예제 #1
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')
예제 #2
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():
            xqci = XQueueCertInterface()
            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]:
                logger.info(
                    "Grading and certification requested for user {} in course {} via /request_certificate call".format(
                        username, course_key
                    )
                )
                status = xqci.add_cert(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")
예제 #3
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():
            xqci = XQueueCertInterface()
            username = request.user.username
            student = User.objects.get(username=username)
            course_id = request.POST.get('course_id')
            course = modulestore().get_instance(
                course_id, CourseDescriptor.id_to_location(course_id), depth=2)

            status = certificate_status_for_student(student,
                                                    course_id)['status']
            if status in [
                    CertificateStatuses.unavailable,
                    CertificateStatuses.notpassing, CertificateStatuses.error
            ]:
                logger.info(
                    'Grading and certification requested for user {} in course {} via /request_certificate call'
                    .format(username, course_id))
                status = xqci.add_cert(student, course_id, course=course)
            return HttpResponse(json.dumps({'add_status': status}),
                                mimetype='application/json')
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}),
                            mimetype='application/json')
예제 #4
0
 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:
         return {"url": certificate_info["download_url"]}
     else:
         return {}
예제 #5
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')
예제 #6
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']
            })
예제 #7
0
파일: tests.py 프로젝트: gopinath81/vmss
    def test_certificate_status_for_student(self):
        student = UserFactory()
        course = CourseFactory.create(org='edx', number='verified', display_name='Verified Course')

        certificate_status = certificate_status_for_student(student, course.id)
        self.assertEqual(certificate_status['status'], CertificateStatuses.unavailable)
        self.assertEqual(certificate_status['mode'], GeneratedCertificate.MODES.honor)
예제 #8
0
def certificate_downloadable_status(student, course_key):
    """
    Check the student existing certificates against a given course.
    if status is not generating and not downloadable or error then user can view the generate button.

    Args:
        student (user object): logged-in user
        course_key (CourseKey): ID associated with the course

    Returns:
        Dict containing student passed status also download url for cert if available
    """
    current_status = certificate_status_for_student(student, course_key)

    # If the certificate status is an error user should view that status is "generating".
    # On the back-end, need to monitor those errors and re-submit the task.

    response_data = {
        'is_downloadable':
        False,
        'is_generating':
        True if current_status['status'] in [
            CertificateStatuses.generating, CertificateStatuses.error
        ] else False,
        'download_url':
        None
    }

    if current_status['status'] == CertificateStatuses.downloadable:
        response_data['is_downloadable'] = True
        response_data['download_url'] = current_status['download_url']

    return response_data
예제 #9
0
파일: api.py 프로젝트: chauhanhardik/populo
def certificate_downloadable_status(student, course_key):
    """
    Check the student existing certificates against a given course.
    if status is not generating and not downloadable or error then user can view the generate button.

    Args:
        student (user object): logged-in user
        course_key (CourseKey): ID associated with the course

    Returns:
        Dict containing student passed status also download url for cert if available
    """
    current_status = certificate_status_for_student(student, course_key)

    # If the certificate status is an error user should view that status is "generating".
    # On the back-end, need to monitor those errors and re-submit the task.

    response_data = {
        'is_downloadable': False,
        'is_generating': True if current_status['status'] in [CertificateStatuses.generating,
                                                              CertificateStatuses.error] else False,
        'download_url': None
    }

    if current_status['status'] == CertificateStatuses.downloadable:
        response_data['is_downloadable'] = True
        response_data['download_url'] = current_status['download_url']

    return response_data
예제 #10
0
 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:
         return {
             "url": certificate_info['download_url'],
         }
     else:
         return {}
    def handle(self, *args, **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]

        if options['course']:
            # try to parse out the course from the serialized form
            try:
                course = CourseKey.from_string(options['course'])
            except InvalidKeyError:
                print("Course id {} could not be parsed as a CourseKey; falling back to SSCK.from_dep_str".format(options['course']))
                course = SlashSeparatedCourseKey.from_deprecated_string(options['course'])
            ended_courses = [course]
        else:
            raise CommandError("You must specify a course")
        
        if options['api_key']:
            api_key = options['api_key']
        else:
            raise CommandError("You must give a api_key, if don't have one visit: https://accredible.com/issuer/sign_up")

        if options['styling']:
            if options['styling'] == 'True': 
                new_status = "generating"
            else:
                raise CommandError("You must give true if want to do no styling, no any other argument")
        else:
            new_status = "downloadable"


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

            print "Fetching enrolled students for {0}".format(course_key.to_deprecated_string())
            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_key)

            xq = CertificateGeneration(api_key=api_key)
            total = enrolled_students.count()
            print "Total number of students: " + str(total) 
            for student in enrolled_students:
                if certificate_status_for_student(
                    student, course_key)['status'] in valid_statuses:
                      ret = xq.add_cert(student, course_key, new_status, course=course)
                      print ret
예제 #12
0
def generate_certificate(_xmodule_instance_args, _entry_id, course_id, _task_input, action_name):
    """
    Generate a certificate for graduated students
    """

    course = modulestore().get_course(course_id, depth=2)
    course_key = get_course_key(str(course_id))
    course_display_name = unicode(course.display_name).encode('utf-8')
    university = University.objects.get(code=course.location.org)
    certificate_base_filename = "attestation_suivi_" + (course_id.to_deprecated_string().replace('/', '_')) + '_'

    start_time = time()
    start_date = datetime.now(UTC)
    status_interval = 1
    enrolled_students = get_enrolled_students(course_id)
    teachers = get_teachers_list_from_course(course_id.to_deprecated_string())
    task_progress = TaskProgress(action_name, enrolled_students.count(), start_time)

    # generate a test certificate
    test_certificate = create_test_certificate(course, course_key, university)

    all_status = {status.notpassing: 0,
                  status.error: 0,
                  status.downloadable: 0,
                  'test_certificate_filename' : test_certificate.filename}

    for count, student in enumerate(enrolled_students):
        task_progress.attempted += 1
        if task_progress.attempted % status_interval == 0:
            task_progress.update_task_state(extra_meta=all_status)
        if certificate_status_for_student(student, course_id)['status'] != status.downloadable:
            if university.certificate_logo:
                logo_path = os.path.join(university.certificate_logo.url, university.certificate_logo.path)
            else:
                logo_path = None
            student_status = generate_fun_certificate(student, course_id,
                                                  course_display_name, course,
                                                  teachers, university.name,
                                                  logo_path, certificate_base_filename,
                                                  False, False, False)
            if student_status:
                all_status[student_status] += 1
                task_progress.succeeded += 1
            else:
                task_progress.failed += 1
        else:
            all_status[status.downloadable] += 1

    return task_progress.update_task_state(extra_meta=all_status)
    def handle(self, *args, **options):
        course_key_string = args[0]
        course_id = CourseKey.from_string(course_key_string)
        student_ids = enrolled_proctoru_students(course_id)

        reports = utils_proctorU_api.get_reports_from_ids(course_id.course, course_id.run, student_ids=student_ids)

        for student in reports:
            user = User.objects.get(username=student)
            course_enrollment = CourseEnrollment.objects.get(course_id=course_id, user=user)
            generated_certificate = certificate_status_for_student(user, course_id)

            print("Previous certificate status: {}".format(generated_certificate.get("status")))
            print("Mode for student {}: {}".format(student, course_enrollment.mode))
            print("reports for: {} -- is OK PU: {}".format(student, utils_proctorU_api.is_proctoru_ok(reports[student])))
            pprint(reports[student])
예제 #14
0
    def handle(self, *args, **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 len(options['teachers']) > 4:
            raise CommandError("Too many teachers. Certificate can not include more than four names.")
        if not options['course']:
            raise CommandError("--course argument is mandatory")
        if options['grade'] and float(options['grade']) > 1:
            raise CommandError('grades range from 0 to 1')

        try:
            ended_courses = [CourseKey.from_string(options['course'])]
        except InvalidKeyError:
            raise CommandError("Course id {} could not be parsed as a CourseKey;".format(options['course']))

        for course_id in ended_courses:
            # prefetch all chapters/sequentials by saying depth=2
            course = modulestore().get_course(course_id, depth=2)
            course_display_name = unicode(course.display_name).encode('utf-8')
            university = University.objects.get(code=course.location.org)
            certificate_base_filename = "attestation_suivi_" + (course_id.to_deprecated_string().replace('/', '_')) + '_'
            print "Fetching enrolled students for {0} ()".format(course_id)
            enrolled_students = get_enrolled_students(course_id, options['user'])
            total = enrolled_students.count()
            print "Course has {0} enrolled students".format(total)
            stats = {
                status.notpassing: 0,
                status.error: 0,
                status.downloadable: 0
            }
            start = datetime.datetime.now(UTC)

            for count, student in enumerate(enrolled_students):
                start = print_progress(count, total, start)
                if options['force'] or (certificate_status_for_student(student, course_id)['status'] != status.downloadable):
                    if university.certificate_logo:
                        logo_path = os.path.join(university.certificate_logo.url, university.certificate_logo.path)
                    else:
                        logo_path = None
                    new_status = generate_fun_certificate(
                        student, course_id, course_display_name, course,
                        options['teachers'], university.name, logo_path,
                        certificate_base_filename, options['ignore_grades'], options['grade'], options['fail'])
                    stats[new_status] += 1
                    pprint(stats)
예제 #15
0
def cert_info(user, course):
    """
    Get the certificate info needed to render the dashboard section for the given
    student and course.  Returns a dictionary with keys:

    'status': one of 'generating', 'ready', 'notpassing', 'processing', 'restricted'
    'show_download_url': bool
    'download_url': url, only present if show_download_url is True
    'show_disabled_download_button': bool -- true if state is 'generating'
    'show_survey_button': bool
    'survey_url': url, only if show_survey_button is True
    'grade': if status is not 'processing'
    """
    if not course.has_ended():
        return {}

    return _cert_info(user, course, certificate_status_for_student(user, course.id))
예제 #16
0
def cert_info(user, course):
    """
    Get the certificate info needed to render the dashboard section for the given
    student and course.  Returns a dictionary with keys:

    'status': one of 'generating', 'ready', 'notpassing', 'processing', 'restricted'
    'show_download_url': bool
    'download_url': url, only present if show_download_url is True
    'show_disabled_download_button': bool -- true if state is 'generating'
    'show_survey_button': bool
    'survey_url': url, only if show_survey_button is True
    'grade': if status is not 'processing'
    """
    if not course.has_ended():
        return {}

    return _cert_info(user, course, certificate_status_for_student(user, course.id))
예제 #17
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,
                "download_url": "/certificates/user/{user_id}/course/{course_id}".format(
                    user_id=self.student.id, course_id=self.course.id  # pylint: disable=no-member
                ),
                "uuid": cert_status["uuid"],
            },
        )
예제 #18
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,
                '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']
            }
        )
예제 #19
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.
    """
    # Memoize user information; return error if it's invalid
    user = None
    username = ''
    try:
        user = request.user
        username = user.username
    except AttributeError:
        return HttpResponse(json.dumps({'add_status': 'error', 'error': 'ERRORBADREQUEST'}), mimetype='application/json')

    # It is an error to hit this endpoint with anything but a POST
    if request.method != "POST":
        return HttpResponse(json.dumps({'add_status': 'error', 'error': 'ERRORNOPOST'}), mimetype='application/json')

    # It is an error to hit this endpoint as an anonymous/nonregistered user
    if not (user.is_authenticated() and UserProfile.has_registered(user)):
        return HttpResponse(json.dumps({'add_status': 'error', 'error': 'ERRORANONYMOUSUSER'}), mimetype='application/json')

    xq = XQueueCertInterface()
    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)
    title = 'None'
    if use_cme:
        titlelist = CmeUserProfile.objects.filter(user=student).values('professional_designation')
        if len(titlelist):
            title = titlelist[0]['professional_designation']

    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 = xq.add_cert(student, course_key, course=course, title=title)
    return HttpResponse(json.dumps({'add_status': status, 'error': ''}), mimetype='application/json')
    def handle(self, *args, **options):
        course_key_string = args[0]
        course_id = CourseKey.from_string(course_key_string)
        student_ids = enrolled_proctoru_students(course_id)

        reports = utils_proctorU_api.get_reports_from_ids(
            course_id.course, course_id.run, student_ids=student_ids)

        for student in reports:
            user = User.objects.get(username=student)
            course_enrollment = CourseEnrollment.objects.get(
                course_id=course_id, user=user)
            generated_certificate = certificate_status_for_student(
                user, course_id)

            print("Previous certificate status: {}".format(
                generated_certificate.get("status")))
            print("Mode for student {}: {}".format(student,
                                                   course_enrollment.mode))
            print("reports for: {} -- is OK PU: {}".format(
                student, utils_proctorU_api.is_proctoru_ok(reports[student])))
            pprint(reports[student])
예제 #21
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():
            # Enter your api key here
            xqci = CertificateGeneration(api_key=settings.APPSEMBLER_FEATURES['ACCREDIBLE_API_KEY'])
            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]:
                logger.info('Grading and certification requested for user {} in course {} via /request_certificate call'.format(username, course_key))
                status = xqci.add_cert(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')
예제 #22
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():
            xqci = XQueueCertInterface()
            username = request.user.username
            student = User.objects.get(username=username)
            course_id = request.POST.get('course_id')
            course = modulestore().get_instance(course_id, CourseDescriptor.id_to_location(course_id), depth=2)

            status = certificate_status_for_student(student, course_id)['status']
            if status in [CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error]:
                logger.info('Grading and certification requested for user {} in course {} via /request_certificate call'.format(username, course_id))
                status = xqci.add_cert(student, course_id, course=course)
            return HttpResponse(json.dumps({'add_status': status}), mimetype='application/json')
        return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}), mimetype='application/json')
예제 #23
0
    def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None,
                 title='None', generate_pdf=True):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.
          generate_pdf - Boolean should a message be sent in queue to generate certificate PDF

        Will change the certificate status to 'generating' or
        `downloadable` in case of web view certificates.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status and newly created certificate instance
        """

        valid_statuses = [
            status.generating,
            status.unavailable,
            status.deleted,
            status.error,
            status.notpassing,
            status.downloadable
        ]

        cert_status = certificate_status_for_student(student, course_id)['status']
        new_status = cert_status
        cert = None

        if cert_status not in valid_statuses:
            LOGGER.warning(
                (
                    u"Cannot create certificate generation task for user %s "
                    u"in the course '%s'; "
                    u"the certificate status '%s' is not one of %s."
                ),
                student.id,
                unicode(course_id),
                cert_status,
                unicode(valid_statuses)
            )
        else:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = modulestore().get_course(course_id, depth=0)
            profile = UserProfile.objects.get(user=student)
            profile_name = profile.name

            # Needed
            self.request.user = student
            self.request.session = {}

            course_name = course.display_name or unicode(course_id)
            is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
            grade = grades.grade(student, self.request, course)
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
            mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
            cert_mode = enrollment_mode

            # For credit mode generate verified certificate
            if cert_mode == CourseMode.CREDIT_MODE:
                cert_mode = CourseMode.VERIFIED

            if mode_is_verified and user_is_verified:
                template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
            elif mode_is_verified and not user_is_verified:
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                # honor code and audit students
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
            if forced_grade:
                grade['grade'] = forced_grade

            cert, __ = GeneratedCertificate.objects.get_or_create(user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade['percent']
            cert.course_id = course_id
            cert.name = profile_name
            cert.download_url = ''
            # Strip HTML from grade range label
            grade_contents = grade.get('grade', None)
            try:
                grade_contents = lxml.html.fromstring(grade_contents).text_content()
            except (TypeError, XMLSyntaxError, ParserError) as exc:
                LOGGER.info(
                    (
                        u"Could not retrieve grade for student %s "
                        u"in the course '%s' "
                        u"because an exception occurred while parsing the "
                        u"grade contents '%s' as HTML. "
                        u"The exception was: '%s'"
                    ),
                    student.id,
                    unicode(course_id),
                    grade_contents,
                    unicode(exc)
                )

                #   Despite blowing up the xml parser, bad values here are fine
                grade_contents = None

            if is_whitelisted or grade_contents is not None:

                if is_whitelisted:
                    LOGGER.info(
                        u"Student %s is whitelisted in '%s'",
                        student.id,
                        unicode(course_id)
                    )

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue

                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()

                    LOGGER.info(
                        (
                            u"Student %s is in the embargoed country restricted "
                            u"list, so their certificate status has been set to '%s' "
                            u"for the course '%s'. "
                            u"No certificate generation task was sent to the XQueue."
                        ),
                        student.id,
                        new_status,
                        unicode(course_id)
                    )
                else:
                    key = make_hashkey(random.random())
                    cert.key = key
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': unicode(course_id),
                        'course_name': course_name,
                        'name': profile_name,
                        'grade': grade_contents,
                        'template_pdf': template_pdf,
                    }
                    if template_file:
                        contents['template_pdf'] = template_file
                    if generate_pdf:
                        new_status = status.generating
                    else:
                        new_status = status.downloadable
                        cert.verify_uuid = uuid4().hex

                    cert.status = new_status
                    cert.save()

                    if generate_pdf:
                        try:
                            self._send_to_xqueue(contents, key)
                        except XQueueAddToQueueError as exc:
                            new_status = ExampleCertificate.STATUS_ERROR
                            cert.status = new_status
                            cert.error_reason = unicode(exc)
                            cert.save()
                            LOGGER.critical(
                                (
                                    u"Could not add certificate task to XQueue.  "
                                    u"The course was '%s' and the student was '%s'."
                                    u"The certificate task status has been marked as 'error' "
                                    u"and can be re-submitted with a management command."
                                ), course_id, student.id
                            )
                        else:
                            LOGGER.info(
                                (
                                    u"The certificate status has been set to '%s'.  "
                                    u"Sent a certificate grading task to the XQueue "
                                    u"with the key '%s'. "
                                ),
                                new_status,
                                key
                            )
            else:
                new_status = status.notpassing
                cert.status = new_status
                cert.save()

                LOGGER.info(
                    (
                        u"Student %s does not have a grade for '%s', "
                        u"so their certificate status has been set to '%s'. "
                        u"No certificate generation task was sent to the XQueue."
                    ),
                    student.id,
                    unicode(course_id),
                    new_status
                )

        return new_status, cert
    def handle(self, *args, **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:
                print(
                    "Course id {} could not be parsed as a CourseKey; falling back to SSCK.from_dep_str"
                    .format(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)

            print "Fetching enrolled students for {0}".format(
                course_key.to_deprecated_string())
            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_key)

            xq = XQueueCertInterface()
            if options['insecure']:
                xq.use_https = False
            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)

                if certificate_status_for_student(
                        student, course_key)['status'] in valid_statuses:
                    if not options['noop']:
                        # Add the certificate request to the queue
                        ret = xq.add_cert(student, course_key, course=course)
                        if ret == 'generating':
                            print '{0} - {1}'.format(student, ret)
예제 #25
0
    def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None, title='None'):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.

        Will change the certificate status to 'generating'.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status
        """

        valid_statuses = [
            status.generating,
            status.unavailable,
            status.deleted,
            status.error,
            status.notpassing
        ]

        cert_status = certificate_status_for_student(student, course_id)['status']
        new_status = cert_status

        if cert_status not in valid_statuses:
            LOGGER.warning(
                (
                    u"Cannot create certificate generation task for user %s "
                    u"in the course '%s'; "
                    u"the certificate status '%s' is not one of %s."
                ),
                student.id,
                unicode(course_id),
                cert_status,
                unicode(valid_statuses)
            )
        else:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = courses.get_course_by_id(course_id)
            profile = UserProfile.objects.get(user=student)
            profile_name = profile.name

            # Needed
            self.request.user = student
            self.request.session = {}

            course_name = course.display_name or course_id.to_deprecated_string()
            is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
            grade = grades.grade(student, self.request, course)
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
            mode_is_verified = (enrollment_mode == GeneratedCertificate.MODES.verified)
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
            user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student)
            cert_mode = enrollment_mode
            if (mode_is_verified and user_is_verified and user_is_reverified):
                template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
            elif (mode_is_verified and not (user_is_verified and user_is_reverified)):
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                # honor code and audit students
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
            if forced_grade:
                grade['grade'] = forced_grade

            cert, __ = GeneratedCertificate.objects.get_or_create(user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade['percent']
            cert.course_id = course_id
            cert.name = profile_name
            # Strip HTML from grade range label
            grade_contents = grade.get('grade', None)
            try:
                grade_contents = lxml.html.fromstring(grade_contents).text_content()
            except (TypeError, XMLSyntaxError, ParserError) as exc:
                LOGGER.info(
                    (
                        u"Could not retrieve grade for student %s "
                        u"in the course '%s' "
                        u"because an exception occurred while parsing the "
                        u"grade contents '%s' as HTML. "
                        u"The exception was: '%s'"
                    ),
                    student.id,
                    unicode(course_id),
                    grade_contents,
                    unicode(exc)
                )

                #   Despite blowing up the xml parser, bad values here are fine
                grade_contents = None

            if is_whitelisted or grade_contents is not None:

                if is_whitelisted:
                    LOGGER.info(
                        u"Student %s is whitelisted in '%s'",
                        student.id,
                        unicode(course_id)
                    )

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue

                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()

                    LOGGER.info(
                        (
                            u"Student %s is in the embargoed country restricted "
                            u"list, so their certificate status has been set to '%s' "
                            u"for the course '%s'. "
                            u"No certificate generation task was sent to the XQueue."
                        ),
                        student.id,
                        new_status,
                        unicode(course_id)
                    )
                else:
                    key = make_hashkey(random.random())
                    cert.key = key
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': course_id.to_deprecated_string(),
                        'course_name': course_name,
                        'name': profile_name,
                        'grade': grade_contents,
                        'template_pdf': template_pdf,
                    }
                    if template_file:
                        contents['template_pdf'] = template_file
                    new_status = status.generating
                    cert.status = new_status
                    cert.save()
                    self._send_to_xqueue(contents, key)

                    LOGGER.info(
                        (
                            u"The certificate status has been set to '%s'.  "
                            u"Sent a certificate grading task to the XQueue "
                            u"with the key '%s'. "
                        ),
                        key,
                        new_status
                    )
            else:
                cert_status = status.notpassing
                cert.status = cert_status
                cert.save()

                LOGGER.info(
                    (
                        u"Student %s does not have a grade for '%s', "
                        u"so their certificate status has been set to '%s'. "
                        u"No certificate generation task was sent to the XQueue."
                    ),
                    student.id,
                    unicode(course_id),
                    cert_status
                )

        return new_status
예제 #26
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)
            )
예제 #27
0
    def handle(self, *args, **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 len(options['teachers']) > 4:
            print "Too many teachers. Certificate can not include more than four names."
            return

        # Print update after this many students

        STATUS_INTERVAL = 100

        if options['course']:
            try:
                ended_courses = [CourseKey.from_string(options['course'])]
            except InvalidKeyError:
                print("Course id {} could not be parsed as a CourseKey;".format(options['course']))
                return

        if options['grade'] and float(options['grade']) > 1:
            raise CommandError('grades range from 0 to 1')

        for course_id in ended_courses:
            # prefetch all chapters/sequentials by saying depth=2
            course = modulestore().get_course(course_id, depth=2)
            course_display_name = unicode(course.display_name).encode('utf-8')
            university = University.objects.get(code=course.location.org)
            certificate_base_filename = "attestation_suivi_" + (course_id.to_deprecated_string().replace('/','_')) + '_';
            print "Fetching enrolled students for {0} ()".format(course_id, course_display_name)
            if options['user'] is None:
                enrolled_students = User.objects.filter(
                    courseenrollment__course_id=course_id, profile__isnull=False).prefetch_related(
                    "groups").order_by('username')
            else:
                user = options['user']
                if '@' in user:
                    enrolled_students = User.objects.filter(email=user, courseenrollment__course_id=course_id, profile__isnull=False)
                else:
                    enrolled_students = User.objects.filter(username=user, courseenrollment__course_id=course_id, profile__isnull=False)
            total = enrolled_students.count()
            print "Course has {0} enrolled students".format(total)
            count = 0
            stats = {
                status.notpassing : 0,
                status.error : 0,
                status.downloadable : 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)
                if options['force'] or (certificate_status_for_student(student, course_id)['status'] != status.downloadable):
                    if university.certificate_logo:
                        logo_path = os.path.join(university.certificate_logo.url, university.certificate_logo.path)
                    else:
                        logo_path = None
                    new_status = generate_fun_certificate(student, course_id, course_display_name,
                                                              course, options['teachers'], university.name,
                                                              logo_path, certificate_base_filename, options['ignore_grades'],
                                                              options['grade'])
                    stats[new_status] += 1
                    pprint(stats)
예제 #28
0
    def add_cert(self, student, course_id, defined_status="downloadable", course=None, forced_grade=None, template_file=None, title='None'):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.

        Will change the certificate status to 'generating' or 'downloadable'.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status
        """

        VALID_STATUSES = [status.generating,
                          status.unavailable,
                          status.deleted,
                          status.error,
                          status.notpassing]

        cert_status = certificate_status_for_student(student, course_id)['status']

        new_status = cert_status

        if cert_status in VALID_STATUSES:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = courses.get_course_by_id(course_id)
            profile = UserProfile.objects.get(user=student)
            profile_name = profile.name

            # Needed
            self.request.user = student
            self.request.session = {}

            course_name = course.display_name or course_id.to_deprecated_string()
            description = ''
            for section_key in ['short_description', 'description','overview']:
                loc = loc = course.location.replace(category='about', name=section_key)
                try:
                    if modulestore().get_item(loc).data:
                       description = modulestore().get_item(loc).data
                       break
                except:
                    print "this course don't have " +section_key
              
            if not description:
               description = "course_description"


            is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
            grade = grades.grade(student, self.request, course)
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
            mode_is_verified = (enrollment_mode == GeneratedCertificate.MODES.verified)
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
            user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student)
            cert_mode = enrollment_mode
            if (mode_is_verified and not (user_is_verified and user_is_reverified)):
                cert_mode = GeneratedCertificate.MODES.honor
            
            if forced_grade:
                grade['grade'] = forced_grade

            cert, __ = GeneratedCertificate.objects.get_or_create(user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade['percent']
            cert.course_id = course_id
            cert.name = profile_name
            # Strip HTML from grade range label
            grade_contents = grade.get('grade', None)
            try:
                grade_contents = lxml.html.fromstring(grade_contents).text_content()
            except (TypeError, XMLSyntaxError, ParserError) as e:
                #   Despite blowing up the xml parser, bad values here are fine
                grade_contents = None

            if is_whitelisted or grade_contents is not None:

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue
                print grade_contents
                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()
                else:
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': course_id.to_deprecated_string(),
                        'course_name': course_name,
                        'name': profile_name,
                        'grade': grade_contents
                    }
                    if cert_mode == "verified":
                         seal_image = "https://s3.amazonaws.com/accredible_api_style_preferences/signature_images/37/original/open-uri20141023-10175-q5szt4"
                    elif cert_mode == "honor":
                         seal_image = "https://s3.amazonaws.com/accredible_api_organizations/images/8/medium/data?1414086141"
                    else:
                         seal_image = None
                    
                    if defined_status == "generating":
                      approve = False
                    else:
                      approve = True

                    grade_into_string =  ''.join('{}{}'.format(key, val) for key, val in grade.items())
                    payload = {"credential": { "name": course_name, "description": description, "achievement_id": contents['course_id'] , "course_link": "/courses/" +contents['course_id'] + "/about", "approve": approve, "grade": grade_contents, "recipient": {"name": contents['name'], "email": student.email}, "style_preference": {"distinction_url": seal_image},"evidence_items": [{"description": "Course Transcript", "category": "transcript", "string_object": json.dumps(grade["section_breakdown"])}, {"description": "Final Grade", "category": "grade", "string_object": grade['percent']}]}}
                    payload = json.dumps(payload)
                    r = requests.post('https://api.accredible.com/v1/credentials', payload, headers={'Authorization':'Token token=' + self.api_key, 'Content-Type':'application/json'})
                    
                    if r.status_code == 200:
                       json_response = r.json()  
                       cert.status = defined_status
                       cert.key = json_response["credential"]["id"]
                       if 'private' in json_response:
                          cert.download_url = "https://wwww.accredible.com/" + str(json_response["credential"]["id"]) + "?key" + str(json_response["private_key"])
                       else:
                          cert.download_url = "https://www.accredible.com/" + str(cert.key)
                       cert.save()
                    else:
                        new_status = "errors"
                    

            else:
                cert_status = status.notpassing
                cert.status = cert_status
                cert.save()

        return new_status
예제 #29
0
파일: queue.py 프로젝트: eliesmr4/myedx
    def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None, generate_pdf=True):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.
          generate_pdf - Boolean should a message be sent in queue to generate certificate PDF

        Will change the certificate status to 'generating' or
        `downloadable` in case of web view certificates.

        The course must not be a CCX.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the newly created certificate instance
        """

        if hasattr(course_id, 'ccx'):
            LOGGER.warning(
                (
                    u"Cannot create certificate generation task for user %s "
                    u"in the course '%s'; "
                    u"certificates are not allowed for CCX courses."
                ),
                student.id,
                unicode(course_id)
            )
            return None

        valid_statuses = [
            status.generating,
            status.unavailable,
            status.deleted,
            status.error,
            status.notpassing,
            status.downloadable,
            status.auditing,
            status.audit_passing,
            status.audit_notpassing,
        ]

        cert_status = certificate_status_for_student(student, course_id)['status']
        cert = None

        if cert_status not in valid_statuses:
            LOGGER.warning(
                (
                    u"Cannot create certificate generation task for user %s "
                    u"in the course '%s'; "
                    u"the certificate status '%s' is not one of %s."
                ),
                student.id,
                unicode(course_id),
                cert_status,
                unicode(valid_statuses)
            )
            return None

        # The caller can optionally pass a course in to avoid
        # re-fetching it from Mongo. If they have not provided one,
        # get it from the modulestore.
        if course is None:
            course = modulestore().get_course(course_id, depth=0)

        profile = UserProfile.objects.get(user=student)
        profile_name = profile.name

        # Needed for access control in grading.
        self.request.user = student
        self.request.session = {}

        is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
        course_grade = CourseGradeFactory().create(student, course)
        enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
        mode_is_verified = enrollment_mode in GeneratedCertificate.VERIFIED_CERTS_MODES
        user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
        cert_mode = enrollment_mode
        is_eligible_for_certificate = is_whitelisted or CourseMode.is_eligible_for_certificate(enrollment_mode)
        unverified = False
        # For credit mode generate verified certificate
        if cert_mode == CourseMode.CREDIT_MODE:
            cert_mode = CourseMode.VERIFIED

        if template_file is not None:
            template_pdf = template_file
        elif mode_is_verified and user_is_verified:
            template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
        elif mode_is_verified and not user_is_verified:
            template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
            if CourseMode.mode_for_course(course_id, CourseMode.HONOR):
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                unverified = True
        else:
            # honor code and audit students
            template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)

        LOGGER.info(
            (
                u"Certificate generated for student %s in the course: %s with template: %s. "
                u"given template: %s, "
                u"user is verified: %s, "
                u"mode is verified: %s"
            ),
            student.username,
            unicode(course_id),
            template_pdf,
            template_file,
            user_is_verified,
            mode_is_verified
        )

        cert, created = GeneratedCertificate.objects.get_or_create(user=student, course_id=course_id)  # pylint: disable=no-member

        cert.mode = cert_mode
        cert.user = student
        cert.grade = course_grade.percent
        cert.course_id = course_id
        cert.name = profile_name
        cert.download_url = ''

        # Strip HTML from grade range label
        grade_contents = forced_grade or course_grade.letter_grade
        try:
            grade_contents = lxml.html.fromstring(grade_contents).text_content()
            passing = True
        except (TypeError, XMLSyntaxError, ParserError) as exc:
            LOGGER.info(
                (
                    u"Could not retrieve grade for student %s "
                    u"in the course '%s' "
                    u"because an exception occurred while parsing the "
                    u"grade contents '%s' as HTML. "
                    u"The exception was: '%s'"
                ),
                student.id,
                unicode(course_id),
                grade_contents,
                unicode(exc)
            )

            # Log if the student is whitelisted
            if is_whitelisted:
                LOGGER.info(
                    u"Student %s is whitelisted in '%s'",
                    student.id,
                    unicode(course_id)
                )
                passing = True
            else:
                passing = False

        # If this user's enrollment is not eligible to receive a
        # certificate, mark it as such for reporting and
        # analytics. Only do this if the certificate is new, or
        # already marked as ineligible -- we don't want to mark
        # existing audit certs as ineligible.
        cutoff = settings.AUDIT_CERT_CUTOFF_DATE
        if (cutoff and cert.created_date >= cutoff) and not is_eligible_for_certificate:
            cert.status = CertificateStatuses.audit_passing if passing else CertificateStatuses.audit_notpassing
            cert.save()
            LOGGER.info(
                u"Student %s with enrollment mode %s is not eligible for a certificate.",
                student.id,
                enrollment_mode
            )
            return cert
        # If they are not passing, short-circuit and don't generate cert
        elif not passing:
            cert.status = status.notpassing
            cert.save()

            LOGGER.info(
                (
                    u"Student %s does not have a grade for '%s', "
                    u"so their certificate status has been set to '%s'. "
                    u"No certificate generation task was sent to the XQueue."
                ),
                student.id,
                unicode(course_id),
                cert.status
            )
            return cert

        # Check to see whether the student is on the the embargoed
        # country restricted list. If so, they should not receive a
        # certificate -- set their status to restricted and log it.
        if self.restricted.filter(user=student).exists():
            cert.status = status.restricted
            cert.save()

            LOGGER.info(
                (
                    u"Student %s is in the embargoed country restricted "
                    u"list, so their certificate status has been set to '%s' "
                    u"for the course '%s'. "
                    u"No certificate generation task was sent to the XQueue."
                ),
                student.id,
                cert.status,
                unicode(course_id)
            )
            return cert

        if unverified:
            cert.status = status.unverified
            cert.save()
            LOGGER.info(
                (
                    u"User %s has a verified enrollment in course %s "
                    u"but is missing ID verification. "
                    u"Certificate status has been set to unverified"
                ),
                student.id,
                unicode(course_id),
            )
            return cert

        # Finally, generate the certificate and send it off.
        return self._generate_cert(cert, course, student, grade_contents, template_pdf, generate_pdf)
예제 #30
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
            )

            xq = XQueueCertInterface()
            if options['insecure']:
                xq.use_https = False
            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 = xq.add_cert(student, course_key, course=course)

                        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)
            )
예제 #31
0
    def add_cert(self, student, course_id, course=None):
        """

        Arguments:
          student - User.object
          course_id - courseenrollment.course_id (string)

        Request a new certificate for a student.
        Will change the certificate status to 'generating'.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status

        """

        VALID_STATUSES = [status.generating,
                          status.unavailable,
                          status.deleted,
                          status.error,
                          status.notpassing]

        cert_status = certificate_status_for_student(student, course_id)['status']

        new_status = cert_status

        if cert_status in VALID_STATUSES:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = courses.get_course_by_id(course_id)
            profile = UserProfile.objects.get(user=student)

            # Needed
            self.request.user = student
            self.request.session = {}

            grade = grades.grade(student, self.request, course)
            is_whitelisted = self.whitelist.filter(
                user=student, course_id=course_id, whitelist=True).exists()
            enrollment_mode = CourseEnrollment.enrollment_mode_for_user(student, course_id)
            mode_is_verified = (enrollment_mode == GeneratedCertificate.MODES.verified)
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
            user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student)
            org = course_id.split('/')[0]
            course_num = course_id.split('/')[1]
            cert_mode = enrollment_mode
            if (mode_is_verified and user_is_verified and user_is_reverified):
                template_pdf = "certificate-template-{0}-{1}-verified.pdf".format(
                    org, course_num)
            elif (mode_is_verified and not (user_is_verified and user_is_reverified)):
                template_pdf = "certificate-template-{0}-{1}.pdf".format(
                    org, course_num)
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                # honor code and audit students
                template_pdf = "certificate-template-{0}-{1}.pdf".format(
                    org, course_num)

            cert, created = GeneratedCertificate.objects.get_or_create(
                user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade['percent']
            cert.course_id = course_id
            cert.name = profile.name

            if is_whitelisted or grade['grade'] is not None:

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue

                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()
                else:
                    key = make_hashkey(random.random())
                    cert.key = key
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': course_id,
                        'name': profile.name,
                        'grade': grade['grade'],
                        'template_pdf': template_pdf,
                    }
                    new_status = status.generating
                    cert.status = new_status
                    cert.save()
                    self._send_to_xqueue(contents, key)
            else:
                new_status = status.notpassing
                cert.status = new_status
                cert.save()

        return new_status
예제 #32
0
    def handle(self, *args, **options):
        LOGGER.info(
            (
                u"Starting to create tasks for ungenerated certificates "
                u"with arguments %s and options %s"
            ),
            text_type(args),
            text_type(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

        course = CourseKey.from_string(options['course'])
        ended_courses = [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,
                    text_type(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,
                                text_type(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,
                            text_type(course_key)
                        )

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

            LOGGER.info(
                (
                    u"Completed ungenerated certificates command "
                    u"for course '%s'"
                ),
                text_type(course_key)
            )
예제 #33
0
    def handle(self, *args, **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]

        if options['course']:
            # try to parse out the course from the serialized form
            try:
                course = CourseKey.from_string(options['course'])
            except InvalidKeyError:
                print(
                    "Course id {} could not be parsed as a CourseKey; falling back to SSCK.from_dep_str"
                    .format(options['course']))
                course = SlashSeparatedCourseKey.from_deprecated_string(
                    options['course'])
            ended_courses = [course]
        else:
            raise CommandError("You must specify a course")

        if options['api_key']:
            api_key = options['api_key']
        else:
            raise CommandError(
                "You must give a api_key, if don't have one visit: https://accredible.com/issuer/sign_up"
            )

        if options['styling']:
            if options['styling'] == 'True':
                new_status = "generating"
            else:
                raise CommandError(
                    "You must give true if want to do no styling, no any other argument"
                )
        else:
            new_status = "downloadable"

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

            print "Fetching enrolled students for {0}".format(
                course_key.to_deprecated_string())
            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_key)

            xq = CertificateGeneration(api_key=api_key)
            total = enrolled_students.count()
            print "Total number of students: " + str(total)
            for student in enrolled_students:
                if certificate_status_for_student(
                        student, course_key)['status'] in valid_statuses:
                    ret = xq.add_cert(student,
                                      course_key,
                                      new_status,
                                      course=course)
                    print ret
예제 #34
0
파일: queue.py 프로젝트: jswope00/griffinx
    def add_cert(self,
                 student,
                 course_id,
                 course=None,
                 forced_grade=None,
                 template_file=None,
                 title='None'):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.

        Will change the certificate status to 'generating'.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status
        """

        VALID_STATUSES = [
            status.generating, status.unavailable, status.deleted,
            status.error, status.notpassing
        ]

        cert_status = certificate_status_for_student(student,
                                                     course_id)['status']

        new_status = cert_status

        if cert_status in VALID_STATUSES:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = courses.get_course_by_id(course_id)
            profile = UserProfile.objects.get(user=student)
            profile_name = profile.name

            # Needed
            self.request.user = student
            self.request.session = {}

            course_name = course.display_name or course_id.to_deprecated_string(
            )
            is_whitelisted = self.whitelist.filter(user=student,
                                                   course_id=course_id,
                                                   whitelist=True).exists()
            grade = grades.grade(student, self.request, course)
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
                student, course_id)
            mode_is_verified = (
                enrollment_mode == GeneratedCertificate.MODES.verified)
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(
                student)
            user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(
                course_id, student)
            cert_mode = enrollment_mode
            if (mode_is_verified and user_is_verified and user_is_reverified):
                template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(
                    id=course_id)
            elif (mode_is_verified
                  and not (user_is_verified and user_is_reverified)):
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(
                    id=course_id)
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                # honor code and audit students
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(
                    id=course_id)
            if forced_grade:
                grade['grade'] = forced_grade

            cert, __ = GeneratedCertificate.objects.get_or_create(
                user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade['percent']
            cert.course_id = course_id
            cert.name = profile_name
            # Strip HTML from grade range label
            grade_contents = grade.get('grade', None)
            try:
                grade_contents = lxml.html.fromstring(
                    grade_contents).text_content()
            except (TypeError, XMLSyntaxError, ParserError) as e:
                #   Despite blowing up the xml parser, bad values here are fine
                grade_contents = None

            if is_whitelisted or grade_contents is not None:

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue

                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()
                else:
                    key = make_hashkey(random.random())
                    cert.key = key
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': course_id.to_deprecated_string(),
                        'course_name': course_name,
                        'name': profile_name,
                        'grade': grade_contents,
                        'template_pdf': template_pdf,
                    }
                    if template_file:
                        contents['template_pdf'] = template_file
                    new_status = status.generating
                    cert.status = new_status
                    cert.save()
                    self._send_to_xqueue(contents, key)
            else:
                cert_status = status.notpassing
                cert.status = cert_status
                cert.save()

        return new_status
예제 #35
0
    def add_cert(self, student, course_id, course=None):
        """

        Arguments:
          student - User.object
          course_id - courseenrollment.course_id (string)

        Request a new certificate for a student.
        Will change the certificate status to 'generating'.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'


        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status

        """

        VALID_STATUSES = [status.generating,
                          status.unavailable, status.deleted, status.error,
                          status.notpassing]

        cert_status = certificate_status_for_student(
            student, course_id)['status']

        if cert_status in VALID_STATUSES:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = courses.get_course_by_id(course_id)
            profile = UserProfile.objects.get(user=student)

            cert, created = GeneratedCertificate.objects.get_or_create(
                user=student, course_id=course_id)

            grade = grades.grade(student, self.request, course)
            is_whitelisted = self.whitelist.filter(
                user=student, course_id=course_id, whitelist=True).exists()

            if is_whitelisted or grade['grade'] is not None:

                key = make_hashkey(random.random())

                cert.grade = grade['percent']
                cert.user = student
                cert.course_id = course_id
                cert.key = key
                cert.name = profile.name

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue
                if self.restricted.filter(user=student).exists():
                    cert.status = status.restricted
                else:
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': course_id,
                        'name': profile.name,
                    }
                    cert.status = status.generating
                    self._send_to_xqueue(contents, key)
                cert.save()
            else:
                cert_status = status.notpassing
                cert.grade = grade['percent']
                cert.status = cert_status
                cert.user = student
                cert.course_id = course_id
                cert.name = profile.name
                cert.save()

        return cert_status
예제 #36
0
    def add_cert(self, student, course_id, course=None, forced_grade=None, template_file=None, title="None"):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.

        Will change the certificate status to 'generating'.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status
        """

        VALID_STATUSES = [status.generating, status.unavailable, status.deleted, status.error, status.notpassing]

        cert_status = certificate_status_for_student(student, course_id)["status"]

        new_status = cert_status

        if cert_status in VALID_STATUSES:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = courses.get_course_by_id(course_id)
            profile = UserProfile.objects.get(user=student)
            profile_name = profile.name

            # Needed
            self.request.user = student
            self.request.session = {}

            course_name = course.display_name or course_id.to_deprecated_string()
            is_whitelisted = self.whitelist.filter(user=student, course_id=course_id, whitelist=True).exists()
            grade = grades.grade(student, self.request, course)
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(student, course_id)
            mode_is_verified = enrollment_mode == GeneratedCertificate.MODES.verified
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student)
            user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student)
            cert_mode = enrollment_mode
            if mode_is_verified and user_is_verified and user_is_reverified:
                template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(id=course_id)
            elif mode_is_verified and not (user_is_verified and user_is_reverified):
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                # honor code and audit students
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(id=course_id)
            if forced_grade:
                grade["grade"] = forced_grade

            cert, __ = GeneratedCertificate.objects.get_or_create(user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade["percent"]
            cert.course_id = course_id
            cert.name = profile_name
            # Strip HTML from grade range label
            grade_contents = grade.get("grade", None)
            try:
                grade_contents = lxml.html.fromstring(grade_contents).text_content()
            except (TypeError, XMLSyntaxError, ParserError) as e:
                #   Despite blowing up the xml parser, bad values here are fine
                grade_contents = None

            if is_whitelisted or grade_contents is not None:

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue

                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()
                else:
                    key = make_hashkey(random.random())
                    cert.key = key
                    contents = {
                        "action": "create",
                        "username": student.username,
                        "course_id": course_id.to_deprecated_string(),
                        "course_name": course_name,
                        "name": profile_name,
                        "grade": grade_contents,
                        "template_pdf": template_pdf,
                    }
                    if template_file:
                        contents["template_pdf"] = template_file
                    new_status = status.generating
                    cert.status = new_status
                    cert.save()
                    self._send_to_xqueue(contents, key)
            else:
                cert_status = status.notpassing
                cert.status = cert_status
                cert.save()

        return new_status
예제 #37
0
    def handle(self, *args, **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']:
            ended_courses = [options['course']]
        else:
            # Find all courses that have ended
            ended_courses = []
            for course_id in [course  # all courses in COURSE_LISTINGS
                              for sub in settings.COURSE_LISTINGS
                              for course in settings.COURSE_LISTINGS[sub]]:
                course_loc = CourseDescriptor.id_to_location(course_id)
                course = modulestore().get_instance(course_id, course_loc)
                if course.has_ended():
                    ended_courses.append(course_id)

        for course_id in ended_courses:
            # prefetch all chapters/sequentials by saying depth=2
            course = modulestore().get_instance(
                course_id, CourseDescriptor.id_to_location(course_id), depth=2)

            print "Fetching enrolled students for {0}".format(course_id)
            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_id).prefetch_related(
                    "groups").order_by('username')
            xq = XQueueCertInterface()
            total = enrolled_students.count()
            count = 0
            start = datetime.datetime.now()
            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() - 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()

                if certificate_status_for_student(
                        student, course_id)['status'] in valid_statuses:
                    if not options['noop']:
                        # Add the certificate request to the queue
                        ret = xq.add_cert(student, course_id, course=course)
                        if ret == 'generating':
                            print '{0} - {1}'.format(student, ret)
예제 #38
0
    def add_cert(self,
                 student,
                 course_id,
                 course=None,
                 forced_grade=None,
                 template_file=None,
                 title='None',
                 generate_pdf=True):
        """
        Request a new certificate for a student.

        Arguments:
          student   - User.object
          course_id - courseenrollment.course_id (CourseKey)
          forced_grade - a string indicating a grade parameter to pass with
                         the certificate request. If this is given, grading
                         will be skipped.
          generate_pdf - Boolean should a message be sent in queue to generate certificate PDF

        Will change the certificate status to 'generating' or
        `downloadable` in case of web view certificates.

        Certificate must be in the 'unavailable', 'error',
        'deleted' or 'generating' state.

        If a student has a passing grade or is in the whitelist
        table for the course a request will be made for a new cert.

        If a student has allow_certificate set to False in the
        userprofile table the status will change to 'restricted'

        If a student does not have a passing grade the status
        will change to status.notpassing

        Returns the student's status and newly created certificate instance
        """

        valid_statuses = [
            status.generating, status.unavailable, status.deleted,
            status.error, status.notpassing, status.downloadable
        ]

        cert_status = certificate_status_for_student(student,
                                                     course_id)['status']
        new_status = cert_status
        cert = None

        if cert_status not in valid_statuses:
            LOGGER.warning(
                (u"Cannot create certificate generation task for user %s "
                 u"in the course '%s'; "
                 u"the certificate status '%s' is not one of %s."), student.id,
                unicode(course_id), cert_status, unicode(valid_statuses))
        else:
            # grade the student

            # re-use the course passed in optionally so we don't have to re-fetch everything
            # for every student
            if course is None:
                course = modulestore().get_course(course_id, depth=0)
            profile = UserProfile.objects.get(user=student)
            profile_name = profile.name

            # Needed
            self.request.user = student
            self.request.session = {}

            course_name = course.display_name or unicode(course_id)
            is_whitelisted = self.whitelist.filter(user=student,
                                                   course_id=course_id,
                                                   whitelist=True).exists()
            grade = grades.grade(student, self.request, course)
            enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(
                student, course_id)
            mode_is_verified = (
                enrollment_mode == GeneratedCertificate.MODES.verified)
            user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(
                student)
            cert_mode = enrollment_mode
            if mode_is_verified and user_is_verified:
                template_pdf = "certificate-template-{id.org}-{id.course}-verified.pdf".format(
                    id=course_id)
            elif mode_is_verified and not user_is_verified:
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(
                    id=course_id)
                cert_mode = GeneratedCertificate.MODES.honor
            else:
                # honor code and audit students
                template_pdf = "certificate-template-{id.org}-{id.course}.pdf".format(
                    id=course_id)
            if forced_grade:
                grade['grade'] = forced_grade

            cert, __ = GeneratedCertificate.objects.get_or_create(
                user=student, course_id=course_id)

            cert.mode = cert_mode
            cert.user = student
            cert.grade = grade['percent']
            cert.course_id = course_id
            cert.name = profile_name
            cert.download_url = ''
            # Strip HTML from grade range label
            grade_contents = grade.get('grade', None)
            try:
                grade_contents = lxml.html.fromstring(
                    grade_contents).text_content()
            except (TypeError, XMLSyntaxError, ParserError) as exc:
                LOGGER.info(
                    (u"Could not retrieve grade for student %s "
                     u"in the course '%s' "
                     u"because an exception occurred while parsing the "
                     u"grade contents '%s' as HTML. "
                     u"The exception was: '%s'"), student.id,
                    unicode(course_id), grade_contents, unicode(exc))

                #   Despite blowing up the xml parser, bad values here are fine
                grade_contents = None

            if is_whitelisted or grade_contents is not None:

                if is_whitelisted:
                    LOGGER.info(u"Student %s is whitelisted in '%s'",
                                student.id, unicode(course_id))

                # check to see whether the student is on the
                # the embargoed country restricted list
                # otherwise, put a new certificate request
                # on the queue

                if self.restricted.filter(user=student).exists():
                    new_status = status.restricted
                    cert.status = new_status
                    cert.save()

                    LOGGER.info((
                        u"Student %s is in the embargoed country restricted "
                        u"list, so their certificate status has been set to '%s' "
                        u"for the course '%s'. "
                        u"No certificate generation task was sent to the XQueue."
                    ), student.id, new_status, unicode(course_id))
                else:
                    key = make_hashkey(random.random())
                    cert.key = key
                    contents = {
                        'action': 'create',
                        'username': student.username,
                        'course_id': unicode(course_id),
                        'course_name': course_name,
                        'name': profile_name,
                        'grade': grade_contents,
                        'template_pdf': template_pdf,
                    }
                    if template_file:
                        contents['template_pdf'] = template_file
                    if generate_pdf:
                        new_status = status.generating
                    else:
                        new_status = status.downloadable
                        cert.verify_uuid = uuid4().hex

                    cert.status = new_status
                    cert.save()

                    if generate_pdf:
                        try:
                            self._send_to_xqueue(contents, key)
                        except XQueueAddToQueueError as exc:
                            new_status = ExampleCertificate.STATUS_ERROR
                            cert.status = new_status
                            cert.error_reason = unicode(exc)
                            cert.save()
                            LOGGER.critical((
                                u"Could not add certificate task to XQueue.  "
                                u"The course was '%s' and the student was '%s'."
                                u"The certificate task status has been marked as 'error' "
                                u"and can be re-submitted with a management command."
                            ), course_id, student.id)
                        else:
                            LOGGER.info((
                                u"The certificate status has been set to '%s'.  "
                                u"Sent a certificate grading task to the XQueue "
                                u"with the key '%s'. "), new_status, key)
            else:
                new_status = status.notpassing
                cert.status = new_status
                cert.save()

                LOGGER.info((
                    u"Student %s does not have a grade for '%s', "
                    u"so their certificate status has been set to '%s'. "
                    u"No certificate generation task was sent to the XQueue."),
                            student.id, unicode(course_id), new_status)

        return new_status, cert
예제 #39
0
    def handle(self, *args, **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']:
            ended_courses = [options['course']]
        else:
            # Find all courses that have ended
            ended_courses = []
            for course_id in [
                    course  # all courses in COURSE_LISTINGS
                    for sub in settings.COURSE_LISTINGS
                    for course in settings.COURSE_LISTINGS[sub]
            ]:
                course_loc = CourseDescriptor.id_to_location(course_id)
                course = modulestore().get_instance(course_id, course_loc)
                if course.has_ended():
                    ended_courses.append(course_id)

        for course_id in ended_courses:
            # prefetch all chapters/sequentials by saying depth=2
            course = modulestore().get_instance(
                course_id, CourseDescriptor.id_to_location(course_id), depth=2)

            print "Fetching enrolled students for {0}".format(course_id)
            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_id)

            xq = XQueueCertInterface()
            if options['insecure']:
                xq.use_https = False
            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)

                if certificate_status_for_student(
                        student, course_id)['status'] in valid_statuses:
                    if not options['noop']:
                        # Add the certificate request to the queue
                        ret = xq.add_cert(student, course_id, course=course)
                        if ret == 'generating':
                            print '{0} - {1}'.format(student, ret)
예제 #40
0
    def handle(self, *args, **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:
                print("Course id {} could not be parsed as a CourseKey; falling back to SSCK.from_dep_str".format(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)

            print "Fetching enrolled students for {0}".format(course_key.to_deprecated_string())
            enrolled_students = User.objects.filter(
                courseenrollment__course_id=course_key)

            xq = XQueueCertInterface()
            if options['insecure']:
                xq.use_https = False
            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)

                if certificate_status_for_student(
                        student, course_key)['status'] in valid_statuses:
                    if not options['noop']:
                        # Add the certificate request to the queue
                        ret = xq.add_cert(student, course_key, course=course)
                        if ret == 'generating':
                            print '{0} - {1}'.format(student, ret)