def get_queryset(self): course_ids = self.request.query_params.get('course_id', None) results = [] if course_ids: course_ids = course_ids.split(',') for course_id in course_ids: course_key = CourseKey.from_string(course_id) course_descriptor = courses.get_course(course_key) results.append(course_descriptor) else: results = modulestore().get_courses() proctoring_system = self.request.query_params.get('proctoring_system') if proctoring_system: results = (course for course in results if course.proctoring_service == proctoring_system) # Ensure only course descriptors are returned. results = (course for course in results if course.scope_ids.block_type == 'course') # Sort the results in a predictable manner. v = sorted(results, key=lambda course: unicode(course.id)) return v
def _get_course(request, user, course_id, depth=0, load_content=False): """ Utility method to obtain course components """ course_descriptor = None course_key = None course_content = None try: course_key = CourseKey.from_string(course_id) except InvalidKeyError: try: course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) except InvalidKeyError: pass if course_key: try: course_descriptor = get_course(course_key, depth=depth) except ValueError: pass if course_descriptor and load_content: field_data_cache = FieldDataCache([course_descriptor], course_key, user) course_content = module_render.get_module( user, request, course_descriptor.location, field_data_cache, course_key ) return course_descriptor, course_key, course_content
def handle(self, *args, **options): """Handler for command.""" task_number = options['task_number'] if len(args) == 2: course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0]) usage_key = course_id.make_usage_key_from_deprecated_string(args[1]) else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_item(usage_key, depth=0) if descriptor is None: print "Location {0} not found in course".format(usage_key) return try: enrolled_students = CourseEnrollment.users_enrolled_in(course_id) print "Total students enrolled in {0}: {1}".format(course_id, enrolled_students.count()) calculate_task_statistics(enrolled_students, course, usage_key, task_number) except KeyboardInterrupt: print "\nOperation Cancelled"
def push_objects_to_sso(sender, course_key, **kwargs): if course_key.branch: return if not hasattr(settings, 'SSO_API_URL'): log.error('settings.SSO_API_URL is not defined') return if not hasattr(settings, 'SSO_API_TOKEN'): log.error('SSO_API_TOKEN is not defined') return url = os.path.join(settings.SSO_API_URL, 'course/') sso_api_headers = {'Authorization': 'Token {}'.format(settings.SSO_API_TOKEN)} course = get_course(course_key) name = course.name or course_key.run start = course.start and datetime.strftime(course.start, '%Y-%m-%dT%H:%M:%SZ') or None end = course.end and datetime.strftime(course.end, '%Y-%m-%dT%H:%M:%SZ') or None data = { 'name': name, 'course_id': course_key.html_id(), 'start': start, 'end': end, 'org': course.org, 'run': course_key.run, } r = requests.post(url, headers=sso_api_headers, data=data) if r.ok: return r.text log.error('API "{}" returned: {}'.format(url, r.status_code))
def send_email_to_student(self, receivers, subject, text): # Instead of sending the email through the rest of the edX bulk mail system, # we're going to use the edX email templater, and then toss the email directly through # the Django mailer. # We're assuming receivers is a list of User IDs. emails = [] email_template = CourseEmailTemplate.get_template() context = get_email_context(CourseData.get_course(self.course_id)) from_address = get_source_address(self.course_id, self.acquire_course_name()) for student_id in list(set(receivers)): context['email'] = self.acquire_student_email(student_id) context['name'] = self.acquire_student_name(student_id) plaintext_message = email_template.render_plaintext(text, context) html_message = email_template.render_htmltext(text, context) email_message = mail.EmailMultiAlternatives(subject, plaintext_message, from_address, [context['email']]) email_message.attach_alternative(html_message, 'text/html') emails.append(email_message) connection = mail.get_connection() connection.send_messages(emails) return
def handle(self, *args, **options): """Handler for command.""" task_number = options['task_number'] if len(args) == 2: course_id = args[0] location = args[1] else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_instance(course.id, location, depth=0) if descriptor is None: print "Location {0} not found in course".format(location) return try: enrolled_students = CourseEnrollment.users_enrolled_in(course_id) print "Total students enrolled in {0}: {1}".format( course_id, enrolled_students.count()) calculate_task_statistics(enrolled_students, course, location, task_number) except KeyboardInterrupt: print "\nOperation Cancelled"
def handle(self, *args, **options): """Handler for command.""" task_number = options['task_number'] if len(args) == 2: course_id = args[0] location = args[1] else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_instance(course.id, location, depth=0) if descriptor is None: print "Location {0} not found in course".format(location) return try: enrolled_students = CourseEnrollment.users_enrolled_in(course_id) print "Total students enrolled in {0}: {1}".format(course_id, enrolled_students.count()) calculate_task_statistics(enrolled_students, course, location, task_number) except KeyboardInterrupt: print "\nOperation Cancelled"
def handle(self, *args, **options): dry_run = options['dry_run'] task_number = options['task_number'] if len(args) == 3: course_id = args[0] location = args[1] students_ids = [line.strip() for line in open(args[2])] else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_instance(course.id, location, depth=0) if descriptor is None: print "Location not found in course" return if dry_run: print "Doing a dry run." students = User.objects.filter(id__in=students_ids).order_by('username') print "Number of students: {0}".format(students.count()) for student in students: post_submission_for_student(student, course, location, task_number, dry_run=dry_run)
def test_problem_with_student_answer_and_answers(self): self.course = get_course(CourseKey.from_string('edX/graded/2012_Fall')) problem_location = Location('edX', 'graded', '2012_Fall', 'problem', 'H1P2') self.create_student() StudentModuleFactory.create( course_id=self.course.id, module_state_key=problem_location, student=self.student, grade=0, state=u'{"student_answers":{"problem_id":"student response1"}}', ) submit_and_compare_location = Location('edX', 'graded', '2012_Fall', 'problem', 'H1P3') StudentModuleFactory.create( course_id=self.course.id, module_state_key=submit_and_compare_location, student=self.student, grade=0, state=u'{"student_answer": "student response2"}', ) submit_and_compare_location = Location("edX", "graded", "2012_Fall", "problem", 'H1P0') StudentModuleFactory.create( course_id=self.course.id, module_state_key=submit_and_compare_location, student=self.student, grade=0, state=u'{"answer": {"problem_id": "123"}}', ) datarows = list(student_responses(self.course)) self.assertEqual(datarows[0][-1], u'problem_id=student response1') self.assertEqual(datarows[1][-1], u'student response2')
def __init__(self, course_id, update_state=None, debug=False): """Initialize.""" self.course_id = get_coursekey(course_id) self.update_state = update_state self.debug = debug self.module_summary = {} """ if isinstance(self.course_id, CourseKey): self.course = get_course(self.course_id) else: self.course = get_course(CourseKey.from_string(self.course_id)) """ self.course = get_course(self.course_id) self.request = self._create_request() self.enroll_count, self.active_count, self.students = self.get_active_students( self.course_id) self.location_list = {} self.location_parent = [] self._get_children_rec(self.course) self.courseware_summary = { "enrollments": self.enroll_count, "active_students": self.active_count, "module_tree": self.location_parent }
def request_certificate(request): """Request the on-demand creation of a certificate for some user, course. A request doesn't imply a guarantee that such a creation will take place. We intentionally use the same machinery as is used for doing certification at the end of a course run, so that we can be sure users get graded and then if and only if they pass, do they get a certificate issued. """ if request.method == "POST": if request.user.is_authenticated(): # Enter your api key here xqci = CertificateGeneration( api_key=settings.APPSEMBLER_FEATURES['ACCREDIBLE_API_KEY']) username = request.user.username student = User.objects.get(username=username) course_key = CourseKey.from_string(request.POST.get('course_id')) course = get_course(course_key) status = certificate_status_for_student(student, course_key)['status'] if status in [ CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error ]: logger.info( 'Grading and certification requested for user {} in course {} via /request_certificate call' .format(username, course_key)) status = xqci.add_cert(student, course_key, course=course) return HttpResponse(json.dumps({'add_status': status}), content_type='application/json') return HttpResponse(json.dumps({'add_status': 'ERRORANONYMOUSUSER'}), content_type='application/json')
def handle(self, *args, **options): dry_run = options['dry_run'] task_number = options['task_number'] if len(args) == 4: course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0]) location = course_id.make_usage_key_from_deprecated_string(args[1]) students_ids = [line.strip() for line in open(args[2])] hostname = args[3] else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_item(location, depth=0) if descriptor is None: print "Location not found in course" return if dry_run: print "Doing a dry run." students = User.objects.filter(id__in=students_ids).order_by('username') print "Number of students: {0}".format(students.count()) for student in students: post_submission_for_student(student, course, location, task_number, dry_run=dry_run, hostname=hostname)
def handle(self, *args, **options): """Handler for command.""" task_number = options['task_number'] if len(args) == 2: course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0]) usage_key = course_id.make_usage_key_from_deprecated_string(args[1]) else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_item(usage_key, depth=0) if descriptor is None: print "Location {0} not found in course".format(usage_key) return try: enrolled_students = CourseEnrollment.objects.users_enrolled_in(course_id) print "Total students enrolled in {0}: {1}".format(course_id, enrolled_students.count()) calculate_task_statistics(enrolled_students, course, usage_key, task_number) except KeyboardInterrupt: print "\nOperation Cancelled"
def test(request): c = get_course('UFC/CS101/2013_Fall') course_loc = loc_mapper().translate_location(c.location.course_id, c.location, published=False, add_entry_if_missing=True) url = course_loc.url_reverse('course/', '') return HttpResponse(url)
def get_course_lti_endpoints(request, course_id): """ View that, given a course_id, returns the a JSON object that enumerates all of the LTI endpoints for that course. The LTI 2.0 result service spec at http://www.imsglobal.org/lti/ltiv2p0/uml/purl.imsglobal.org/vocab/lis/v2/outcomes/Result/service.html says "This specification document does not prescribe a method for discovering the endpoint URLs." This view function implements one way of discovering these endpoints, returning a JSON array when accessed. Arguments: request (django request object): the HTTP request object that triggered this view function course_id (unicode): id associated with the course Returns: (django response object): HTTP response. 404 if course is not found, otherwise 200 with JSON body. """ try: course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) except InvalidKeyError: return HttpResponse(status=404) try: course = get_course(course_key, depth=2) except ValueError: return HttpResponse(status=404) anonymous_user = AnonymousUser() anonymous_user.known = False # make these "noauth" requests like module_render.handle_xblock_callback_noauth lti_descriptors = modulestore().get_items(course.id, qualifiers={'category': 'lti'}) lti_noauth_modules = [ get_module_for_descriptor( anonymous_user, request, descriptor, FieldDataCache.cache_for_descriptor_descendents( course_key, anonymous_user, descriptor ), course_key ) for descriptor in lti_descriptors ] endpoints = [ { 'display_name': module.display_name, 'lti_2_0_result_service_json_endpoint': module.get_outcome_service_url( service_name='lti_2_0_result_rest_handler') + "/user/{anon_user_id}", 'lti_1_1_result_service_xml_endpoint': module.get_outcome_service_url( service_name='grade_handler'), } for module in lti_noauth_modules ] return HttpResponse(json.dumps(endpoints), content_type='application/json')
def get_course_descriptor(course_key, depth): """ Returns course descriptor """ try: course_descriptor = courses.get_course(course_key, depth) except ValueError: course_descriptor = None return course_descriptor
def post(self, request, *args, **kwargs): """ Attempt to enroll the user. """ user = request.user valid, course_key, error = self._is_data_valid(request) if not valid: return DetailResponse(error, status=HTTP_406_NOT_ACCEPTABLE) embargo_response = embargo_api.get_embargo_response( request, course_key, user) if embargo_response: return embargo_response # Don't do anything if an enrollment already exists course_id = unicode(course_key) enrollment = CourseEnrollment.get_enrollment(user, course_key) if enrollment and enrollment.is_active: msg = Messages.ENROLLMENT_EXISTS.format(course_id=course_id, username=user.username) return DetailResponse(msg, status=HTTP_409_CONFLICT) # Check to see if enrollment for this course is closed. course = courses.get_course(course_key) if CourseEnrollment.is_enrollment_closed(user, course): msg = Messages.ENROLLMENT_CLOSED.format(course_id=course_id) log.info(u'Unable to enroll user %s in closed course %s.', user.id, course_id) return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE) # If there is no audit or honor course mode, this most likely # a Prof-Ed course. Return an error so that the JS redirects # to track selection. honor_mode = CourseMode.mode_for_course(course_key, CourseMode.HONOR) audit_mode = CourseMode.mode_for_course(course_key, CourseMode.AUDIT) # Accept either honor or audit as an enrollment mode to # maintain backwards compatibility with existing courses default_enrollment_mode = audit_mode or honor_mode if default_enrollment_mode: msg = Messages.ENROLL_DIRECTLY.format(username=user.username, course_id=course_id) if not default_enrollment_mode.sku: # If there are no course modes with SKUs, return a different message. msg = Messages.NO_SKU_ENROLLED.format( enrollment_mode=default_enrollment_mode.slug, course_id=course_id, username=user.username) log.info(msg) self._enroll(course_key, user, default_enrollment_mode.slug) self._handle_marketing_opt_in(request, course_key, user) return DetailResponse(msg) else: msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format( course_id=course_id) return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE)
def get_course_lti_endpoints(request, course_id): """ View that, given a course_id, returns the a JSON object that enumerates all of the LTI endpoints for that course. The LTI 2.0 result service spec at http://www.imsglobal.org/lti/ltiv2p0/uml/purl.imsglobal.org/vocab/lis/v2/outcomes/Result/service.html says "This specification document does not prescribe a method for discovering the endpoint URLs." This view function implements one way of discovering these endpoints, returning a JSON array when accessed. Arguments: request (django request object): the HTTP request object that triggered this view function course_id (unicode): id associated with the course Returns: (django response object): HTTP response. 404 if course is not found, otherwise 200 with JSON body. """ try: course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id) except InvalidKeyError: return HttpResponse(status=404) try: course = get_course(course_key, depth=2) except ValueError: return HttpResponse(status=404) anonymous_user = AnonymousUser() anonymous_user.known = False # make these "noauth" requests like module_render.handle_xblock_callback_noauth lti_descriptors = modulestore().get_items(course.id, category='lti') lti_noauth_modules = [ get_module_for_descriptor( anonymous_user, request, descriptor, FieldDataCache.cache_for_descriptor_descendents( course_key, anonymous_user, descriptor ), course_key ) for descriptor in lti_descriptors ] endpoints = [ { 'display_name': module.display_name, 'lti_2_0_result_service_json_endpoint': module.get_outcome_service_url( service_name='lti_2_0_result_rest_handler') + "/user/{anon_user_id}", 'lti_1_1_result_service_xml_endpoint': module.get_outcome_service_url( service_name='grade_handler'), } for module in lti_noauth_modules ] return HttpResponse(json.dumps(endpoints), content_type='application/json')
def post(self, request, *args, **kwargs): """ Attempt to enroll the user. """ user = request.user valid, course_key, error = self._is_data_valid(request) if not valid: return DetailResponse(error, status=HTTP_406_NOT_ACCEPTABLE) embargo_response = embargo_api.get_embargo_response(request, course_key, user) if embargo_response: return embargo_response # Don't do anything if an enrollment already exists course_id = unicode(course_key) enrollment = CourseEnrollment.get_enrollment(user, course_key) if enrollment and enrollment.is_active: msg = Messages.ENROLLMENT_EXISTS.format(course_id=course_id, username=user.username) return DetailResponse(msg, status=HTTP_409_CONFLICT) # Check to see if enrollment for this course is closed. course = courses.get_course(course_key) if CourseEnrollment.is_enrollment_closed(user, course): msg = Messages.ENROLLMENT_CLOSED.format(course_id=course_id) log.info(u'Unable to enroll user %s in closed course %s.', user.id, course_id) return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE) # If there is no audit or honor course mode, this most likely # a Prof-Ed course. Return an error so that the JS redirects # to track selection. honor_mode = CourseMode.mode_for_course(course_key, CourseMode.HONOR) audit_mode = CourseMode.mode_for_course(course_key, CourseMode.AUDIT) # Accept either honor or audit as an enrollment mode to # maintain backwards compatibility with existing courses default_enrollment_mode = audit_mode or honor_mode if default_enrollment_mode: msg = Messages.ENROLL_DIRECTLY.format( username=user.username, course_id=course_id ) if not default_enrollment_mode.sku: # If there are no course modes with SKUs, return a different message. msg = Messages.NO_SKU_ENROLLED.format( enrollment_mode=default_enrollment_mode.slug, course_id=course_id, username=user.username ) log.info(msg) self._enroll(course_key, user, default_enrollment_mode.slug) self._handle_marketing_opt_in(request, course_key, user) return DetailResponse(msg) else: msg = Messages.NO_DEFAULT_ENROLLMENT_MODE.format(course_id=course_id) return DetailResponse(msg, status=HTTP_406_NOT_ACCEPTABLE)
def handle(self, *args, **options): course_id = options['course_id'] course_key = CourseKey.from_string(course_id) course = get_course(course_key) if not course: raise CommandError(u'Invalid course id: {}'.format(course_id)) if course.discussion_link: self.stdout.write(course.discussion_link)
def grades(self, request, pk): """ Submit a grade for a Workgroup. The grade will be applied to all members of the workgroup """ # Ensure we received all of the necessary information course_id = request.data.get('course_id') if course_id is None: return Response({}, status=status.HTTP_400_BAD_REQUEST) course_key = get_course_key(course_id) if not course_key: return Response({}, status=status.HTTP_400_BAD_REQUEST) course_descriptor = get_course(course_key) if not course_descriptor: return Response({}, status=status.HTTP_400_BAD_REQUEST) content_id = request.data.get('content_id') if content_id is None: return Response({}, status=status.HTTP_400_BAD_REQUEST) try: usage_key = UsageKey.from_string(content_id) except InvalidKeyError: return Response({}, status=status.HTTP_400_BAD_REQUEST) content_descriptor = modulestore().get_item(usage_key) if content_descriptor is None: return Response({}, status=status.HTTP_400_BAD_REQUEST) grade = request.data.get('grade') if grade is None: return Response({}, status=status.HTTP_400_BAD_REQUEST) max_grade = request.data.get('max_grade') if max_grade is None: return Response({}, status=status.HTTP_400_BAD_REQUEST) if grade > max_grade: max_grade = grade users = User.objects.filter(workgroups=pk) for user in users: SCORE_PUBLISHED.send( sender=None, block=content_descriptor, user=user, raw_earned=grade, raw_possible=max_grade, only_if_higher=None, ) return Response({}, status=status.HTTP_201_CREATED)
def _is_data_valid(self, request): """ Validates the data posted to the view. Arguments request -- HTTP request Returns Tuple (data_is_valid, course_key, error_msg) """ course_id = request.data.get('course_id') if not course_id: return False, None, u'Field course_id is missing.' try: course_key = CourseKey.from_string(course_id) courses.get_course(course_key) except (InvalidKeyError, ValueError)as ex: log.exception(u'Unable to locate course matching %s.', course_id) return False, None, ex.message return True, course_key, None
def dump_one(self, *args, **options): if not args: raise CommandError("Course id not specified") if len(args) > 2: raise CommandError("Only one course id may be specified") raw_course_key = args[0] if len(args) == 1: output_file_location = self.get_default_file_location( raw_course_key) else: output_file_location = args[1] try: course_key = CourseKey.from_string(raw_course_key) except InvalidKeyError: course_key = SlashSeparatedCourseKey.from_deprecated_string( raw_course_key) course = get_course(course_key) if not course: raise CommandError("Invalid course id: {}".format(course_key)) target_discussion_ids = None if options.get(self.COHORTED_ONLY_PARAMETER, False): cohorted_discussions = get_legacy_discussion_settings( course_key).cohorted_discussions if not cohorted_discussions: raise MissingCohortedConfigCommandError( "Only cohorted discussions are marked for export, " "but no cohorted discussions found for the course") else: target_discussion_ids = cohorted_discussions raw_end_date = options.get(self.END_DATE_PARAMETER, None) end_date = dateutil.parser.parse( raw_end_date) if raw_end_date else None data = Extractor().extract( course_key, end_date=end_date, thread_type=(options.get(self.THREAD_TYPE_PARAMETER, None)), thread_ids=target_discussion_ids, ) filter_str = self._get_filter_string_representation(options) self.stdout.write("Writing social stats ({}) to {}\n".format( filter_str, output_file_location)) with open(output_file_location, 'wb') as output_stream: Exporter(output_stream).export(data)
def handle(self, *args, **options): if not args: raise CommandError("Course id not specified") if len(args) > 1: raise CommandError("Only one course id may be specifiied") course_id = args[0] try: course = get_course(course_id) except ValueError: raise CommandError("Invalid course id: {}".format(course_id)) if course.discussion_link: self.stdout.write(course.discussion_link)
def _is_data_valid(self, request): """ Validates the data posted to the view. Arguments request -- HTTP request Returns Tuple (data_is_valid, course_key, error_msg) """ course_id = request.DATA.get('course_id') if not course_id: return False, None, u'Field course_id is missing.' try: course_key = CourseKey.from_string(course_id) courses.get_course(course_key) except (InvalidKeyError, ValueError) as ex: log.exception(u'Unable to locate course matching %s.', course_id) return False, None, ex.message return True, course_key, None
def get_course_or_404(self): """ Retrieves the specified course, or raises an Http404 error if it does not exist. Also checks to ensure the user has permissions to view the course """ try: course_id = self.kwargs.get('course_id') course_key = CourseKey.from_string(course_id) course = courses.get_course(course_key) self.check_course_permissions(self.request.user, course_key) return course except ValueError: raise Http404
def _get_default_cohort(course_key): """ Helper method to get a default cohort for assignment in get_cohort """ course = courses.get_course(course_key) cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM) if cohorts: cohort = local_random().choice(cohorts) else: cohort = CourseCohort.create( cohort_name=DEFAULT_COHORT_NAME, course_id=course_key, assignment_type=CourseCohort.RANDOM ).course_user_group return cohort
def get_user_role(user, course_id): """ Return corresponding string if user has staff, instructor or student course role in LMS. """ from courseware.courses import get_course course = get_course(course_id) if is_masquerading_as_student(user): return 'student' elif has_access(user, course, 'instructor'): return 'instructor' elif has_access(user, course, 'staff'): return 'staff' else: return 'student'
def handle(self, *args, **options): if not args: raise CommandError("Course id not specified") if len(args) > 1: raise CommandError("Only one course id may be specifiied") course_id = args[0] course_key = CourseKey.from_string(course_id) course = get_course(course_key) if not course: raise CommandError("Invalid course id: {}".format(course_id)) if course.discussion_link: self.stdout.write(course.discussion_link)
def test_problem_with_no_answer(self): self.course = get_course(CourseKey.from_string('edX/graded/2012_Fall')) problem_location = Location('edX', 'graded', '2012_Fall', 'problem', 'H1P2') self.create_student() StudentModuleFactory.create( course_id=self.course.id, module_state_key=problem_location, student=self.student, grade=0, state=u'{"answer": {"problem_id": "123"}}', ) datarows = list(student_responses(self.course)) self.assertEqual(datarows[0][-1], None)
def _retrieve_course(course_key): """Retrieves the course for the given course key. Args: course_key: The CourseKey for the course we'd like to retrieve. Returns: the course that matches the CourseKey Raises: CourseNotFoundError """ try: return courses.get_course(course_key) except ValueError: raise CourseNotFoundError
def test_get_course_invalid_chars(self): """ Test that `get_course` throws a ValueError, rather than a 404, when faced with unexpected characters (such as unicode characters, and symbols such as = and ' ') """ with self.assertRaises(ValueError): get_course('MITx/foobar/statistics=introduction') get_course('MITx/foobar/business and management') get_course('MITx/foobar/NiñøJoséMaríáßç')
def test_get_course_invalid_chars(self): """ Test that `get_course` throws a ValueError, rather than a 404, when faced with unexpected characters (such as unicode characters, and symbols such as = and ' ') """ with self.assertRaises(ValueError): get_course("MITx/foobar/statistics=introduction") get_course("MITx/foobar/business and management") get_course("MITx/foobar/NiñøJoséMaríáßç")
def get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in(self.course_key).filter(username=username) course = courses.get_course(self.course_key) student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return Response(student_info)
def test_invalid_module_state(self): self.course = get_course(CourseKey.from_string('edX/graded/2012_Fall')) self.problem_location = Location("edX", "graded", "2012_Fall", "problem", "H1P2") self.create_student() StudentModuleFactory.create( course_id=self.course.id, module_state_key=self.problem_location, student=self.student, grade=0, state=u'{"student_answers":{"fake-problem":"No idea"}}}' ) datarows = list(student_responses(self.course)) #Invalid module state response will be skipped, so datarows should be empty self.assertEqual(len(datarows), 0)
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 get_random_cohort(course_key): """ Helper method to get a cohort for random assignment. If there are multiple cohorts of type RANDOM in the course, one of them will be randomly selected. If there are no existing cohorts of type RANDOM in the course, one will be created. """ course = courses.get_course(course_key) cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM) if cohorts: cohort = local_random().choice(cohorts) else: cohort = CourseCohort.create( cohort_name=DEFAULT_COHORT_NAME, course_id=course_key, assignment_type=CourseCohort.RANDOM).course_user_group return cohort
def update_resources(): user = get_user_model().objects.filter(Q(is_staff=True) | Q(is_superuser=True), is_active=True).first() if user is None: log.error( 'The system must have a User is_active=True and staff or superuser' ) return for course_overview in CourseOverview.objects.all(): try: course = get_course(course_overview.id, depth=4) except ValueError: continue try: edflex_client = EdflexOauthClient( get_edflex_configuration_for_org(course.location.org)) except ImproperlyConfigured as er: log.error(er) continue for section in course.get_children(): for subsection in section.get_children(): for unit in subsection.get_children(): for xblock in unit.get_children(): if xblock.location.block_type == 'edflex': resource_id = xblock.resource.get('id') if resource_id: resource = edflex_client.get_resource( resource_id) if resource and xblock.resource != resource: xblock.resource = resource old_xblock_location = xblock.location xblock.location = xblock.location.for_branch( ModuleStoreEnum.BranchName.draft) xblock.save() modulestore().update_item(xblock, user.id, asides=[]) xblock.location = old_xblock_location modulestore().publish( xblock.location, user.id)
def dump_one(self, *args, **options): if not args: raise CommandError("Course id not specified") if len(args) > 2: raise CommandError("Only one course id may be specified") raw_course_key = args[0] if len(args) == 1: output_file_location = self.get_default_file_location(raw_course_key) else: output_file_location = args[1] try: course_key = CourseKey.from_string(raw_course_key) except InvalidKeyError: course_key = SlashSeparatedCourseKey.from_deprecated_string(raw_course_key) course = get_course(course_key) if not course: raise CommandError("Invalid course id: {}".format(course_key)) target_discussion_ids = None if options.get(self.COHORTED_ONLY_PARAMETER, False): cohorted_discussions = get_legacy_discussion_settings(course_key).cohorted_discussions if not cohorted_discussions: raise MissingCohortedConfigCommandError( "Only cohorted discussions are marked for export, " "but no cohorted discussions found for the course") else: target_discussion_ids = cohorted_discussions raw_end_date = options.get(self.END_DATE_PARAMETER, None) end_date = dateutil.parser.parse(raw_end_date) if raw_end_date else None data = Extractor().extract( course_key, end_date=end_date, thread_type=(options.get(self.THREAD_TYPE_PARAMETER, None)), thread_ids=target_discussion_ids, ) filter_str = self._get_filter_string_representation(options) self.stdout.write("Writing social stats ({}) to {}\n".format(filter_str, output_file_location)) with open(output_file_location, 'wb') as output_stream: Exporter(output_stream).export(data)
def get_queryset(self): course_ids = self.request.QUERY_PARAMS.get('course_id', None) results = [] if course_ids: course_ids = course_ids.split(',') for course_id in course_ids: course_key = CourseKey.from_string(course_id) course_descriptor = courses.get_course(course_key) results.append(course_descriptor) else: results = modulestore().get_courses() # Ensure only course descriptors are returned. results = (course for course in results if course.scope_ids.block_type == 'course') # Sort the results in a predictable manner. return sorted(results, key=lambda course: unicode(course.id))
def get_random_cohort(course_key): """ Helper method to get a cohort for random assignment. If there are multiple cohorts of type RANDOM in the course, one of them will be randomly selected. If there are no existing cohorts of type RANDOM in the course, one will be created. """ course = courses.get_course(course_key) cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM) if cohorts: cohort = local_random().choice(cohorts) else: cohort = CourseCohort.create( cohort_name=DEFAULT_COHORT_NAME, course_id=course_key, assignment_type=CourseCohort.RANDOM ).course_user_group return cohort
def send_course_completion_mail(sender, user, course_id, **kwargs): try: course_email = Custom_email.objects.get( course_id=course_id, template_name="completion_mail.template") log.info(u"course_email->%s", course_email) if course_email: connection = get_connection() connection.open() log.info("->-> XX == %s ++ %s ++ %s", user, course_id) userprofile = getuserfullprofile(user.id) email = user.email subject = course_email.subject message = ("Congratulations" + user.username + "you are enrolled in the course") from_addr = "*****@*****.**" course = get_course(course_id) global_email_context = _get_course_email_context(course) email_context = {"name": "", "email": ""} email_context.update(global_email_context) email_context["email"] = email email_context["name"] = userprofile.name email_context["user_id"] = user.id email_context["course_id"] = course_id email_template = course_email.get_template() plaintext_msg = email_template.render_plaintext( course_email.text_message, email_context) log.info(u"plaintext_msg %s", plaintext_msg) html_msg = email_template.render_htmltext( course_email.html_message, email_context) log.info(u"html_msg %s", html_msg) email_msg = EmailMultiAlternatives(subject, plaintext_msg, from_addr, [email], connection=connection) log.info(u"email_msg1->%s", email_msg) email_msg.attach_alternative(html_msg, "text/html") email_msg.send() log.info(u"email_msg2->%s", email_msg) except ObjectDoesNotExist: course_email = "Not set"
def studio_view(self, context): """ Create a fragment used to display the edit view in the Studio. """ if is_course_cohorted(self.course_id): course = courses.get_course(self.course_id) self.cohort_list = get_course_cohorts(course) context.update({"self": self}) fragment = Fragment() fragment.add_content( loader.render_template("static/html/cohortxblock_edit.html", context)) fragment.add_javascript( self.resource_string("static/js/src/cohortxblock_edit.js")) fragment.initialize_js('CohortXBlockEdit') return fragment
def get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in( self.course_key).filter(username=username) course = courses.get_course(self.course_key) student_info = [{ 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students] return Response(student_info)
def generate_user_gradebook(course_key, user): """ Recalculates the specified user's gradebook entry """ with modulestore().bulk_operations(course_key): course_descriptor = get_course(course_key, depth=None) course_grade = CourseGradeFactory().create(user, course_descriptor) grade_summary = course_grade.summary is_passed = course_grade.passed progress_summary = make_courseware_summary(course_grade) grading_policy = course_descriptor.grading_policy grade = grade_summary['percent'] proforma_grade = calculate_proforma_grade(course_grade, grading_policy) progress_summary = get_json_data(progress_summary) grade_summary = get_json_data(grade_summary) grading_policy = get_json_data(grading_policy) gradebook_entry, created = StudentGradebook.objects.get_or_create( user=user, course_id=course_key, defaults={ 'grade': grade, 'proforma_grade': proforma_grade, 'progress_summary': progress_summary, 'grade_summary': grade_summary, 'grading_policy': grading_policy, 'is_passed': is_passed, }) if gradebook_entry.grade != grade or \ gradebook_entry.proforma_grade != proforma_grade or \ gradebook_entry.is_passed != is_passed: gradebook_entry.grade = grade gradebook_entry.proforma_grade = proforma_grade gradebook_entry.progress_summary = progress_summary gradebook_entry.grade_summary = grade_summary gradebook_entry.grading_policy = grading_policy gradebook_entry.is_passed = is_passed gradebook_entry.save() invalid_user_data_cache('grade', course_key, user.id) return gradebook_entry
def get_queryset(self): course_ids = self.request.query_params.get("course_id", None) results = [] if course_ids: course_ids = course_ids.split(",") for course_id in course_ids: course_key = CourseKey.from_string(course_id) course_descriptor = courses.get_course(course_key) results.append(course_descriptor) else: results = modulestore().get_courses() # Ensure only course descriptors are returned. results = (course for course in results if course.scope_ids.block_type == "course") # Ensure only courses accessible by the user are returned. results = (course for course in results if self.user_can_access_course(self.request.user, course)) # Sort the results in a predictable manner. return sorted(results, key=lambda course: unicode(course.id))
def get_queryset(self): course_ids = self.request.QUERY_PARAMS.get('course_id', None) results = [] if course_ids: course_ids = course_ids.split(',') for course_id in course_ids: course_key = CourseKey.from_string(course_id) course_descriptor = courses.get_course(course_key) results.append(course_descriptor) else: results = modulestore().get_courses() # Ensure only course descriptors are returned. results = (course for course in results if course.scope_ids.block_type == 'course') # Ensure only courses accessible by the user are returned. results = (course for course in results if self.user_can_access_course(self.request.user, course)) # Sort the results in a predictable manner. return sorted(results, key=lambda course: unicode(course.id))
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 get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in(self.course_key).filter(username=username) course = courses.get_course(self.course_key) if not enrolled_students: return Response({ "error_description": "User is not enrolled for the course", "error": "invalid_request" }) student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': student_grades(student, request, course), 'realname': student.profile.name, } for student in enrolled_students ] return Response(student_info)
def handle(self, *args, **options): dry_run = options['dry_run'] task_number = options['task_number'] if len(args) == 4: course_id = SlashSeparatedCourseKey.from_deprecated_string(args[0]) location = course_id.make_usage_key_from_deprecated_string(args[1]) students_ids = [line.strip() for line in open(args[2])] hostname = args[3] else: print self.help return try: course = get_course(course_id) except ValueError as err: print err return descriptor = modulestore().get_item(location, depth=0) if descriptor is None: print "Location not found in course" return if dry_run: print "Doing a dry run." students = User.objects.filter( id__in=students_ids).order_by('username') print "Number of students: {0}".format(students.count()) for student in students: post_submission_for_student(student, course, location, task_number, dry_run=dry_run, hostname=hostname)
def get_queryset(self): course_ids = self.request.QUERY_PARAMS.get('course_id', None) course_descriptors = [] if course_ids: course_ids = course_ids.split(',') for course_id in course_ids: course_key = CourseKey.from_string(course_id) course_descriptor = courses.get_course(course_key) course_descriptors.append(course_descriptor) else: course_descriptors = modulestore().get_courses() results = [ course for course in course_descriptors if self.user_can_access_course(self.request.user, course) ] # Sort the results in a predictable manner. results.sort(key=attrgetter('id')) return results
def get(self, request, **kwargs): username = self.kwargs.get('username') enrolled_students = CourseEnrollment.objects.users_enrolled_in( self.course_key).filter(username=username) if not enrolled_students: return Response({ "error_description": "User is not enrolled for the course", "error": "invalid_request" }) course = None grade_summaries = [] for student in enrolled_students: # use cache if have any saved_info = CourseUserResultCache.get_grade_summary(student, self.course_key) if saved_info is not None: grade_summaries.append(saved_info) continue # otherwise get grades elsewhere and save them to cache if course is None: course = courses.get_course(self.course_key) new_info = student_grades(student, course) CourseUserResultCache.save_grade_summary(student, self.course_key, new_info) grade_summaries.append(new_info) student_info = [ { 'username': student.username, 'id': student.id, 'email': student.email, 'grade_summary': grade_summaries[num], 'realname': student.profile.name, } for num, student in enumerate(enrolled_students) ] return Response(student_info)
def get_or_create_course(source, target, user): source_course = get_course_by_id(SlashSeparatedCourseKey.from_deprecated_string(source)) display_name = source_course.display_name org, number, run = target.split('/') course_key = SlashSeparatedCourseKey(org, number, run) fields = {'display_name': display_name} wiki_slug = u"{0}.{1}.{2}".format(course_key.org, course_key.course, course_key.run) definition_data = {'wiki_slug': wiki_slug} fields.update(definition_data) try: if CourseRole.course_group_already_exists(course_key): raise InvalidLocationError() course = modulestore().create_course( course_key.org, course_key.course, course_key.run, user.id, fields=fields, ) except InvalidLocationError: course = get_course(course_key) else: # Make sure user has instructor and staff access to the new course add_instructor(course.id, user, user) # Initialize permissions for user in the new course initialize_permissions(course.id, user) return course