def handle(self, *args, **options): user = options['username'] course_id = options['course'] if not (course_id and user): raise CommandError('both course id and student username are required') student = None print "Fetching enrollment for student {0} in {1}".format(user, course_id) if '@' in user: student = User.objects.get(email=user, courseenrollment__course_id=course_id) else: student = User.objects.get(username=user, courseenrollment__course_id=course_id) print "Fetching course data for {0}".format(course_id) course = modulestore().get_instance(course_id, CourseDescriptor.id_to_location(course_id), depth=2) if not options['noop']: # Add the certificate request to the queue xq = XQueueCertInterface() if options['insecure']: xq.use_https = False ret = xq.regen_cert(student, course_id, course=course) print '{0} - {1}'.format(student, ret) else: print "noop option given, skipping work queueing..."
def handle(self, *args, **options): user = options['username'] course_id = options['course'] if not (course_id and user): raise CommandError( 'both course id and student username are required') student = None print "Fetching enrollment for student {0} in {1}".format( user, course_id) if '@' in user: student = User.objects.get(email=user, courseenrollment__course_id=course_id) else: student = User.objects.get(username=user, courseenrollment__course_id=course_id) print "Fetching course data for {0}".format(course_id) course = modulestore().get_instance( course_id, CourseDescriptor.id_to_location(course_id), depth=2) if not options['noop']: # Add the certificate request to the queue xq = XQueueCertInterface() if options['insecure']: xq.use_https = False ret = xq.regen_cert(student, course_id, course=course, forced_grade=options['grade_value'], template_file=options['template_file']) print '{0} - {1}'.format(student, ret) else: print "noop option given, skipping work queueing..."
def regenerate_user_certificates(student, course_key, course=None, forced_grade=None, template_file=None, insecure=False): """ It will add the regen-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. grade_value - The grade string, such as "Distinction" template_file - The template file used to render this certificate insecure - (Boolean) """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False generate_pdf = not has_html_certificates_enabled(course_key, course) return xqueue.regen_cert( student, course_key, course=course, forced_grade=forced_grade, template_file=template_file, generate_pdf=generate_pdf )
def generate_user_certificates(student, course_key, course=None, insecure=False, generation_mode='batch'): """ It will add the add-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. It also emits `edx.certificate.created` event for analytics. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. insecure - (Boolean) generation_mode - who has requested certificate generation. Its value should `batch` in case of django command and `self` if student initiated the request. """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False generate_pdf = not has_html_certificates_enabled(course_key, course) status, cert = xqueue.add_cert(student, course_key, course=course, generate_pdf=generate_pdf) if status in [CertificateStatuses.generating, CertificateStatuses.downloadable]: emit_certificate_event('created', student, course_key, course, { 'user_id': student.id, 'course_id': unicode(course_key), 'certificate_id': cert.verify_uuid, 'enrollment_mode': cert.mode, 'generation_mode': generation_mode }) return status
def regenerate_user_certificates(student, course_key, course=None, forced_grade=None, template_file=None, insecure=False): """ It will add the regen-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. grade_value - The grade string, such as "Distinction" template_file - The template file used to render this certificate insecure - (Boolean) """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False generate_pdf = not has_html_certificates_enabled(course_key, course) return xqueue.regen_cert(student, course_key, course=course, forced_grade=forced_grade, template_file=template_file, generate_pdf=generate_pdf)
def generate_user_certificates(student, course_key, course=None, insecure=False, generation_mode='batch', forced_grade=None): """ It will add the add-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. It also emits `edx.certificate.created` event for analytics. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. insecure - (Boolean) generation_mode - who has requested certificate generation. Its value should `batch` in case of django command and `self` if student initiated the request. forced_grade - a string indicating to replace grade parameter. if present grading will be skipped. """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False if not course: course = modulestore().get_course(course_key, depth=0) generate_pdf = not has_html_certificates_enabled(course) cert = xqueue.add_cert(student, course_key, course=course, generate_pdf=generate_pdf, forced_grade=forced_grade) # If cert_status is not present in certificate valid_statuses (for example unverified) then # add_cert returns None and raises AttributeError while accesing cert attributes. if cert is None: return if CertificateStatuses.is_passing_status(cert.status): emit_certificate_event( 'created', student, course_key, course, { 'user_id': student.id, 'course_id': unicode(course_key), 'certificate_id': cert.verify_uuid, 'enrollment_mode': cert.mode, 'generation_mode': generation_mode }) return cert.status
def generate_user_certificates(student, course_key, course=None, insecure=False, generation_mode='batch', forced_grade=None): """ It will add the add-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. It also emits `edx.certificate.created` event for analytics. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. insecure - (Boolean) generation_mode - who has requested certificate generation. Its value should `batch` in case of django command and `self` if student initiated the request. forced_grade - a string indicating to replace grade parameter. if present grading will be skipped. """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False if not course: course = modulestore().get_course(course_key, depth=0) generate_pdf = not has_html_certificates_enabled(course) cert = xqueue.add_cert( student, course_key, course=course, generate_pdf=generate_pdf, forced_grade=forced_grade ) # If cert_status is not present in certificate valid_statuses (for example unverified) then # add_cert returns None and raises AttributeError while accesing cert attributes. if cert is None: return if CertificateStatuses.is_passing_status(cert.status): emit_certificate_event('created', student, course_key, course, { 'user_id': student.id, 'course_id': unicode(course_key), 'certificate_id': cert.verify_uuid, 'enrollment_mode': cert.mode, 'generation_mode': generation_mode }) return cert.status
def generate_user_certificates( student, course_key, course=None, insecure=False, generation_mode="batch", forced_grade=None ): """ It will add the add-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. It also emits `edx.certificate.created` event for analytics. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. insecure - (Boolean) generation_mode - who has requested certificate generation. Its value should `batch` in case of django command and `self` if student initiated the request. forced_grade - a string indicating to replace grade parameter. if present grading will be skipped. """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False generate_pdf = not has_html_certificates_enabled(course_key, course) status, cert = xqueue.add_cert( student, course_key, course=course, generate_pdf=generate_pdf, forced_grade=forced_grade ) if status in [CertificateStatuses.generating, CertificateStatuses.downloadable]: emit_certificate_event( "created", student, course_key, course, { "user_id": student.id, "course_id": unicode(course_key), "certificate_id": cert.verify_uuid, "enrollment_mode": cert.mode, "generation_mode": generation_mode, }, ) return status
def handle(self, *args, **options): if options['course']: # try to parse out the course from the serialized form try: course_id = 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_id = SlashSeparatedCourseKey.from_deprecated_string( options['course']) else: raise CommandError("You must specify a course") user = options['username'] if not (course_id and user): raise CommandError( 'both course id and student username are required') student = None print "Fetching enrollment for student {0} in {1}".format( user, course_id) if '@' in user: student = User.objects.get(email=user, courseenrollment__course_id=course_id) else: student = User.objects.get(username=user, courseenrollment__course_id=course_id) print "Fetching course data for {0}".format(course_id) course = modulestore().get_course(course_id, depth=2) if not options['noop']: # Add the certificate request to the queue xq = XQueueCertInterface() if options['insecure']: xq.use_https = False ret = xq.regen_cert(student, course_id, course=course, forced_grade=options['grade_value'], template_file=options['template_file']) print '{0} - {1}'.format(student, ret) else: print "noop option given, skipping work queueing..."
def generate_user_certificates(student, course_key, course=None, insecure=False): """ It will add the add-cert request into the xqueue. A new record will be created to track the certificate generation task. If an error occurs while adding the certificate to the queue, the task will have status 'error'. Args: student (User) course_key (CourseKey) Keyword Arguments: course (Course): Optionally provide the course object; if not provided it will be loaded. insecure - (Boolean) """ xqueue = XQueueCertInterface() if insecure: xqueue.use_https = False generate_pdf = not has_html_certificates_enabled(course_key, course) return xqueue.add_cert(student, course_key, course=course, generate_pdf=generate_pdf)
def handle(self, *args, **options): if options['course']: # try to parse out the course from the serialized form try: course_id = 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_id = SlashSeparatedCourseKey.from_deprecated_string(options['course']) else: raise CommandError("You must specify a course") user = options['username'] if not (course_id and user): raise CommandError('both course id and student username are required') student = None print "Fetching enrollment for student {0} in {1}".format(user, course_id) if '@' in user: student = User.objects.get(email=user, courseenrollment__course_id=course_id) else: student = User.objects.get(username=user, courseenrollment__course_id=course_id) print "Fetching course data for {0}".format(course_id) course = modulestore().get_course(course_id, depth=2) if not options['noop']: # Add the certificate request to the queue xq = XQueueCertInterface() if options['insecure']: xq.use_https = False ret = xq.regen_cert(student, course_id, course=course, forced_grade=options['grade_value'], template_file=options['template_file']) print '{0} - {1}'.format(student, ret) else: print "noop option given, skipping work queueing..."
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)
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) )
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)
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))
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)
def handle(self, *args, **options): # Scrub the username from the log message cleaned_options = copy.copy(options) if 'username' in cleaned_options: cleaned_options['username'] = '******' LOGGER.info( ( u"Starting to create tasks to regenerate certificates " u"with arguments %s and options %s" ), unicode(args), unicode(cleaned_options) ) if options['course']: # try to parse out the course from the serialized form try: course_id = 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_id = SlashSeparatedCourseKey.from_deprecated_string(options['course']) else: raise CommandError("You must specify a course") user = options['username'] if not (course_id and user): raise CommandError('both course id and student username are required') student = None if '@' in user: student = User.objects.get(email=user, courseenrollment__course_id=course_id) else: student = User.objects.get(username=user, courseenrollment__course_id=course_id) course = modulestore().get_course(course_id, depth=2) if not options['noop']: LOGGER.info( ( u"Adding task to the XQueue to generate a certificate " u"for student %s in course '%s'." ), student.id, course_id ) # Add the certificate request to the queue xqueue_interface = XQueueCertInterface() if options['insecure']: xqueue_interface.use_https = False ret = xqueue_interface.regen_cert( student, course_id, course=course, forced_grade=options['grade_value'], template_file=options['template_file'] ) LOGGER.info( ( u"Added a certificate regeneration task to the XQueue " u"for student %s in course '%s'. " u"The new certificate status is '%s'." ), student.id, unicode(course_id), 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_id) ) LOGGER.info( ( u"Finished regenerating certificates command for " u"user %s and course '%s'." ), student.id, unicode(course_id) )
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() 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)