def check_state(self, user, descriptor, expected_score, expected_max_score, expected_attempts=1): """ Check that the StudentModule state contains the expected values. The student module is found for the test course, given the `username` and problem `descriptor`. Values checked include the number of attempts, the score, and the max score for a problem. """ module = self.get_student_module(user.username, descriptor) self.assertEqual(module.grade, expected_score) self.assertEqual(module.max_grade, expected_max_score) state = json.loads(module.state) attempts = state['attempts'] self.assertEqual(attempts, expected_attempts) if attempts > 0: self.assertIn('correct_map', state) self.assertIn('student_answers', state) self.assertGreater(len(state['correct_map']), 0) self.assertGreater(len(state['student_answers']), 0) # assume only one problem in the subsection and the grades # are in sync. expected_subsection_grade = expected_score course_grade = CourseGradeFactory(user).create(self.course) self.assertEquals( course_grade.subsection_grade_totals_by_format['Homework'] [0].earned, expected_subsection_grade, )
def atp_check_certificate(request, course_id): log.info("atp_check_certificate start: " + str(datetime.datetime.now().strftime("%s"))) context = {} try: user = request.user username = user.username course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_by_id(course_key) is_passed = CourseGradeFactory().create(user, course).passed if is_passed: certificate_url = '/api/atp/generate/certificate/' + course_id + '/' else: certificate_url = '' context['course_id'] = course_id context['username'] = username context['passed'] = is_passed context['certificate_url'] = certificate_url context['microsite'] = is_request_in_microsite() context['status'] = True except: context['status'] = False context['message'] = 'Error' log.info("atp_check_certificate end: " + str(datetime.datetime.now().strftime("%s"))) return JsonResponse(context)
def get_all_course_progress(student, course): """ Return course overall progress percentage for a student """ course_grade = CourseGradeFactory().create(student, course) courseware_summary = course_grade.chapter_grades total_score = 0 earned_score = 0 for week in courseware_summary: sections = week.get('sections', []) for section in sections: total_score += section.all_total.possible earned_score += section.all_total.earned if total_score: average = earned_score / total_score percentage = average * 100 else: percentage = 0 return int(percentage)
def get(self, request, course_id): """ Gets a course progress status. Args: request (Request): Django request object. course_id (string): URI element specifying the course location. Return: A JSON serialized representation of the requesting user's current grade status. """ course = self._get_course(course_id, request.user, 'load') if isinstance(course, Response): # Returns a 404 if course_id is invalid, or request.user is not enrolled in the course return course grade_user = self._get_effective_user(request, course) if isinstance(grade_user, Response): # Returns a 403 if the request.user can't access grades for the requested user, # or a 404 if the requested user does not exist. return grade_user prep_course_for_grading(course, request) course_grade = CourseGradeFactory().create(grade_user, course) return Response([{ 'username': grade_user.username, 'course_key': course_id, 'passed': course_grade.passed, 'percent': course_grade.percent, 'letter_grade': course_grade.letter_grade, }])
def ensure_certif(request, course_id): user_id = request.user.id username = request.user.username course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_tma = get_course_by_id(course_key) is_graded = course_tma.is_graded grade_cutoffs = modulestore().get_course( course_key, depth=0).grade_cutoffs['Pass'] * 100 grading_note = CourseGradeFactory().create(request.user, course_tma) #TMA GRADE TRACKING UPDATE mongo_persist = dashboardStats() collection = mongo_persist.connect() add_user = {} add_user['user_id'] = request.user.id add_user['username'] = request.user.username add_user['passed'] = grading_note.passed add_user['percent'] = grading_note.percent add_user['summary'] = grading_note.summary mongo_persist.add_user_grade_info(collection, str(course_id), add_user) # END TMA GRADE TRACKING UPDATE passed = grading_note.passed percent = float(int(grading_note.percent * 1000) / 10) overall_progress = get_overall_progress(request.user.id, course_key) context = { 'passed': passed, 'percent': percent, 'is_graded': is_graded, 'grade_cutoffs': grade_cutoffs, 'overall_progress': overall_progress } return JsonResponse(context)
def get_scores(self, user, course_id): """ Return the scores for each qualifiable unit per user in a determinated course. """ course = get_course_with_access(user, 'load', course_id, depth=None, check_if_enrolled=True) course_grade = CourseGradeFactory().create(user, course) return course_grade.summary
def get_grade_book_page(request, course, course_key): """ Get student records per page along with page information i.e current page, total pages and offset information. """ # Unsanitized offset current_offset = request.GET.get('offset', 0) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1).order_by('username').select_related( "profile") total_students = enrolled_students.count() page = calculate_page_info(current_offset, total_students) offset = page["offset"] total_pages = page["total_pages"] if total_pages > 1: # Apply limit on queryset only if total number of students are greater then MAX_STUDENTS_PER_PAGE_GRADE_BOOK. enrolled_students = enrolled_students[offset:offset + MAX_STUDENTS_PER_PAGE_GRADE_BOOK] with modulestore().bulk_operations(course.location.course_key): student_info = [{ 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': CourseGradeFactory().create(student, course).summary } for student in enrolled_students] return student_info, page
def send_composite_outcome(user_id, course_id, assignment_id, version): """ Calculate and transmit the score for a composite module (such as a vertical). A composite module may contain multiple problems, so we need to calculate the total points earned and possible for all child problems. This requires calculating the scores for the whole course, which is an expensive operation. Callers should be aware that the score calculation code accesses the latest scores from the database. This can lead to a race condition between a view that updates a user's score and the calculation of the grade. If the Celery task attempts to read the score from the database before the view exits (and its transaction is committed), it will see a stale value. Care should be taken that this task is not triggered until the view exits. The GradedAssignment model has a version_number field that is incremented whenever the score is updated. It is used by this method for two purposes. First, it allows the task to exit if it detects that it has been superseded by another task that will transmit the score for the same assignment. Second, it prevents a race condition where two tasks calculate different scores for a single assignment, and may potentially update the campus LMS in the wrong order. """ assignment = GradedAssignment.objects.get(id=assignment_id) if version != assignment.version_number: log.info( "Score passback for GradedAssignment %s skipped. More recent score available.", assignment.id ) return course_key = CourseKey.from_string(course_id) mapped_usage_key = assignment.usage_key.map_into_course(course_key) user = User.objects.get(id=user_id) course = modulestore().get_course(course_key, depth=0) course_grade = CourseGradeFactory().create(user, course) earned, possible = course_grade.score_for_module(mapped_usage_key) if possible == 0: weighted_score = 0 else: weighted_score = float(earned) / float(possible) assignment = GradedAssignment.objects.get(id=assignment_id) if assignment.version_number == version: outcomes.send_score_update(assignment, weighted_score)
def assert_course_grade(self, user, expected_percent): """ Verifies the given user's course grade is the expected percentage. Also verifies the user's grade information contains values for all problems in the course, whether or not they are currently gated. """ course_grade = CourseGradeFactory().create(user, self.course) for prob in [self.gating_prob1, self.gated_prob2, self.prob3]: self.assertIn(prob.location, course_grade.locations_to_scores) self.assertEquals(course_grade.percent, expected_percent)
def ccx_grades_csv(request, course, ccx=None): """ Download grades as CSV. """ if not ccx: raise Http404 ccx_key = CCXLocator.from_course_locator(course.id, unicode(ccx.id)) with ccx_course(ccx_key) as course: prep_course_for_grading(course, request) enrolled_students = User.objects.filter( courseenrollment__course_id=ccx_key, courseenrollment__is_active=1).order_by('username').select_related( "profile") grades = CourseGradeFactory().iter(course, enrolled_students) header = None rows = [] for student, course_grade, __ in grades: if course_grade: # We were able to successfully grade this student for this # course. if not header: # Encode the header row in utf-8 encoding in case there are # unicode characters header = [ section['label'].encode('utf-8') for section in course_grade.summary[u'section_breakdown'] ] rows.append(["id", "email", "username", "grade"] + header) percents = { section['label']: section.get('percent', 0.0) for section in course_grade.summary[u'section_breakdown'] if 'label' in section } row_percents = [percents.get(label, 0.0) for label in header] rows.append([ student.id, student.email, student.username, course_grade.percent ] + row_percents) buf = StringIO() writer = csv.writer(buf) for row in rows: writer.writerow(row) response = HttpResponse(buf.getvalue(), content_type='text/csv') response['Content-Disposition'] = 'attachment' return response
def handle(self, *args, **options): course_id = options['course'] log.info('Fetching ungraded students for %s.', course_id) ungraded = GeneratedCertificate.objects.filter( # pylint: disable=no-member course_id__exact=course_id).filter(grade__exact='') course = courses.get_course_by_id(course_id) for cert in ungraded: # grade the student grade = CourseGradeFactory().create(cert.user, course) log.info('grading %s - %s', cert.user, grade.percent) cert.grade = grade.percent if not options['noop']: cert.save()
def atp_generate_certificate(request, course_id): log.info("atp_generate_certificate start: " + str(datetime.datetime.now().strftime("%s"))) context = {} response = HttpResponse(content_type='application/pdf') response['Content-Disposition'] = 'attachment; filename="certificate.pdf"' user = request.user username = user.username course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_by_id(course_key) categorie = course.categ course_factory = CourseGradeFactory().get_persisted(user, course) is_passed = course_factory.passed courseoverview = CourseOverview.get_from_id(course_key) course_title = courseoverview.display_name_with_default _temp_score = int(course_factory.percent * 1000) score = str(float(_temp_score / 10)) + '%' url = 'https://' + settings.FEATURES['LMS_BASE'] if configuration_helpers.get_value('logo_couleur'): logo_path = configuration_helpers.get_value('logo_couleur') else: logo_path = '/media/certificates/images/logo-amundi.jpg' if configuration_helpers.get_value( 'amundi_brand') and configuration_helpers.get_value( 'amundi_brand') == "true": amundi_academy = '/media/certificates/images/logo-amundi-academy.jpg' else: amundi_academy = '' if configuration_helpers.get_value('primary_color'): primary_color = configuration_helpers.get_value('primary_color') else: primary_color = '' if configuration_helpers.get_value('secondary_color'): secondary_color = configuration_helpers.get_value('secondary_color') else: secondary_color = '' course_img_path = courseoverview.image_urls['raw'] course_img_path = url + course_img_path template_path = '/certificates/template.html' certif_img_path = url + '/media/certificates/images/tampon.png' #return HttpResponse(pdf) return generate_html(username, score, course_img_path, template_path, course_title, categorie, certif_img_path, logo_path, amundi_academy, course.language, user.first_name + ' ' + user.last_name, primary_color, secondary_color)
def _add_entrance_exam_to_context(self, courseware_context): """ Adds entrance exam related information to the given context. """ if course_has_entrance_exam(self.course) and getattr( self.chapter, 'is_entrance_exam', False): courseware_context[ 'entrance_exam_passed'] = user_has_passed_entrance_exam( self.effective_user, self.course) courseware_context[ 'entrance_exam_current_score'] = get_entrance_exam_score_ratio( CourseGradeFactory().create(self.effective_user, self.course), get_entrance_exam_usage_key(self.course), )
def get(self, request, course_id): """ Gets a course progress status. Args: request (Request): Django request object. course_id (string): URI element specifying the course location. Return: A JSON serialized representation of the requesting user's current grade status. """ username = request.GET.get('username') # only the student can access her own grade status info if request.user.username != username: log.info('User %s tried to access the grade for user %s.', request.user.username, username) return self.make_error_response( status_code=status.HTTP_404_NOT_FOUND, developer_message= 'The user requested does not match the logged in user.', error_code='user_mismatch') course = self._get_course(course_id, request.user, 'load') if isinstance(course, Response): return course prep_course_for_grading(course, request) course_grade = CourseGradeFactory(request.user).create(course) if not course_grade.has_access_to_course: # This means the student didn't have access to the course log.info('User %s not allowed to access grade for course %s', request.user.username, username) return self.make_error_response( status_code=status.HTTP_403_FORBIDDEN, developer_message= 'The user does not have access to the course.', error_code='user_does_not_have_access_to_course') return Response([{ 'username': username, 'course_key': course_id, 'passed': course_grade.passed, 'percent': course_grade.percent, 'letter_grade': course_grade.letter_grade, }])
def ensure_certif(request, course_id): user_id = request.user.id username = request.user.username course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_tma = get_course_by_id(course_key) is_graded = course_tma.is_graded grade_cutoffs = modulestore().get_course( course_key, depth=0).grade_cutoffs['Pass'] * 100 grading_note = CourseGradeFactory().create(request.user, course_tma) passed = grading_note.passed percent = float(int(grading_note.percent * 1000) / 10) overall_progress = get_overall_progress(request.user.id, course_key) context = { 'passed': passed, 'percent': percent, 'is_graded': is_graded, 'grade_cutoffs': grade_cutoffs, 'overall_progress': overall_progress } return JsonResponse(context)
def send_grade_report(microsite, course_id, register_form, certificate_form, report_fields, receivers): #Get report info course_key = CourseKey.from_string(course_id) course = get_course_by_id(course_key) #Dict of labels form_labels = {} for field in register_form: form_labels[field.get('name')] = field.get('label') for field in certificate_form: form_labels[field.get('name')] = field.get('label') form_labels['last_connexion'] = "Dernière connexion" form_labels['inscription_date'] = "Date d'inscription" form_labels['user_id'] = 'Id Utilisateur' form_labels['email'] = 'Email' form_labels['grade_final'] = 'Note finale' form_labels['cohorte_names'] = "Nom de la cohorte" #Form Factory form_factory = ensure_form_factory() form_factory_db = 'ensure_form' form_factory_collection = 'certificate_form' form_factory.connect(db=form_factory_db, collection=form_factory_collection) #get workbook wb = Workbook(encoding='utf-8') filename = '/home/edxtma/csv/{}_{}.xls'.format( time.strftime("%Y_%m_%d"), course.display_name_with_default) sheet = wb.add_sheet('Stats') #Prepare header log.info('report_fields {}'.format(report_fields)) cell = 0 for field in report_fields: if field == "grade_detailed": grade_detail_labels = [] for evaluation in course._grading_policy['RAW_GRADER']: grade_detail_labels.append(evaluation['type']) sheet.write(0, cell, evaluation['type']) cell += 1 else: sheet.write(0, cell, form_labels.get(field)) cell += 1 if "cohorte_names" in report_fields: cohortes = CourseUserGroup.objects.filter(course_id=course_key) cohortes_names = {} for cohorte in cohortes: cohortes_names[cohorte.id] = cohorte.name #Get user report info course_enrollments = CourseEnrollment.objects.filter(course_id=course_key) line = 1 for enrollment in course_enrollments: cell = 0 user = enrollment.user user_grade = CourseGradeFactory().create(user, course) grade_summary = {} for section_grade in user_grade.grade_value['section_breakdown']: grade_summary[section_grade['category']] = section_grade['percent'] try: custom_field = json.loads( UserProfile.objects.get(user=user).custom_field) except: custom_field = {} user_certificate_info = {} form_factory.microsite = microsite form_factory.user_id = user.id try: user_certificate_info = form_factory.getForm( user_id=True, microsite=True).get('form') except: pass for field in report_fields: if field == "last_connexion": try: last_login = user.last_login.strftime('%d-%m-%y') except: last_login = '' sheet.write(line, cell, last_login) cell += 1 elif field == "inscription_date": try: date_joined = user.date_joined.strftime('%d-%m-%y') except: date_joined = '' sheet.write(line, cell, date_joined) cell += 1 elif field == "user_id": sheet.write(line, cell, user.id) cell += 1 elif field == "email": sheet.write(line, cell, user.email) cell += 1 elif field == "cohorte_names": cohortes_list = '' if CohortMembership.objects.filter(course_id=course_key, user_id=user.id).exists(): user_cohortes = CohortMembership.objects.filter( course_id=course_key, user_id=user.id) log.info('user cohorteeeeeeeeeeessssssss{}'.format( user_cohortes)) for cohorte in user_cohortes: cohortes_list += cohortes_names[ cohorte.course_user_group_id] + " " sheet.write(line, cell, cohortes_list) cell += 1 elif field == "grade_detailed": for section in grade_detail_labels: section_grade = str( int(round(grade_summary[section] * 100))) + '%' sheet.write(line, cell, section_grade) cell += 1 elif field == "grade_final": percent = str(int(round(user_grade.percent * 100))) + '%' sheet.write(line, cell, percent) cell += 1 elif field in user_certificate_info.keys(): certificate_value = user_certificate_info.get(field) sheet.write(line, cell, certificate_value) cell += 1 else: try: user_data = custom_field[field] except: user_data = "" sheet.write(line, cell, user_data) cell += 1 line += 1 log.warning("file ok") #Save the file output = BytesIO() wb.save(output) _files_values = output.getvalue() log.warning("file saved") html = "<html><head></head><body><p>Bonjour,<br/><br/>Vous trouverez en PJ le rapport de donnees du MOOC {}<br/><br/>Bonne reception<br>The MOOC Agency<br></p></body></html>".format( course.display_name) part2 = MIMEText(html.encode('utf-8'), 'html', 'utf-8') for receiver in receivers: fromaddr = "*****@*****.**" toaddr = str(receiver) msg = MIMEMultipart() msg['From'] = fromaddr msg['To'] = toaddr msg['Subject'] = "Rapport des reussites" attachment = _files_values part = MIMEBase('application', 'octet-stream') part.set_payload(attachment) encoders.encode_base64(part) part.add_header( 'Content-Disposition', "attachment; filename= %s" % os.path.basename(filename)) msg.attach(part) server = smtplib.SMTP('mail3.themoocagency.com', 25) server.starttls() server.login('contact', 'waSwv6Eqer89') msg.attach(part2) text = msg.as_string() server.sendmail(fromaddr, toaddr, text) server.quit() log.warning("file sent to {}".format(receiver)) response = {'path': filename, 'send_to': receivers} return response
def task_generate_xls(self): log.info('Start task generate XLS') #Get report infos self.microsite = self.request.get('microsite') report_fields = self.request.get('form') register_fields = self.request.get('register_form') certificate_fields = self.request.get('certificate_form') course_key = CourseKey.from_string(self.course_id) course = get_course_by_id(course_key) form_factory = ensure_form_factory() form_factory.connect(db='ensure_form', collection='certificate_form') #Dict of labels form_labels = { "last_connexion": _("Last login"), "inscription_date": _("Register date"), "user_id": _("User id"), "email": _("Email"), "grade_final": _("Final Grade"), "cohorte_names": _("Cohorte name"), "time_tracking": _("Time spent"), "certified": _("Attestation"), "username": _("Username"), } for field in register_fields: form_labels[field.get('name')] = field.get('label') for field in certificate_fields: form_labels[field.get('name')] = field.get('label') #Identify multiple cells fields multiple_cell_fields = ["exercises_grade", "grade_detailed"] #Is report cohort specific? course_cohorted = is_course_cohorted(course_key) if course_cohorted: cohortes_targeted = [ field.replace('cohort_selection_', '') for field in report_fields if field.find('cohort_selection_') > -1 ] for field in report_fields: log.info(field) log.info(field.find('cohort_selection_')) log.info(cohortes_targeted) log.info('cohortes_targeted') if cohortes_targeted and not 'cohorte_names' in report_fields: report_fields.append('cohorte_names') else: if 'cohorte_names' in report_fields: report_fields.remove('cohorte_names') #Get Graded block for exercises_grade details graded_scorable_blocks = self.tma_graded_scorable_blocks_to_header( course_key) #Create Workbook wb = Workbook(encoding='utf-8') filename = '/home/edxtma/csv/{}_{}.xls'.format( time.strftime("%Y_%m_%d"), course.display_name_with_default) sheet = wb.add_sheet('Grade Report') #Write information line = 1 course_enrollments = CourseEnrollment.objects.filter( course_id=course_key, is_active=1) for enrollment in course_enrollments: #do not include in reports if not active if not enrollment.is_active: continue #Gather user information user = enrollment.user user_grade = CourseGradeFactory().create(user, course) grade_summary = {} if course_cohorted: user_cohorte = get_cohort(user, course_key).name #if cohort specific report avoid student that are not part of cohortes_targeted provided if cohortes_targeted and not user_cohorte in cohortes_targeted: continue for section_grade in user_grade.grade_value['section_breakdown']: grade_summary[ section_grade['category']] = section_grade['percent'] try: custom_field = json.loads( UserProfile.objects.get(user=user).custom_field) except: custom_field = {} user_certificate_info = {} try: form_factory.microsite = self.microsite form_factory.user_id = user.id user_certificate_info = form_factory.getForm( user_id=True, microsite=True).get('form') except: pass cell = 0 for field in report_fields: if field in multiple_cell_fields: if field == "grade_detailed": for section in grade_summary: section_grade = str( int(round(grade_summary[section] * 100))) + '%' sheet.write(line, cell, section_grade) #Write header if line == 1: sheet.write(0, cell, "Travail - " + section) cell += 1 elif field == "exercises_grade": for block_location in graded_scorable_blocks.items(): try: problem_score = user_grade.locations_to_scores[ block_location[0]] if problem_score.attempted: value = round( float(problem_score.earned) / problem_score.possible, 2) else: value = _('n.a.') except: value = _('inv.') sheet.write(line, cell, value) if line == 1: sheet.write(0, cell, block_location[1]) cell += 1 else: value = '' if field == "user_id": value = user.id elif field == "email": value = user.email elif field == "first_name": try: if user.first_name: value = user.first_name elif custom_field: value = custom_field.get( 'first_name', 'unkowna') else: value = 'unknown' except: value = 'unknown' elif field == "last_name": try: if user.last_name: value = user.last_name elif custom_field: value = custom_field.get( 'last_name', 'unkowna') except: value = 'unknown' elif field == "last_connexion": try: value = user.last_login.strftime('%d-%m-%y') except: value = '' elif field == "inscription_date": try: value = user.date_joined.strftime('%d-%m-%y') except: value = '' elif field == "cohorte_names": try: value = user_cohorte except: value = '' elif field == "time_tracking": value = self.get_time_tracking(enrollment) elif field == "certified": if user_grade.passed: value = _("Yes") else: value = _("No") elif field == "grade_final": value = str(int(round(user_grade.percent * 100))) + '%' elif field == "username": value = user.username elif field in user_certificate_info.keys(): value = user_certificate_info.get(field) else: value = custom_field.get(field, '') #Write header and write value log.info('field') log.info(field) log.info('value') log.info(value) log.info(form_labels) if field in form_labels.keys(): sheet.write(line, cell, value) if line == 1: sheet.write(0, cell, form_labels.get(field)) cell += 1 line += 1 log.warning("file ok") #Save the file output = BytesIO() wb.save(output) _files_values = output.getvalue() log.warning("file saved") #Send the email to receivers receivers = self.request.get('send_to') html = "<html><head></head><body><p>Bonjour,<br/><br/>Vous trouverez en PJ le rapport de donnees du MOOC {}<br/><br/>Bonne reception<br>The MOOC Agency<br></p></body></html>".format( course.display_name) part2 = MIMEText(html.encode('utf-8'), 'html', 'utf-8') for receiver in receivers: fromaddr = "*****@*****.**" toaddr = str(receiver) msg = MIMEMultipart() msg['From'] = fromaddr msg['To'] = toaddr msg['Subject'] = "Rapport de donnees" attachment = _files_values part = MIMEBase('application', 'octet-stream') part.set_payload(attachment) encoders.encode_base64(part) part.add_header( 'Content-Disposition', "attachment; filename= %s" % os.path.basename(filename)) msg.attach(part) server = smtplib.SMTP('mail3.themoocagency.com', 25) server.starttls() server.login('contact', 'waSwv6Eqer89') msg.attach(part2) text = msg.as_string() server.sendmail(fromaddr, toaddr, text) server.quit() log.warning("file sent to {}".format(receiver)) response = {'path': self.filename, 'send_to': receivers} return response
def handle(self, *args, **options): if os.path.exists(options['output']): raise CommandError("File {0} already exists".format( options['output'])) status_interval = 100 # parse out the course into a coursekey if options['course']: try: course_key = CourseKey.from_string(options['course']) # if it's not a new-style course key, parse it from an old-style # course key except InvalidKeyError: course_key = SlashSeparatedCourseKey.from_deprecated_string( options['course']) print "Fetching enrolled students for {0}".format(course_key) enrolled_students = User.objects.filter( courseenrollment__course_id=course_key) factory = RequestMock() request = factory.get('/') total = enrolled_students.count() print "Total enrolled: {0}".format(total) course = courses.get_course_by_id(course_key) total = enrolled_students.count() start = datetime.datetime.now() rows = [] header = None print "Fetching certificate data" cert_grades = { cert.user.username: cert.grade for cert in list( GeneratedCertificate.objects.filter( # pylint: disable=no-member course_id=course_key).prefetch_related('user')) } print "Grading students" for count, student in enumerate(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, __ = divmod(remainder, 60) print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format( count, total, hours, minutes) start = datetime.datetime.now() request.user = student grade = CourseGradeFactory().create(student, course) if not header: header = [ section['label'] for section in grade.summary[u'section_breakdown'] ] rows.append( ["email", "username", "certificate-grade", "grade"] + header) percents = { section['label']: section['percent'] for section in grade.summary[u'section_breakdown'] } row_percents = [percents[label] for label in header] if student.username in cert_grades: rows.append([ student.email, student.username, cert_grades[student.username], grade.percent ] + row_percents, ) else: rows.append( [student.email, student.username, "N/A", grade.percent] + row_percents) with open(options['output'], 'wb') as f: writer = csv.writer(f) writer.writerows(rows)
def tma_users_registered(self): context = {} enrolled_to_current_course = False user_email = self.request.POST['user_email'] if User.objects.filter(email=user_email).exists(): user = User.objects.get(email=user_email) #Get preprofile info userprofile = UserProfile.objects.get(user=user) try: custom_field = json.loads(user.profile.custom_field) first_name = custom_field['first_name'] last_name = custom_field['last_name'] except: custom_field = {} last_name = 'Undefined' first_name = 'Undefined' #Get courses enrollments microsite_courses = get_courses( user=user, org=configuration_helpers.get_value('course_org_filter')) user_ms_course_list = {} for course in microsite_courses: if CourseEnrollment.objects.filter( user=user, course_id=course.id).exists(): user_ms_course_list[str(course.id)] = { 'course_name': course.display_name_with_default, 'course_grades': '/courses/' + str(course.id) + '/progress/' + str(user.id), 'opened_enrollments': is_enrollment_opened(course), 'opened_course': is_course_opened(course), 'on_invitation': course.invitation_only, } #Get user grade for this course course_key = SlashSeparatedCourseKey.from_deprecated_string( self.course_id) current_course = get_course_by_id(course_key) grade = CourseGradeFactory().create(user, current_course) #User dates if user.last_login is not None: last_login = user.date_joined.strftime("%d-%b-%Y %H:%M:%S") else: last_login = _('User has not logged in yet') context = { 'email': str(user_email), 'id': str(user.id), 'inscription': str(user.date_joined.strftime("%d-%b-%Y %H:%M:%S")), 'last_login': last_login, 'first_name': first_name, 'last_name': last_name, 'user_ms_course_list': user_ms_course_list, 'custom_field': custom_field, 'grade': grade.grade_value['percent'], 'passed': grade.grade_value['grade'], 'active': user.is_active, 'login_failure': LoginFailures.is_user_locked_out(user), } #Check if user is registered to this course course_key = SlashSeparatedCourseKey.from_deprecated_string( self.course_id) if CourseEnrollment.objects.filter(user=user, course_id=course_key, is_active=1).exists(): current_course_grades = '/courses/' + str( self.course_id) + '/progress/' + str(user.id) context['enrolled_to_current_course'] = True context['current_course_grades'] = current_course_grades else: context['enrolled_to_current_course'] = False else: context = { 'error': 'Le participant n\'a pas de compte sur nos plateformes.' } return context
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() grade = CourseGradeFactory().create(student, course).summary 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) if forced_grade: grade['grade'] = forced_grade 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 = 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() 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)
def export(self, sended_email): reload(sys) sys.setdefaultencoding('utf8') log.warning("export: Start Task grade reports course_id : " + str(self.course_id)) course_key = CourseKey.from_string(self.course_id) course = get_course_by_id(course_key) course_enrollement = CourseEnrollment.objects.filter( course_id=course_key) #prepare xls header = [ "id", "email", "first name", "last name", "level 1", "level 2", "level 3", "level 4" ] # Email content language_setup = { "en": { "subject": "Score report for {}", "text_content": "Please, find attached the score report for {}.\nRemember that if your training campaign is still in progress, this file is an intermediate statistical status." }, "fr": { "subject": "Résultats des participants du module {}", "text_content": "Veuillez trouver en pièce attachée les résultats des participants pour le module {}.\nA noter que si votre campagne de formation est toujours en cours, ce fichier constitue un état statistique intermédiaire." } } title = self.get_titles() for n in title: header.append(n.get('unit') + ' - ' + n.get('title')) header.append('total grade (in %)') filename = '{}_grades_reports.xls'.format(self.course_id).replace( '+', '_') wb = Workbook(encoding='utf-8') sheet = wb.add_sheet('Users') for i, head in enumerate(header): sheet.write(0, i, head) j = 0 for i in range(len(course_enrollement)): j = j + 1 user = course_enrollement[i].user course_grade = CourseGradeFactory().create(user, course) user_id = user.id email = user.email first_name = user.first_name last_name = user.last_name log.info("export: getting grade for user: "******"", "", "", ""] final_grade = course_grade.percent * 100 _user_blocks = self._user(user_id) sheet.write(j, 0, user_id) sheet.write(j, 1, email) sheet.write(j, 2, first_name) sheet.write(j, 3, last_name) sheet.write(j, 4, _lvl[0]) sheet.write(j, 5, _lvl[1]) sheet.write(j, 6, _lvl[2]) sheet.write(j, 7, _lvl[3]) k = 8 for val in title: _grade = 0 for block in _user_blocks: if block.get('root') == val.get('root'): _grade = block.get('earned') sheet.write(j, k, _grade) k = k + 1 sheet.write(j, k, final_grade) output = BytesIO() wb.save(output) _files_values = output.getvalue() log.warning("End Task grade reports course_id : " + str(self.course_id)) #sending mail log.warning("send grade reports course_id : " + str(filename)) log.warning("email5 : " + str(sended_email)) # Email content according to course language (look for #Email content to add new languages) subject = '' text_content = '' if course.language in language_setup: subject = language_setup[course.language]['subject'].format( course.display_name_with_default_escaped) text_content = language_setup[ course.language]['text_content'].format( course.display_name_with_default_escaped) else: subject = language_setup['en']['subject'].format( course.display_name_with_default_escaped) text_content = language_setup['en']['text_content'].format( course.display_name_with_default_escaped) from_email = configuration_helpers.get_value( 'email_from_address', settings.DEFAULT_FROM_EMAIL) to = sended_email mimetype = 'application/vnd.ms-excel' fail_silently = False _data = _files_values #_encoded = base64.b64encode(wb) log.warning("end send grade : right before email is sent out") _email = EmailMessage(subject, text_content, from_email, [to]) _email.attach(filename, _data, mimetype=mimetype) _email.send(fail_silently=fail_silently) log.warning("end send grade reports course_id : " + str(filename)) context = {"filename": filename} return context
def get(self, request, course_id): """ Gets a course progress status. Args: request (Request): Django request object. course_id (string): URI element specifying the course location. Return: A JSON serialized representation of the requesting user's current grade status. """ username = request.GET.get('username') # only the student can access her own grade status info if request.user.username != username: log.info('User %s tried to access the grade for user %s.', request.user.username, username) return self.make_error_response( status_code=status.HTTP_404_NOT_FOUND, developer_message= 'The user requested does not match the logged in user.', error_code='user_mismatch') # build the course key try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: return self.make_error_response( status_code=status.HTTP_404_NOT_FOUND, developer_message='The provided course key cannot be parsed.', error_code='invalid_course_key') # load the course try: course = courses.get_course_with_access(request.user, 'load', course_key, depth=None, check_if_enrolled=True) except Http404: log.info('Course with ID "%s" not found', course_id) return self.make_error_response( status_code=status.HTTP_404_NOT_FOUND, developer_message='The user, the course or both do not exist.', error_code='user_or_course_does_not_exist') prep_course_for_grading(course, request) course_grade = CourseGradeFactory(request.user).create(course) if not course_grade.has_access_to_course: # This means the student didn't have access to the course log.info('User %s not allowed to access grade for course %s', request.user.username, username) return self.make_error_response( status_code=status.HTTP_403_FORBIDDEN, developer_message= 'The user does not have access to the course.', error_code='user_does_not_have_access_to_course') return Response([{ 'username': username, 'course_key': course_id, 'passed': course_grade.passed, 'percent': course_grade.percent, 'letter_grade': course_grade.letter_grade, }])
def _dashboard_username(self): context = { "course_id": self.course_id, "username": self.username, "user_id": '', "course_grade": [], "user_info": '', } try: # get users info users = User.objects.get(username=self.username) # get user id user_id = users.id # get course_key from url's param course_key = SlashSeparatedCourseKey.from_deprecated_string( self.course_id) # get course from course_key course = get_course_by_id(course_key) # get all courses block of the site course_block = StudentModule.objects.all().filter( student_id=user_id, course_id=course_key, max_grade__isnull=False) # var of grades / course_structure course_grade = [] # get course_users_info course_user_info = CourseGradeFactory().create(users, course) # user info responses user_info = [{ 'Grade': str(course_user_info.percent * 100) + '%' }, { 'First_name': users.first_name }, { 'Last_name': users.last_name }, { 'Email': users.email }] for n in course_block: q = {} usage_key = n.module_state_key block_view = BlocksView() block_name = get_blocks(self.request, usage_key, depth='all', requested_fields=['display_name']) root = block_name['root'] display_name = block_name['blocks'][root]['display_name'] q['earned'] = n.grade q['possible'] = n.max_grade q['display_name'] = display_name q['root'] = root course_grade.append(q) context["user_id"] = user_id context["course_grade"] = course_grade context["user_info"] = user_info except: pass return context
def get_student_info(self, email): if User.objects.filter(email=email).exists(): student = User.objects.get(email=email) # List of courses user is enrolled to org_filter_out_set = '' course_org_filter = '' course_enrollments = list( get_course_enrollments(student, course_org_filter, org_filter_out_set)) #last login data_email last_login_brut = str(student.last_login) last_login = last_login_brut.split('.') #Check if microsite admin if MicrositeAdminManager.objects.filter(user=student).exists(): check_admin_microsite = True microsite_key = MicrositeAdminManager.objects.get( user=student).microsite_id microsite_admin_org = Microsite.objects.get( pk=microsite_key).key else: check_admin_microsite = False #Check wich course invited first if CourseEnrollment.objects.filter(user=student).exists(): course_id = CourseEnrollment.objects.filter( user=student).order_by('-created')[0].course_id user_org = str(course_id).split('+')[0].replace( "course-v1:", "") else: user_org = "No organization found for user" #Course counters compteur_progress = 0 compteur_finish = 0 compteur_start = 0 compteur_certified = 0 progress_courses = [] finish_courses = [] start_courses = [] certified_courses = [] _now = int(datetime.datetime.now().strftime("%s")) if len(course_enrollments) > 0: #For each course user is enrolled to for dashboard_index, enrollment in enumerate( course_enrollments): course_id = enrollment.course_overview.id user_id = student.id course_tma = get_course_by_id(enrollment.course_id) try: course_grade_factory = CourseGradeFactory().create( student, course_tma) passed = course_grade_factory.passed percent = course_grade_factory.percent except: passed = False percent = 0 course_progression = get_overall_progress( user_id, course_id) try: _end = int( enrollment.course_overview.end.strftime("%s")) except: _end = 0 _progress = True if _end > 0 and _end < _now: _progress = False #storing student results for this class q = {} q['passed'] = passed q['percent'] = float(int(percent * 1000) / 10) q['course_id'] = str(enrollment.course_id) q['duration'] = CourseDetails.fetch( enrollment.course_id).effort q['required'] = course_tma.is_required_atp q['content_data'] = course_tma.content_data q['category'] = course_tma.categ q['display_name_with_default'] = enrollment.course_overview.display_name_with_default q['course_progression'] = course_progression if passed == True: compteur_certified += 1 certified_courses.append(q) if course_progression > 0 and course_progression < 100 and passed == False and _progress == True: compteur_progress += 1 progress_courses.append(q) elif course_progression == 100 or passed or _progress == False: compteur_finish += 1 finish_courses.append(q) elif course_progression == 0 and _progress == True: compteur_start += 1 start_courses.append(q) #Candidate status if student.is_staff: status = "Staff" elif check_admin_microsite: status = "Admin Microsite" else: status = "Student" context = { 'student_id': student.id, 'status': status, 'student_mail': student.email, 'student_name': student.first_name + " " + student.last_name, 'progress_courses': compteur_progress, #'progress_courses': progress_courses, 'finished_courses': compteur_finish, #'finish_courses': finish_courses, 'started_courses': compteur_start, #'start_courses':start_courses, 'certified_courses': compteur_certified, #'certified_course' : certified_courses, 'user_org': user_org, 'last login': last_login[0] } if check_admin_microsite: context['microsite_admin_org'] = microsite_admin_org else: if UserPreprofile.objects.filter(email=email).exists(): user = UserPreprofile.objects.get(email=email) if CourseEnrollmentAllowed.objects.filter( email=email).exists(): profile = CourseEnrollmentAllowed.objects.filter( email=email).order_by('-created') course_id = profile[0].course_id user_org = str(course_id).split('+')[0].replace( "course-v1:", "") else: user_org = "No organization found for user" context = { 'student_mail': email, 'student_name': user.first_name + " " + user.last_name, 'status': "User preregistered on platform", 'user_org': user_org } else: context = { 'student_mail': email, 'status': "Unknown user", } return context
def testMail(self): course_key_string = "course-v1:nautisme-durable+2018+2019" course_key = CourseKey.from_string(course_key_string) requestFalse = { "fields": [ "user_id", "email", "first_name", "last_name", "situation_professionnelle", "inscription_date", "last_connexion", "time_tracking", "grade_detailed", "exercises_grade", "grade_final", "certified", "cohorte_names", "cp", "phone_number" ], "receivers": ["*****@*****.**"] } otoMicrosite = configuration_helpers.get_value('domain_prefix') report_fields = requestFalse.get('fields') register_fields = configuration_helpers.get_value('FORM_EXTRA') certificate_fields = configuration_helpers.get_value( 'CERTIFICATE_FORM_EXTRA') course = get_course_by_id(course_key) microsite_information = Microsite.objects.get(key=otoMicrosite) form_factory = ensure_form_factory() form_factory.connect(db='ensure_form', collection='certificate_form') #Dict of labels form_labels = { "last_connexion": _("Last login"), "inscription_date": _("Register date"), "user_id": _("User id"), "email": _("Email"), "grade_final": _("Final Grade"), "cohorte_names": _("Cohorte name"), "time_tracking": _("Time spent"), "certified": _("Attestation"), "username": _("Username"), } for field in register_fields: form_labels[field.get('name')] = field.get('label') for field in certificate_fields: form_labels[field.get('name')] = field.get('label') #Identify multiple cells fields multiple_cell_fields = ["exercises_grade", "grade_detailed"] #Is report cohort specific? course_cohorted = is_course_cohorted(course_key) cohortes_targeted = [] course_enrollments = CourseEnrollment.objects.filter(course_id=course_key, is_active=1) grade_summary = {} user_certificate_info = {} for enrollment in course_enrollments: if not enrollment.is_active: continue #Gather user information user = enrollment.user user_grade = CourseGradeFactory().create(user, course) # graded_scorable_blocks = tma_graded_scorable_blocks_to_header(course_key) for section_grade in user_grade.grade_value['section_breakdown']: grade_summary[section_grade['category']] = section_grade['percent'] try: custom_field = json.loads( UserProfile.objects.get(user=user).custom_field) except: custom_field = {} user_certificate_info = {} try: form_factory.microsite = self.microsite form_factory.user_id = user.id user_certificate_info = form_factory.getForm( user_id=True, microsite=True).get('form') except: pass valueArrB = [] dictSelection = {} userDict = {} for field in report_fields: userDict["course_id"] = str(course_key) if field in multiple_cell_fields: if field == "grade_detailed": i = 0 for section in grade_summary: print("len(section)") print(len(section)) i += 1 eval = "eval" evalstr = eval + str(i) section_grade = str( int(round(grade_summary[section] * 100))) + '%' userDict[evalstr] = section_grade userDict["nbrWorks"] = i else: value = '' if field == "user_id": value = user.id userDict[field] = value elif field == "email": value = user.email userDict[field] = value elif field == "first_name": try: if user.first_name: value = user.first_name userDict[field] = value elif custom_field: value = custom_field.get('first_name', 'unkowna') userDict[field] = value else: value = 'unknown' userDict[field] = value except: value = 'unknown' userDict[field] = value elif field == "last_name": try: if user.last_name: value = user.last_name userDict[field] = value elif custom_field: value = custom_field.get('last_name', 'unkowna') userDict[field] = value except: value = 'unknown' userDict[field] = value elif field == "last_connexion": try: dateR = user.last_login.strftime('%m-%d-%y') dt = parse(str(dateR)) f_date = dt.date() l_date = str(datetime.date.today()) g_date = parse(l_date) h_date = g_date.date() delta = h_date - f_date if not delta: deltaStr = 0 elif delta == "": deltaStr = 0 else: deltaStr = str(delta.days) userDict[field] = deltaStr except: value = '' userDict[field] = value elif field == "inscription_date": try: value = user.date_joined.strftime('%d-%m-%y') userDict[field] = value except: value = '' userDict[field] = value elif field == "certified": if user_grade.passed: value = _("Yes") userDict[field] = value else: value = _("No") userDict[field] = value elif field == "grade_final": value = str(int(round(user_grade.percent * 100))) + '%' userDict[field] = value elif field == "username": value = user.username userDict[field] = value cut = len(course_enrollments) bigNar.append(userDict) res = bigNar[0:cut] prepare_and_send(res) return JsonResponse(res)
def get_student_info(self, student): # List of courses user is enrolled to org_filter_out_set = '' course_org_filter = '' course_enrollments = list( get_course_enrollments(student, course_org_filter, org_filter_out_set)) #last login data_email last_login_brut = str(student.last_login) last_login = last_login_brut.split('.') #Check if user is staff / microsite admin / student check_admin_microsite = False try: microsite_key = MicrositeAdminManager.objects.get( user=student).microsite_id user_org = microsite = Microsite.objects.get(pk=microsite_key).key check_admin_microsite = True except: user_org = "Not microsite admin" pass compteur_progress = 0 compteur_finish = 0 compteur_start = 0 compteur_certified = 0 progress_courses = [] finish_courses = [] start_courses = [] certified_courses = [] _now = int(datetime.datetime.now().strftime("%s")) if len(course_enrollments) > 0: #For each course user is enrolled to for dashboard_index, enrollment in enumerate(course_enrollments): course_id = enrollment.course_overview.id user_id = student.id course_tma = get_course_by_id(enrollment.course_id) try: course_grade_factory = CourseGradeFactory().create( student, course_tma) passed = course_grade_factory.passed percent = course_grade_factory.percent except: passed = False percent = 0 course_progression = get_overall_progress(user_id, course_id) try: _end = int(enrollment.course_overview.end.strftime("%s")) except: _end = 0 _progress = True if _end > 0 and _end < _now: _progress = False #storing student results for this class q = {} q['passed'] = passed q['percent'] = float(int(percent * 1000) / 10) q['course_id'] = str(enrollment.course_id) q['duration'] = CourseDetails.fetch( enrollment.course_id).effort q['required'] = course_tma.is_required_atp q['content_data'] = course_tma.content_data q['category'] = course_tma.categ q['display_name_with_default'] = enrollment.course_overview.display_name_with_default q['course_progression'] = course_progression if passed == True: compteur_certified += 1 certified_courses.append(q) if course_progression > 0 and course_progression < 100 and passed == False and _progress == True: compteur_progress += 1 progress_courses.append(q) elif course_progression == 100 or passed or _progress == False: compteur_finish += 1 finish_courses.append(q) elif course_progression == 0 and _progress == True: compteur_start += 1 start_courses.append(q) if student.is_staff: status = "Staff" elif check_admin_microsite: status = "Admin Microsite" else: status = "Student" context = { 'student_id': student.id, 'status': status, 'student_mail': student.email, 'student_name': student.first_name + " " + student.last_name, 'progress_courses': compteur_progress, #'progress_courses': progress_courses, 'finished_courses': compteur_finish, #'finish_courses': finish_courses, 'started_courses': compteur_start, #'start_courses':start_courses, 'certified_courses': compteur_certified, #'certified_course' : certified_courses, 'user org': user_org, 'last login': last_login[0] } return context
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() grade = CourseGradeFactory().create(student, course).summary 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) if forced_grade: grade['grade'] = forced_grade 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 = 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() 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)
def get_course_grade(self): """ Return CourseGrade for current user and course. """ return CourseGradeFactory().create(self.student_user, self.course)