def student_grades(student, request, course, keep_raw_scores=False, use_offline=False): ''' This is the main interface to get grades. It has the same parameters as grades.grade, as well as use_offline. If use_offline is True then this will look for an offline computed gradeset in the DB. ''' if not use_offline: return grades.grade(student, request, course, keep_raw_scores=keep_raw_scores) try: ocg = models.OfflineComputedGrade.objects.get(user=student, course_id=course.id) except models.OfflineComputedGrade.DoesNotExist: return dict( raw_scores=[], section_breakdown=[], msg='Error: no offline gradeset available for {}, {}'.format(student, course.id) ) gradeset = json.loads(ocg.gradeset) # Convert score dicts back to Score tuples: def score_from_dict(encoded): """ Given a formerly JSON-encoded Score tuple, return the Score tuple """ if encoded['module_id']: encoded['module_id'] = UsageKey.from_string(encoded['module_id']) return Score(**encoded) totaled_scores = gradeset['totaled_scores'] for section in totaled_scores: totaled_scores[section] = [score_from_dict(score) for score in totaled_scores[section]] gradeset['raw_scores'] = [score_from_dict(score) for score in gradeset['raw_scores']] return gradeset
def offline_grade_calculation(course_key): ''' Compute grades for all students for a specified course, and save results to the DB. ''' tstart = time.time() enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).prefetch_related("groups").order_by('username') enc = MyEncoder() print "{} enrolled students".format(len(enrolled_students)) course = get_course_by_id(course_key) for student in enrolled_students: request = DummyRequest() request.user = student request.session = {} gradeset = grades.grade(student, request, course, keep_raw_scores=True) gs = enc.encode(gradeset) ocg, _created = models.OfflineComputedGrade.objects.get_or_create(user=student, course_id=course_key) ocg.gradeset = gs ocg.save() print "%s done" % student # print statement used because this is run by a management command tend = time.time() dt = tend - tstart ocgl = models.OfflineComputedGradeLog(course_id=course_key, seconds=dt, nstudents=len(enrolled_students)) ocgl.save() print ocgl print "All Done!"
def get(self, request, course_id): """ GET /api/grades_api/v1/grades/{course_id}?username={username} """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) username = request.QUERY_PARAMS.get('username') try: user = get_user(request.user, username) except UserNotFound: return Response({ 'error': 'No such user "{}"'.format(username) }, status=status.HTTP_404_NOT_FOUND) except UserNotAllowed: return Response({ 'error': 'Not allowed to retrieve grades for "{}"'.format(username) }, status=status.HTTP_403_FORBIDDEN) course = get_course_with_access(user, 'load', course_key, depth=None) grade_summary = grades.grade(user, request, course) return Response({ 'username': user.username, 'course_id': course_id, 'percent': grade_summary.get('percent') })
def offline_grade_calculation(course_id): ''' Compute grades for all students for a specified course, and save results to the DB. ''' tstart = time.time() enrolled_students = User.objects.filter( courseenrollment__course_id=course_id, courseenrollment__is_active=1 ).prefetch_related("groups").order_by('username') enc = MyEncoder() print "%d enrolled students" % len(enrolled_students) course = get_course_by_id(course_id) for student in enrolled_students: request = DummyRequest() request.user = student request.session = {} gradeset = grades.grade(student, request, course, keep_raw_scores=True) gs = enc.encode(gradeset) ocg, created = models.OfflineComputedGrade.objects.get_or_create(user=student, course_id=course_id) ocg.gradeset = gs ocg.save() print "%s done" % student # print statement used because this is run by a management command tend = time.time() dt = tend - tstart ocgl = models.OfflineComputedGradeLog(course_id=course_id, seconds=dt, nstudents=len(enrolled_students)) ocgl.save() print ocgl print "All Done!"
def format_user_data(user): try: grade = grades.grade(user, request, course)['percent'] * 100 except: grade = 0.0 student_dict = dict( (ft, getattr(user, ft)) for ft in [sf for sf in STUDENT_FEATURES if sf in USER_FEATURES]) student_profile = user.profile if student_profile: student_dict.update( dict( (tf, getattr(student_profile, tf)) for tf in [pf for pf in STUDENT_FEATURES if pf in PROFILE_FEATURES])) if student_dict['gender']: st_g = student_dict['gender'] student_dict['gender'] = filter(lambda x: x[0] == st_g, GENDER_CONTRAST)[0][1] if student_dict['level_of_education']: st_level = student_dict['level_of_education'] student_dict['level_of_education'] = filter( lambda x: x[0] == st_level, EDU_LEVEL_CONTRAST)[0][1] student_dict.update( {'complete_degree': "{grade}%".format(grade=grade)}) return student_dict
def get(self, request, course_id): """ GET /api/grades_api/v1/grades/{course_id}?username={username} """ course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) username = request.QUERY_PARAMS.get('username') try: user = get_user(request.user, username) except UserNotFound: return Response({'error': 'No such user "{}"'.format(username)}, status=status.HTTP_404_NOT_FOUND) except UserNotAllowed: return Response( { 'error': 'Not allowed to retrieve grades for "{}"'.format(username) }, status=status.HTTP_403_FORBIDDEN) course = get_course_with_access(user, 'load', course_key, depth=None) grade_summary = grades.grade(user, request, course) return Response({ 'username': user.username, 'course_id': course_id, 'percent': grade_summary.get('percent') })
def get_student_course_stats_base(request,course, type="grades"): """ Called by get_student_course_stats and get_student_problem_stats Gets a list of users in a course, and then computes grades for them request - a mock request (using RequestDict) course - a string course id type - whether to get student weighted grades or unweighted grades. If "grades" will get weighted """ fs, db = common.get_db_and_fs_cron(common.student_course_stats_stub) course_obj = get_course_with_access(request.user, course, 'load', depth=None) users_in_course = StudentModule.objects.filter(course_id=course).values('student').distinct() users_in_course_ids = [u['student'] for u in users_in_course] log.debug("Users in course count: {0}".format(len(users_in_course_ids))) courseware_summaries = [] for i in xrange(0,len(users_in_course_ids)): try: user = users_in_course_ids[i] current_task.update_state(state='PROGRESS', meta={'current': i, 'total': len(users_in_course_ids)}) student = User.objects.using('remote').prefetch_related("groups").get(id=int(user)) model_data_cache = None if type=="grades": grade_summary = grades.grade(student, request, course_obj, model_data_cache) else: grade_summary = grades.progress_summary(student, request, course_obj, model_data_cache) courseware_summaries.append(grade_summary) except: log.exception("Could not generate data for {0}".format(users_in_course_ids[i])) return courseware_summaries, users_in_course_ids
def student_course_progress(request, course_id, username): from django.contrib.auth.models import User from courseware.model_data import FieldDataCache from courseware import grades from django.http import Http404, HttpResponse, HttpResponseRedirect student=User.objects.filter(username=username) if not student.exists(): return HttpResponse("Student '%s' not exists." % username) student=student[0] #return HttpResponse(request.session) try: course=get_course_by_id(course_id) except: return HttpResponse("Course '%s' not exists." % course_id) field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_id, student, course, depth=None) grade_summary = grades.grade(student, request, course, field_data_cache) progress="{totalscore:.0%}".format(totalscore=grade_summary['percent']) return HttpResponse("course:%s<br>user:%s<br>progress:%s" % (course_id,username,progress))
def report(self): """Report course grade.""" students = self._get_students() print "\nFetching course data for {0}".format(self.course_id) course = courses.get_course_by_id(self.course_id) request = self._create_request() total = {'users': 0, 'pass': 0, 'notpass': 0} print "Summary Report: Course Name [{0}]".format( course.display_name.encode('utf_8')) for student in students.iterator(): request.user = student total['users'] += 1 certs = GeneratedCertificate.objects.filter( user=student, course_id=self.course_id) for cert in certs.iterator(): grade = grades.grade(cert.user, request, course) summary = grades.progress_summary(student, request, course) self._report_summary(summary) self._add_total(cert.user, grade, total) self._report_total(total)
def student_grades(student, request, course, keep_raw_scores=False, use_offline=False): ''' This is the main interface to get grades. It has the same parameters as grades.grade, as well as use_offline. If use_offline is True then this will look for an offline computed gradeset in the DB. ''' if not use_offline: return grades.grade(student, request, course, keep_raw_scores=keep_raw_scores) try: ocg = models.OfflineComputedGrade.objects.get(user=student, course_id=course.id) except models.OfflineComputedGrade.DoesNotExist: return dict(raw_scores=[], section_breakdown=[], msg='Error: no offline gradeset available for %s, %s' % (student, course.id)) return json.loads(ocg.gradeset)
def _progress(request, course_key, student_id): """ Unwrapped version of "progress". User progress. We show the grade bar and every problem score. Course staff are allowed to see the progress of students in their class. """ course = get_course_with_access(request.user, 'load', course_key, depth=None, check_if_enrolled=True) # check to see if there is a required survey that must be taken before # the user can access the course. if survey.utils.must_answer_survey(course, request.user): return redirect(reverse('course_survey', args=[unicode(course.id)])) staff_access = has_access(request.user, 'staff', course) if student_id is None or student_id == request.user.id: # always allowed to see your own profile student = request.user else: # Requesting access to a different student's profile if not staff_access: raise Http404 student = User.objects.get(id=int(student_id)) # NOTE: To make sure impersonation by instructor works, use # student instead of request.user in the rest of the function. # The pre-fetching of groups is done to make auth checks not require an # additional DB lookup (this kills the Progress page in particular). student = User.objects.prefetch_related("groups").get(id=student.id) courseware_summary = grades.progress_summary(student, request, course) studio_url = get_studio_url(course, 'settings/grading') grade_summary = grades.grade(student, request, course) if courseware_summary is None: #This means the student didn't have access to the course (which the instructor requested) raise Http404 context = { 'course': course, 'courseware_summary': courseware_summary, 'studio_url': studio_url, 'grade_summary': grade_summary, 'staff_access': staff_access, 'student': student, 'reverifications': fetch_reverify_banner_info(request, course_key) } with grades.manual_transaction(): response = render_to_response('courseware/progress.html', context) return response
def handle(self, *args, **options): course_ids = options.get('course_ids') user_ids = options.get('user_ids') # Get the list of courses from the system courses = modulestore().get_courses() # If one or more courses were specified by the caller, just use those ones... if course_ids is not None: filtered_courses = [] for course in courses: if unicode(course.id) in course_ids.split(','): filtered_courses.append(course) courses = filtered_courses for course in courses: users = CourseEnrollment.objects.users_enrolled_in(course.id) # If one or more users were specified by the caller, just use those ones... if user_ids is not None: filtered_users = [] for user in users: if str(user.id) in user_ids.split(','): filtered_users.append(user) users = filtered_users # For each user... for user in users: grade_data = grades.grade(user, course) grade = grade_data['percent'] grading_policy = course.grading_policy proforma_grade = grades.calculate_proforma_grade(grade_data, grading_policy) progress_summary = grades.progress_summary(user, course) try: gradebook_entry = StudentGradebook.objects.get(user=user, course_id=course.id) if (gradebook_entry.grade != grade or gradebook_entry.proforma_grade != proforma_grade or gradebook_entry.progress_summary != progress_summary or gradebook_entry.grade_summary != grade_data or gradebook_entry.grading_policy != grading_policy): gradebook_entry.grade = grade gradebook_entry.proforma_grade = proforma_grade gradebook_entry.progress_summary = json.dumps(progress_summary, cls=EdxJSONEncoder) gradebook_entry.grade_summary = json.dumps(grade_data, cls=EdxJSONEncoder) gradebook_entry.grading_policy = json.dumps(grading_policy, cls=EdxJSONEncoder) gradebook_entry.save() except StudentGradebook.DoesNotExist: StudentGradebook.objects.create( user=user, course_id=course.id, grade=grade, proforma_grade=proforma_grade, progress_summary=json.dumps(progress_summary, cls=EdxJSONEncoder), grade_summary=json.dumps(grade_data, cls=EdxJSONEncoder), grading_policy=json.dumps(grading_policy, cls=EdxJSONEncoder) ) log_msg = 'Gradebook entry created -- Course: {}, User: {} (grade: {}, proforma_grade: {})'.format(course.id, user.id, grade, proforma_grade) print log_msg log.info(log_msg)
def _create_cert_pdf(self, student, request, course): cert, created = GeneratedCertificate.objects.get_or_create( course_id=self.course_id, user=student) grade = grades.grade(cert.user, request, course) print "User {0}: Grade {1}% - {2}".format( cert.user, grade['percent'] * 100, grade['grade']), profile = UserProfile.objects.get(user=student) cert.grade = grade['percent'] cert.mode = 'honor' cert.user = student cert.course_id = self.course_id cert.name = profile.name is_whitelisted = CertificateWhitelist.objects.filter( user=student, course_id=self.course_id, whitelist=True ).exists() if is_whitelisted or grade['grade']: if profile.allow_certificate is False: new_status = CertificateStatuses.restricted cert.status = new_status print ": Status {0}".format(new_status) if not self.noop: cert.save() else: key = self._make_hashkey(self.course_id.to_deprecated_string() + student.username) cert.key = key if not self.noop: response_json = create_cert_pdf( student.username, self.course_id, cert.key, cert.name, course.display_name, grade['percent'], self.file_prefix) response = json.loads(response_json) self._dprint(": Response = {}".format(response), newline=False) cert.download_url = response.get(u'download_url', False) msg = response.get(u'error', False) if msg is False: new_status = CertificateStatuses.generating cert.status = new_status cert.save() print ": Status {0}".format(new_status) else: new_status = CertificateStatuses.error cert.status = new_status cert.save() print ": Status {0}".format(new_status), print ": Error {}".format(msg) else: print ": Status {0} (Noop)".format(cert.status) else: new_status = CertificateStatuses.notpassing cert.status = new_status print ": Status {0}".format(new_status) if not self.noop: cert.save()
def get_raw(self, command="all"): """Get raw data of progress.""" if not OPERATION.has_key(command): log.error('Invalid command: {}'.format(command)) raise InvalidCommand("Invalid command: {}".format(command)) if command == "summary": return self.courseware_summary self.courseware_summary["graded_students"] = 0 student_count = 0 for student in self.students.iterator(): student_count += 1 if (student_count % 100 == 0) or (student_count == self.courseware_summary['active_students']): msg = "Progress %d/%d" % ( student_count, self.courseware_summary['active_students']) if self.update_state is not None: self.update_state(state=msg) log.info(msg) self.request.user = student log.debug(" * Active user: {}".format(student)) grade = grades.grade(student, self.request, self.course) if grade["grade"] is not None: self.courseware_summary["graded_students"] += 1 for category in self.location_list.keys(): if category not in ["problem"]: continue for loc in self.location_list[category]: log.debug(" * Active location: {}".format(loc)) module = get_module_for_student(student, loc) if module is None: log.debug(" * No state found: %s" % (student)) continue self.collect_module_summary(module) cache.set('progress_summary', self.courseware_summary["graded_students"], timeout=24 * 60 * 60) #statistics = self._calc_statistics() #for key in statistics.keys(): # self.module_summary[key].update(statistics[key]) if command == "modules": return self.module_summary return self.courseware_summary, self.module_summary
def get_grade_summary(self): '''calls grades.grade for current user and course''' model_data_cache = ModelDataCache.cache_for_descriptor_descendents( self.course.id, self.student_user, self.course) fake_request = self.factory.get(reverse('progress', kwargs={'course_id': self.course.id})) return grades.grade(self.student_user, fake_request, self.course, model_data_cache)
def get_grade_summary(self): '''calls grades.grade for current user and course''' model_data_cache = ModelDataCache.cache_for_descriptor_descendents( self.course.id, self.student_user, self.course) fake_request = self.factory.get( reverse('progress', kwargs={'course_id': self.course.id})) return grades.grade(self.student_user, fake_request, self.course, model_data_cache)
def _grade_with_errors(student, request, course, keep_raw_scores=False): """This fake grade method will throw exceptions for student3 and student4, but allow any other students to go through normal grading. It's meant to simulate when something goes really wrong while trying to grade a particular student, so we can test that we won't kill the entire course grading run. """ if student.username in ['student3', 'student4']: raise Exception("I don't like {}".format(student.username)) return grade(student, request, course, keep_raw_scores=keep_raw_scores)
def is_student_pass(user, request, course_id): course_key = locator.CourseLocator.from_string(course_id) course = modulestore().get_course(course_key) if not settings.FEATURES.get('ENABLE_ISSUE_CERTIFICATE'): return False # If user is course staff don't grade the user if has_access(user, 'staff', course): return True return bool(grade(user, request, course)['grade'])
def yield_students_progress(self): """Yield progress of students as CSV row.""" header_flag = False student_count = 0 for student in self.students.iterator(): student_count += 1 if (student_count % 100 == 0) or (student_count == self.courseware_summary['active_students']): msg = "Progress %d/%d" % ( student_count, self.courseware_summary['active_students']) if self.update_state is not None: self.update_state(state=msg) log.info(msg) self.request.user = student grade = grades.grade(student, self.request, self.course) for category in self.location_list.keys(): if category not in ["problem"]: continue for loc in self.location_list[category]: module = get_module_for_student(student, loc) if module is None: log.debug(" * No state found: %s" % (student)) continue module_data = self._get_module_data(module) csvrow = [ student.username, module.location, student.last_login.strftime("%Y/%m/%d %H:%M:%S %Z"), grade["grade"], grade["percent"] ] if header_flag is False: header = [ "username", "location", "last_login", "grade", "percent" ] for key in module_data.keys(): header.append(key) header_flag = True yield header for key in module_data.keys(): csvrow.append(module_data[key]) yield csvrow
def handle(self, *args, **options): if os.path.exists(options['output']): raise CommandError("File {0} already exists".format( options['output'])) STATUS_INTERVAL = 100 course_id = options['course'] print "Fetching enrolled students for {0}".format(course_id) enrolled_students = User.objects.filter( courseenrollment__course_id=course_id) factory = RequestMock() request = factory.get('/') total = enrolled_students.count() print "Total enrolled: {0}".format(total) course = courses.get_course_by_id(course_id) 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( course_id=course_id).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, seconds = 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 = grades.grade(student, request, course) if not header: header = [section['label'] for section in grade[u'section_breakdown']] rows.append(["email", "username", "certificate-grade", "grade"] + header) percents = {section['label']: section['percent'] for section in grade[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 get_grade_summary(self): """ calls grades.grade for current user and course. the keywords for the returned object are - grade : A final letter grade. - percent : The final percent for the class (rounded up). - section_breakdown : A breakdown of each section that makes up the grade. (For display) - grade_breakdown : A breakdown of the major components that make up the final grade. (For display) """ return grades.grade(self.student_user, self.course)
def _progress(request, course_id, student_id): """ Unwrapped version of "progress". User progress. We show the grade bar and every problem score. Course staff are allowed to see the progress of students in their class. """ course = get_course_with_access(request.user, course_id, 'load', depth=None) staff_access = has_access(request.user, course, 'staff') if student_id is None or student_id == request.user.id: # always allowed to see your own profile student = request.user else: # Requesting access to a different student's profile if not staff_access: raise Http404 student = User.objects.get(id=int(student_id)) # NOTE: To make sure impersonation by instructor works, use # student instead of request.user in the rest of the function. # The pre-fetching of groups is done to make auth checks not require an # additional DB lookup (this kills the Progress page in particular). student = User.objects.prefetch_related("groups").get(id=student.id) courseware_summary = grades.progress_summary(student, request, course) grade_summary = grades.grade(student, request, course) if courseware_summary is None: #This means the student didn't have access to the course (which the instructor requested) raise Http404 context = { 'course': course, 'courseware_summary': courseware_summary, 'grade_summary': grade_summary, 'staff_access': staff_access, 'student': student, } with grades.manual_transaction(): response = render_to_response('courseware/progress.html', context) 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 course_id = options['course'] 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') factory = RequestMock() request = factory.get('/') total = enrolled_students.count() print "Total enrolled: {0}".format(total) course = courses.get_course_by_id(course_id) total = enrolled_students.count() start = datetime.datetime.now() rows = [] header = None 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, seconds = 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 = grades.grade(student, request, course) if not header: header = [ section['label'] for section in grade[u'section_breakdown'] ] rows.append(["email", "username"] + header) percents = { section['label']: section['percent'] for section in grade[u'section_breakdown'] } row_percents = [percents[label] for label in header] rows.append([student.email, student.username] + row_percents) with open(options['output'], 'wb') as f: writer = csv.writer(f) writer.writerows(rows)
def _progress(request, course_id, student_id): """ Unwrapped version of "progress". User progress. We show the grade bar and every problem score. Course staff are allowed to see the progress of students in their class. """ course = get_course_with_access(request.user, course_id, "load", depth=None) staff_access = has_access(request.user, course, "staff") if student_id is None or student_id == request.user.id: # always allowed to see your own profile student = request.user else: # Requesting access to a different student's profile if not staff_access: raise Http404 student = User.objects.get(id=int(student_id)) # NOTE: To make sure impersonation by instructor works, use # student instead of request.user in the rest of the function. # The pre-fetching of groups is done to make auth checks not require an # additional DB lookup (this kills the Progress page in particular). student = User.objects.prefetch_related("groups").get(id=student.id) courseware_summary = grades.progress_summary(student, request, course) studio_url = get_studio_url(course_id, "settings/grading") grade_summary = grades.grade(student, request, course) if courseware_summary is None: # This means the student didn't have access to the course (which the instructor requested) raise Http404 context = { "course": course, "courseware_summary": courseware_summary, "studio_url": studio_url, "grade_summary": grade_summary, "staff_access": staff_access, "student": student, "reverifications": fetch_reverify_banner_info(request, course_id), } with grades.manual_transaction(): response = render_to_response("courseware/progress.html", context) return response
def get_api(request, course_id): """ **Use Cases** Retrieve final grade of the user. **Example Requests**: GET: /final_grades/course_id GET: /final_grades/course-v1:test+test111+2014_T3 **Returns**: Course_id: id of the course User: current user Grade: Final Grade of the user Error: If any error persists """ if request.user.is_authenticated(): user = request.user try: course_key = SlashSeparatedCourseKey.from_deprecated_string( course_id) course = get_course_with_access(user, 'load', course_key, depth=None) except Exception as e: return Response(data={"Error": e.message}) try: grade_summary = grades.grade(user, request, course) return Response( data={ "User": request.user.username, "Course ID": course_id, "Grade": grade_summary.get('percent') }) except Exception as e: return Response(data={"Error": e.message}) else: return Response( data={"Error": "Authentication credentials were not provided."})
def generate_fun_certificate(student, course_id, course_display_name, course, teachers, organization_display_name, organization_logo, certificate_base_filename, ignore_grades, new_grade, fail_flag): """Generates a certificate for one student and one course.""" profile = UserProfile.objects.get(user=student) student_name = unicode(profile.name).encode('utf-8') # grade the student cert, _created = GeneratedCertificate.objects.get_or_create( user=student, course_id=course_id ) request.user = student grade = grades.grade(student, request, course) cert.grade = grade['percent'] cert.user = student cert.course_id = course_id cert.name = profile.name fail = False if ignore_grades: cert.grade = 1 elif new_grade: fail = fail_flag cert.grade = new_grade elif grade['grade'] is None: ## edx grading fail = True if fail: cert.status = status.notpassing else: key = make_hashkey(random.random()) cert.key = key certificate_filename = certificate_base_filename + key + ".pdf" certificate_language = Course.get_course_language(unicode(course_id)) info = CertificateInfo( student_name, course_display_name, organization_display_name, organization_logo, certificate_filename, teachers, language=certificate_language ) info.generate() cert.status = status.downloadable cert.download_url = settings.CERTIFICATE_BASE_URL + certificate_filename cert.save() return cert.status
def generate_fun_certificate(student, course_id, course_display_name, course, teachers, organization_display_name, organization_logo, certificate_base_filename,ignore_grades, new_grade): """Generates a certificate for one student and one course.""" profile = UserProfile.objects.get(user=student) student_name = unicode(profile.name).encode('utf-8') # grade the student cert, created = GeneratedCertificate.objects.get_or_create( user=student, course_id=course_id) request.user = student grade = grades.grade(student, request, course) cert.grade = grade['percent'] cert.user = student cert.course_id = course_id cert.name = profile.name if ignore_grades: grade['grade'] = 'A' grade['percent'] = 100.0 if new_grade: grade['grade'] = 'A' cert.grade = new_grade cert.save() if grade['grade'] is None: cert.status = status.notpassing else: key = make_hashkey(random.random()) cert.key = key info = CertificateInfo() info.full_name = student_name info.course_name = course_display_name info.teachers = teachers info.organization = organization_display_name info.organization_logo = organization_logo certificate_filename = certificate_base_filename + key + ".pdf"; info.pdf_file_name = os.path.join( settings.CERTIFICATES_DIRECTORY, certificate_filename) if info.generate(): cert.status = status.downloadable cert.download_url = settings.CERTIFICATE_BASE_URL + certificate_filename else: cert.status = status.error cert.error_reason = "Error while generating PDF file" cert.save() return cert.status
def get_final_score(request, course): """ To get the final score for the user in particular course. """ grade_summary = {} student = request.user try: grade_summary = grades.grade(student, request, course) except: pass final_grade = grade_summary.get('percent', 0) return int(final_grade * 100)
def handle(self, *args, **options): course_id = options['course'] print "Fetching ungraded students for {0}".format(course_id) ungraded = GeneratedCertificate.objects.filter( course_id__exact=course_id).filter(grade__exact='') course = courses.get_course_by_id(course_id) factory = RequestFactory() request = factory.get('/') for cert in ungraded: # grade the student grade = grades.grade(cert.user, request, course) print "grading {0} - {1}".format(cert.user, grade['percent']) cert.grade = grade['percent'] if not options['noop']: cert.save()
def get_grade_summary(self): """ calls grades.grade for current user and course. the keywords for the returned object are - grade : A final letter grade. - percent : The final percent for the class (rounded up). - section_breakdown : A breakdown of each section that makes up the grade. (For display) - grade_breakdown : A breakdown of the major components that make up the final grade. (For display) """ fake_request = self.factory.get(reverse("progress", kwargs={"course_id": self.course.id})) return grades.grade(self.student_user, fake_request, self.course)
def get_student_course_grade(request, course_key_string, username): """ A server to server api view which computes and returns the student's grade for a course. A boolean `passed` property is computed and bound to the grade summary dict to know if student has passed or not the course according to the course grade cutoffs. Example of response : { "section_breakdown": [ { "category": "Exams", "percent": 1.0, "detail": "Exams 1 - First section - 100% (1/1)", "label": "Exam 01" }, ], "passed": true, "grade": "A", "totaled_scores": { "Exams": [[1.0, 1.0, true, "First section", null]], }, "percent": 1.0, "grade_breakdown": [ { "category": "Exams", "percent": 1.0, "detail": "Exams = 100.00% of a possible 100.00%" }, ] } """ try: student = User.objects.get(username=username) course_key = CourseKey.from_string(course_key_string) course = courses.get_course(course_key) except (User.DoesNotExist, ValueError) as error: return Response(str(error), status=404) grade_summary = grade(student, request, course, keep_raw_scores=False) grade_summary.update({ 'passed': _computed_passed(course.grade_cutoffs, grade_summary.get('percent')) }) return Response(grade_summary, status=200)
def offline_grade_calculation(course_id): ''' Compute grades for all students for a specified course, and save results to the DB. ''' tstart = time.time() enrolled_students = User.objects.filter( courseenrollment__course_id=course_id).prefetch_related( "groups").order_by('username') enc = MyEncoder() class DummyRequest(object): META = {} def __init__(self): return def get_host(self): return 'edx.mit.edu' def is_secure(self): return False request = DummyRequest() print "%d enrolled students" % len(enrolled_students) course = get_course_by_id(course_id) for student in enrolled_students: gradeset = grades.grade(student, request, course, keep_raw_scores=True) gs = enc.encode(gradeset) ocg, created = models.OfflineComputedGrade.objects.get_or_create( user=student, course_id=course_id) ocg.gradeset = gs ocg.save() print "%s done" % student # print statement used because this is run by a management command tend = time.time() dt = tend - tstart ocgl = models.OfflineComputedGradeLog(course_id=course_id, seconds=dt, nstudents=len(enrolled_students)) ocgl.save() print ocgl print "All Done!"
def extract_student(student, features): """ convert student to dictionary """ student_features = [x for x in STUDENT_FEATURES if x in features] profile_features = [x for x in PROFILE_FEATURES if x in features] student_dict = dict((feature, getattr(student, feature)) for feature in student_features) profile = student.profile if profile is not None: profile_dict = dict((feature, getattr(profile, feature)) for feature in profile_features) student_dict.update(profile_dict) try: student_dict['district']=profile.district.name except: student_dict['district']='' try: student_dict['cohort']=profile.cohort.code except: student_dict['cohort']='' try: student_dict['school']=profile.school.name except: student_dict['school']='' try: reg=Registration.objects.get(user_id=student.id) student_dict['activate_key']=reg.activation_key except: student_dict['activate_key']='' try: if course_completed(request,student,course): student_dict['completed']='YES' else: student_dict['completed']='NO' except Exception as e: student_dict['completed']='error' field_data_cache = FieldDataCache.cache_for_descriptor_descendents(course_id, student, course, depth=None) grade_summary = grades.grade(student, request, course, field_data_cache) student_dict['progress']="{totalscore:.0%}".format(totalscore=grade_summary['percent']) return student_dict
def get_grade_summary(self): """ calls grades.grade for current user and course. the keywords for the returned object are - grade : A final letter grade. - percent : The final percent for the class (rounded up). - section_breakdown : A breakdown of each section that makes up the grade. (For display) - grade_breakdown : A breakdown of the major components that make up the final grade. (For display) """ fake_request = self.factory.get( reverse('progress', kwargs={'course_id': self.course.id})) return grades.grade(self.student_user, fake_request, self.course)
def handle(self, *args, **options): course_id = options.get('course_id') course_ids = [] if course_id: course_ids.append(course_id) else: course_ids = StudentGradebook.objects.filter( grade_summary='').values_list('course_id', flat=True) for course_id in course_ids: course_key = CourseKey.from_string(course_id) users = CourseEnrollment.objects.users_enrolled_in(course_key) course = modulestore().get_course(course_key, depth=None) if course: # For each user... for user in users: request = RequestMockWithoutMiddleware().get('/') request.user = user grade_data = grades.grade(user, course) grade = grade_data['percent'] grading_policy = course.grading_policy proforma_grade = grades.calculate_proforma_grade( grade_data, grading_policy) progress_summary = grades.progress_summary(user, course) try: gradebook_entry = StudentGradebook.objects.get( user=user, course_id=course.id) if not gradebook_entry.grade_summary: gradebook_entry.grade = grade gradebook_entry.proforma_grade = proforma_grade gradebook_entry.progress_summary = json.dumps( progress_summary, cls=EdxJSONEncoder) gradebook_entry.grade_summary = json.dumps( grade_data, cls=EdxJSONEncoder) gradebook_entry.grading_policy = json.dumps( grading_policy, cls=EdxJSONEncoder) gradebook_entry.save() except StudentGradebook.DoesNotExist: pass log_msg = 'Gradebook entry created -- Course: {}, User: {} (grade: {}, proforma_grade: {})'.format( course.id, user.id, grade, proforma_grade) log.info(log_msg)
def get_student_certificate_grade(course_id, student): """Compute the student grade for the certificate exercises in a course Returns: grade (float or None): returns None if the course does not include any 'certificate' exercise. """ request = RequestFactory().get('/') request.session = {} request.user = student course = modulestore().get_course(course_id) grades = courseware_grades.grade(student, request, course) sections_grades = grades['section_breakdown'] for section in sections_grades: if section['label'].lower() in ASSIGNMENT_VALID_SHORT_NAMES: return section['percent'] return None
def progress(request, course_id, student_id=None): """ User progress. We show the grade bar and every problem score. Course staff are allowed to see the progress of students in their class. """ course = get_course_with_access(request.user, course_id, 'load', depth=None) staff_access = has_access(request.user, course, 'staff') if student_id is None or student_id == request.user.id: # always allowed to see your own profile student = request.user else: # Requesting access to a different student's profile if not staff_access: raise Http404 student = User.objects.get(id=int(student_id)) # NOTE: To make sure impersonation by instructor works, use # student instead of request.user in the rest of the function. # The pre-fetching of groups is done to make auth checks not require an # additional DB lookup (this kills the Progress page in particular). student = User.objects.prefetch_related("groups").get(id=student.id) field_data_cache = FieldDataCache.cache_for_descriptor_descendents( course_id, student, course, depth=None) courseware_summary = grades.progress_summary(student, request, course, field_data_cache) grade_summary = grades.grade(student, request, course, field_data_cache) if courseware_summary is None: #This means the student didn't have access to the course (which the instructor requested) raise Http404 context = {'course': course, 'courseware_summary': courseware_summary, 'grade_summary': grade_summary, 'staff_access': staff_access, 'student': student, } context.update() return render_to_response('courseware/progress.html', context)
def student_grades(student, request, course, keep_raw_scores=False, use_offline=False): ''' This is the main interface to get grades. It has the same parameters as grades.grade, as well as use_offline. If use_offline is True then this will look for an offline computed gradeset in the DB. ''' if not use_offline: return grades.grade(student, request, course, keep_raw_scores=keep_raw_scores) try: ocg = models.OfflineComputedGrade.objects.get(user=student, course_id=course.id) except models.OfflineComputedGrade.DoesNotExist: return dict( raw_scores=[], section_breakdown=[], msg='Error: no offline gradeset available for {}, {}'.format( student, course.id)) gradeset = json.loads(ocg.gradeset) # Convert score dicts back to Score tuples: def score_from_dict(encoded): """ Given a formerly JSON-encoded Score tuple, return the Score tuple """ if encoded['module_id']: encoded['module_id'] = UsageKey.from_string(encoded['module_id']) return Score(**encoded) totaled_scores = gradeset['totaled_scores'] for section in totaled_scores: totaled_scores[section] = [ score_from_dict(score) for score in totaled_scores[section] ] gradeset['raw_scores'] = [ score_from_dict(score) for score in gradeset['raw_scores'] ] return gradeset
def generate_fun_certificate(student, course, teachers, university): """Generates a certificate for one student and one course.""" # grade the student cert, _created = GeneratedCertificate.objects.get_or_create( user=student, course_id=course.id ) # TODO We need to create a request object manually. It's very ugly and we should # do something about it. request = RequestFactory().get('/') request.session = {} request.user = student grade = grades.grade(student, request, course) cert.grade = grade['percent'] cert.name = student.profile.name if grade['grade'] is None: cert.status = CertificateStatuses.notpassing else: key = make_certificate_hash_key() certificate_filename = "attestation_suivi_{}_{}.pdf".format( (unicode(course.id).replace('/', '_')), key ) cert.key = key certificate_language = Course.get_course_language(unicode(course.id)) course_display_name = unicode(course.display_name).encode('utf-8') CertificateInfo( student.profile.name, course_display_name, university, certificate_filename, teachers, language=certificate_language ).generate() set_certificate_filename(cert, certificate_filename) cert.save() logger.info("Honor certificate status for student {}: {}".format(student.username, cert.status)) trigger_tracking_log(cert, course, student) return cert.status
def get_student_course_stats_base(request, course, type="grades"): """ Called by get_student_course_stats and get_student_problem_stats Gets a list of users in a course, and then computes grades for them request - a mock request (using RequestDict) course - a string course id type - whether to get student weighted grades or unweighted grades. If "grades" will get weighted """ fs, db = common.get_db_and_fs_cron(common.student_course_stats_stub) course_obj = get_course_with_access(request.user, course, 'load', depth=None) users_in_course = StudentModule.objects.filter( course_id=course).values('student').distinct() users_in_course_ids = [u['student'] for u in users_in_course] log.debug("Users in course count: {0}".format(len(users_in_course_ids))) courseware_summaries = [] for i in xrange(0, len(users_in_course_ids)): try: user = users_in_course_ids[i] current_task.update_state(state='PROGRESS', meta={ 'current': i, 'total': len(users_in_course_ids) }) student = User.objects.using('remote').prefetch_related( "groups").get(id=int(user)) model_data_cache = None if type == "grades": grade_summary = grades.grade(student, request, course_obj, model_data_cache) else: grade_summary = grades.progress_summary( student, request, course_obj, model_data_cache) courseware_summaries.append(grade_summary) except: log.exception("Could not generate data for {0}".format( users_in_course_ids[i])) return courseware_summaries, users_in_course_ids
def generate_fun_certificate(student, course, teachers, university): """Generates a certificate for one student and one course.""" # grade the student cert, _created = GeneratedCertificate.objects.get_or_create( user=student, course_id=course.id) # TODO We need to create a request object manually. It's very ugly and we should # do something about it. request = RequestFactory().get('/') request.session = {} request.user = student grade = grades.grade(student, request, course) cert.grade = grade['percent'] cert.name = student.profile.name if grade['grade'] is None: cert.status = CertificateStatuses.notpassing else: key = make_certificate_hash_key() certificate_filename = "attestation_suivi_{}_{}.pdf".format( (unicode(course.id).replace('/', '_')), key) cert.key = key certificate_language = Course.get_course_language(unicode(course.id)) course_display_name = unicode(course.display_name).encode('utf-8') CertificateInfo(student.profile.name, course_display_name, university, certificate_filename, teachers, language=certificate_language).generate() set_certificate_filename(cert, certificate_filename) cert.save() logger.info("Honor certificate status for student {}: {}".format( student.username, cert.status)) trigger_tracking_log(cert, course, student) return cert.status
def is_course_passed(course, grade_summary=None, student=None, request=None): """ check user's course passing status. return True if passed Arguments: course : course object grade_summary (dict) : contains student grade details. student : user object request (HttpRequest) Returns: returns bool value """ nonzero_cutoffs = [cutoff for cutoff in course.grade_cutoffs.values() if cutoff > 0] success_cutoff = min(nonzero_cutoffs) if nonzero_cutoffs else None if grade_summary is None: grade_summary = grades.grade(student, request, course) return success_cutoff and grade_summary['percent'] >= success_cutoff
def has_passed(request, course_id, section_url_name): """ Returns True if the student has higher or equeal grades in asssignment type. """ student = request.user # Get the course by ID course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) course = get_course_with_access(student, 'load', course_key, depth=None) # Get the grade summary with outer_atomic(): field_data_cache = grades.field_data_cache_for_grading(course, student) scores_client = ScoresClient.from_field_data_cache(field_data_cache) grade_summary = grades.grade(student, request, course, field_data_cache=field_data_cache, scores_client=scores_client) # Get assignment type wise percent assignments = {} for section in grade_summary['section_breakdown']: if section.get('prominent', False): assignments.update({section['category']: section['percent']}) # Get the section assignment type section_assignment_type = '' for chapter in course.get_children(): for sequenctial in chapter.get_children(): if sequenctial.url_name == section_url_name: section_assignment_type = sequenctial.format break # Get section assignment percent percentage = assignments.get(section_assignment_type, 0.0) # Return passing status return percentage * 100 == 100
def offline_grade_calculation(course_key): ''' Compute grades for all students for a specified course, and save results to the DB. ''' tstart = time.time() enrolled_students = User.objects.filter( courseenrollment__course_id=course_key, courseenrollment__is_active=1 ).prefetch_related("groups").order_by('username') enc = MyEncoder() print "{} enrolled students".format(len(enrolled_students)) course = get_course_by_id(course_key) for student in enrolled_students: request = DummyRequest() request.user = student request.session = {} gradeset = grades.grade(student, request, course, keep_raw_scores=True) # Convert Score namedtuples to dicts: totaled_scores = gradeset['totaled_scores'] for section in totaled_scores: totaled_scores[section] = [score._asdict() for score in totaled_scores[section]] gradeset['raw_scores'] = [score._asdict() for score in gradeset['raw_scores']] # Encode as JSON and save: gradeset_str = enc.encode(gradeset) ocg, _created = models.OfflineComputedGrade.objects.get_or_create(user=student, course_id=course_key) ocg.gradeset = gradeset_str ocg.save() print "%s done" % student # print statement used because this is run by a management command tend = time.time() dt = tend - tstart ocgl = models.OfflineComputedGradeLog(course_id=course_key, seconds=dt, nstudents=len(enrolled_students)) ocgl.save() print ocgl print "All Done!"
def get_grade_summary(self): """ calls grades.grade for current user and course. the keywords for the returned object are - grade : A final letter grade. - percent : The final percent for the class (rounded up). - section_breakdown : A breakdown of each section that makes up the grade. (For display) - grade_breakdown : A breakdown of the major components that make up the final grade. (For display) """ field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, self.student_user, self.course) fake_request = self.factory.get(reverse('progress', kwargs={'course_id': self.course.id})) return grades.grade(self.student_user, fake_request, self.course, field_data_cache)
def _generate_user_gradebook(course_key, user): """ Recalculates the specified user's gradebook entry """ # import is local to avoid recursive import from courseware.courses import get_course course_descriptor = get_course(course_key, depth=None) grading_policy = course_descriptor.grading_policy request = RequestMockWithoutMiddleware().get('/') request.user = user request.course_descriptor = course_descriptor progress_summary = progress_summary_wrapped(request, course_id) log.info(progress_summary) grade_summary = grades.grade(user, course_descriptor) grade = grade_summary['percent'] proforma_grade = grades.calculate_proforma_grade(grade_summary, grading_policy) try: gradebook_entry = StudentGradebook.objects.get(user=user, course_id=course_key) if gradebook_entry.grade != grade: gradebook_entry.grade = grade gradebook_entry.proforma_grade = proforma_grade gradebook_entry.progress_summary = json.dumps(progress_summary, cls=EdxJSONEncoder) gradebook_entry.grade_summary = json.dumps(grade_summary, cls=EdxJSONEncoder) gradebook_entry.grading_policy = json.dumps(grading_policy, cls=EdxJSONEncoder) gradebook_entry.save() except StudentGradebook.DoesNotExist: StudentGradebook.objects.create( user=user, course_id=course_key, grade=grade, proforma_grade=proforma_grade, progress_summary=json.dumps(progress_summary, cls=EdxJSONEncoder), grade_summary=json.dumps(grade_summary, cls=EdxJSONEncoder), grading_policy=json.dumps(grading_policy, cls=EdxJSONEncoder))
def offline_grade_calculation(course): ''' Compute grades for all students for a specified course, and save results to the DB. ''' tstart = time.time() enrolled_students = User.objects.filter( courseenrollment__course_id=course.id, courseenrollment__is_active=1).prefetch_related("groups").order_by( 'username') enc = MyEncoder() all_studnets = len(enrolled_students) print "{} enrolled students in {}".format(all_studnets, course.id) counter = 0 for student in enrolled_students: counter += 1 if counter % 1000 == 0: print "{}/{} done: Course {}".format(counter, all_studnets, course.id) request = DummyRequest() request.user = student request.session = {} gradeset = grades.grade(student, request, course, keep_raw_scores=True) ocg, _created = models.OfflineComputedGrade.objects.get_or_create( user=student, course_id=course.id) ocg.gradeset = gradeset['grade'] ocg.save() tend = time.time() dt = tend - tstart ocgl = models.OfflineComputedGradeLog(course_id=course.id, seconds=dt, nstudents=len(enrolled_students)) ocgl.save() print ocgl print "All Done!"
def on_score_changed(sender, **kwargs): """ Listens for a 'score_changed' signal and when observed recalculates the specified user's gradebook entry """ from courseware.views import get_course user = kwargs['user'] course_key = kwargs['course_key'] course_descriptor = get_course(course_key, depth=None) request = RequestMockWithoutMiddleware().get('/') request.user = user progress_summary = grades.progress_summary(user, request, course_descriptor, locators_as_strings=True) grade_summary = grades.grade(user, request, course_descriptor) grading_policy = course_descriptor.grading_policy grade = grade_summary['percent'] proforma_grade = grades.calculate_proforma_grade(grade_summary, grading_policy) try: gradebook_entry = StudentGradebook.objects.get(user=user, course_id=course_key) if gradebook_entry.grade != grade: gradebook_entry.grade = grade gradebook_entry.proforma_grade = proforma_grade gradebook_entry.progress_summary = json.dumps(progress_summary, cls=EdxJSONEncoder) gradebook_entry.grade_summary = json.dumps(grade_summary, cls=EdxJSONEncoder) gradebook_entry.grading_policy = json.dumps(grading_policy, cls=EdxJSONEncoder) gradebook_entry.save() except StudentGradebook.DoesNotExist: StudentGradebook.objects.create( user=user, course_id=course_key, grade=grade, proforma_grade=proforma_grade, progress_summary=json.dumps(progress_summary, cls=EdxJSONEncoder), grade_summary=json.dumps(grade_summary, cls=EdxJSONEncoder), grading_policy=json.dumps(grading_policy, cls=EdxJSONEncoder) )
def format_user_data(user): try: grade = grades.grade(user, request, course)['percent'] * 100 except: grade = 0.0 student_dict = dict((ft, getattr(user, ft)) for ft in [sf for sf in STUDENT_FEATURES if sf in USER_FEATURES]) student_profile = user.profile if student_profile: student_dict.update(dict((tf, getattr(student_profile, tf)) for tf in [pf for pf in STUDENT_FEATURES if pf in PROFILE_FEATURES])) if student_dict['gender']: st_g = student_dict['gender'] student_dict['gender'] = filter(lambda x: x[0] == st_g, GENDER_CONTRAST)[0][1] if student_dict['level_of_education']: st_level = student_dict['level_of_education'] student_dict['level_of_education'] = filter(lambda x: x[0] == st_level, EDU_LEVEL_CONTRAST)[0][1] student_dict.update({'complete_degree': "{grade}%".format(grade=grade)}) return student_dict
def add_cert(self, student, course_id, course=None): """ Arguments: student - User.object course_id - courseenrollment.course_id (string) Request a new certificate for a student. Will change the certificate status to 'generating'. Certificate must be in the 'unavailable', 'error', 'deleted' or 'generating' state. If a student has a passing grade or is in the whitelist table for the course a request will made for a new cert. If a student has allow_certificate set to False in the userprofile table the status will change to 'restricted' If a student does not have a passing grade the status will change to status.notpassing Returns the student's status """ VALID_STATUSES = [status.generating, status.unavailable, status.deleted, status.error, status.notpassing] cert_status = certificate_status_for_student( student, course_id)['status'] if cert_status in VALID_STATUSES: # grade the student # re-use the course passed in optionally so we don't have to re-fetch everything # for every student if course is None: course = courses.get_course_by_id(course_id) profile = UserProfile.objects.get(user=student) cert, created = GeneratedCertificate.objects.get_or_create( user=student, course_id=course_id) grade = grades.grade(student, self.request, course) is_whitelisted = self.whitelist.filter( user=student, course_id=course_id, whitelist=True).exists() if is_whitelisted or grade['grade'] is not None: key = make_hashkey(random.random()) cert.grade = grade['percent'] cert.user = student cert.course_id = course_id cert.key = key cert.name = profile.name # check to see whether the student is on the # the embargoed country restricted list # otherwise, put a new certificate request # on the queue if self.restricted.filter(user=student).exists(): cert.status = status.restricted else: contents = { 'action': 'create', 'username': student.username, 'course_id': course_id, 'name': profile.name, } cert.status = status.generating self._send_to_xqueue(contents, key) cert.save() else: cert_status = status.notpassing cert.grade = grade['percent'] cert.status = cert_status cert.user = student cert.course_id = course_id cert.name = profile.name cert.save() return cert_status
def add_cert(self, student, course_id, course=None): """ Arguments: student - User.object course_id - courseenrollment.course_id (string) Request a new certificate for a student. Will change the certificate status to 'generating'. Certificate must be in the 'unavailable', 'error', 'deleted' or 'generating' state. If a student has a passing grade or is in the whitelist table for the course a request will made for a new cert. If a student has allow_certificate set to False in the userprofile table the status will change to 'restricted' If a student does not have a passing grade the status will change to status.notpassing Returns the student's status """ VALID_STATUSES = [status.generating, status.unavailable, status.deleted, status.error, status.notpassing] cert_status = certificate_status_for_student(student, course_id)['status'] new_status = cert_status if cert_status in VALID_STATUSES: # grade the student # re-use the course passed in optionally so we don't have to re-fetch everything # for every student if course is None: course = courses.get_course_by_id(course_id) profile = UserProfile.objects.get(user=student) # Needed self.request.user = student self.request.session = {} grade = grades.grade(student, self.request, course) is_whitelisted = self.whitelist.filter( user=student, course_id=course_id, whitelist=True).exists() enrollment_mode = CourseEnrollment.enrollment_mode_for_user(student, course_id) mode_is_verified = (enrollment_mode == GeneratedCertificate.MODES.verified) user_is_verified = SoftwareSecurePhotoVerification.user_is_verified(student) user_is_reverified = SoftwareSecurePhotoVerification.user_is_reverified_for_all(course_id, student) org = course_id.split('/')[0] course_num = course_id.split('/')[1] cert_mode = enrollment_mode if (mode_is_verified and user_is_verified and user_is_reverified): template_pdf = "certificate-template-{0}-{1}-verified.pdf".format( org, course_num) elif (mode_is_verified and not (user_is_verified and user_is_reverified)): template_pdf = "certificate-template-{0}-{1}.pdf".format( org, course_num) cert_mode = GeneratedCertificate.MODES.honor else: # honor code and audit students template_pdf = "certificate-template-{0}-{1}.pdf".format( org, course_num) cert, created = GeneratedCertificate.objects.get_or_create( user=student, course_id=course_id) cert.mode = cert_mode cert.user = student cert.grade = grade['percent'] cert.course_id = course_id cert.name = profile.name if is_whitelisted or grade['grade'] is not None: # check to see whether the student is on the # the embargoed country restricted list # otherwise, put a new certificate request # on the queue if self.restricted.filter(user=student).exists(): new_status = status.restricted cert.status = new_status cert.save() else: key = make_hashkey(random.random()) cert.key = key contents = { 'action': 'create', 'username': student.username, 'course_id': course_id, 'name': profile.name, 'grade': grade['grade'], 'template_pdf': template_pdf, } new_status = status.generating cert.status = new_status cert.save() self._send_to_xqueue(contents, key) else: new_status = status.notpassing cert.status = new_status cert.save() return new_status