def create_flag(apps, schema_editor): Flag = apps.get_model('waffle', 'Flag') # Replacement for flag_undefined_default=True on flag definition Flag.objects.get_or_create( name=waffle_flags()[REJECTED_EXAM_OVERRIDES_GRADE].name, defaults={'everyone': True}) Flag.objects.get_or_create( name=waffle_flags()[ENFORCE_FREEZE_GRADE_AFTER_COURSE_END].name, defaults={'everyone': True}) Flag.objects.get_or_create(name=waffle_flags()[WRITABLE_GRADEBOOK].name, defaults={'everyone': True})
def setUpClass(cls): super(GradebookViewTest, cls).setUpClass() cls.namespaced_url = 'grades_api:v1:course_gradebook' cls.waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] cls.course = CourseFactory.create(display_name='test-course', run='run-1') cls.course_overview = CourseOverviewFactory.create(id=cls.course.id) # we re-assign cls.course from what's created in the parent class, so we have to # re-create the enrollments, too. cls._create_user_enrollments(cls.course, cls.student, cls.other_student) cls.chapter_1 = ItemFactory.create( category='chapter', parent_location=cls.course.location, display_name="Chapter 1", ) cls.chapter_2 = ItemFactory.create( category='chapter', parent_location=cls.course.location, display_name="Chapter 2", ) cls.subsections = { cls.chapter_1.location: [ ItemFactory.create( category='sequential', parent_location=cls.chapter_1.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='HW 1', format='Homework', graded=True, ), ItemFactory.create( category='sequential', parent_location=cls.chapter_1.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='Lab 1', format='Lab', graded=True, ), ], cls.chapter_2.location: [ ItemFactory.create( category='sequential', parent_location=cls.chapter_2.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='HW 2', format='Homework', graded=True, ), ItemFactory.create( category='sequential', parent_location=cls.chapter_2.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='Lab 2', format='Lab', graded=True, ), ], }
def setUpClass(cls): super(GradebookViewTestBase, cls).setUpClass() cls.namespaced_url = 'grades_api:v1:course_gradebook' cls.waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] cls.course = CourseFactory.create(display_name='test-course', run='run-1') cls.course_key = cls.course.id cls.course_overview = CourseOverviewFactory.create(id=cls.course.id) cls.chapter_1 = ItemFactory.create( category='chapter', parent_location=cls.course.location, display_name="Chapter 1", ) cls.chapter_2 = ItemFactory.create( category='chapter', parent_location=cls.course.location, display_name="Chapter 2", ) cls.subsections = { cls.chapter_1.location: [ ItemFactory.create( category='sequential', parent_location=cls.chapter_1.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='HW 1', format='Homework', graded=True, ), ItemFactory.create( category='sequential', parent_location=cls.chapter_1.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='Lab 1', format='Lab', graded=True, ), ], cls.chapter_2.location: [ ItemFactory.create( category='sequential', parent_location=cls.chapter_2.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='HW 2', format='Homework', graded=True, ), ItemFactory.create( category='sequential', parent_location=cls.chapter_2.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='Lab 2', format='Lab', graded=True, ), ], }
def _section_student_admin(course, access): """ Provide data for the corresponding dashboard section """ course_key = course.id is_small_course = _is_small_course(course_key) section_data = { 'section_key': 'student_admin', 'section_display_name': _('Student Admin'), 'access': access, 'is_small_course': is_small_course, 'get_student_enrollment_status_url': reverse('get_student_enrollment_status', kwargs={'course_id': unicode(course_key)}), 'get_student_progress_url_url': reverse('get_student_progress_url', kwargs={'course_id': unicode(course_key)}), 'enrollment_url': reverse('students_update_enrollment', kwargs={'course_id': unicode(course_key)}), 'reset_student_attempts_url': reverse('reset_student_attempts', kwargs={'course_id': unicode(course_key)}), 'reset_student_attempts_for_entrance_exam_url': reverse( 'reset_student_attempts_for_entrance_exam', kwargs={'course_id': unicode(course_key)}, ), 'rescore_problem_url': reverse('rescore_problem', kwargs={'course_id': unicode(course_key)}), 'override_problem_score_url': reverse('override_problem_score', kwargs={'course_id': unicode(course_key)}), 'rescore_entrance_exam_url': reverse('rescore_entrance_exam', kwargs={'course_id': unicode(course_key)}), 'student_can_skip_entrance_exam_url': reverse( 'mark_student_can_skip_entrance_exam', kwargs={'course_id': unicode(course_key)}, ), 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': unicode(course_key)}), 'list_entrace_exam_instructor_tasks_url': reverse('list_entrance_exam_instructor_tasks', kwargs={'course_id': unicode(course_key)}), 'spoc_gradebook_url': reverse('spoc_gradebook', kwargs={'course_id': unicode(course_key)}), } if waffle_flags()[WRITABLE_GRADEBOOK].is_enabled( course_key) and settings.WRITABLE_GRADEBOOK_URL: section_data['writable_gradebook_url'] = urljoin( settings.WRITABLE_GRADEBOOK_URL, '/' + text_type(course_key)) return section_data
def test_no_gradebook_learner_count_message(self): """ Test that, when the writable gradebook featue IS enabled, there is NOT a message that the feature is only available for courses with small numbers of learners. """ waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] with override_waffle_flag(waffle_flag, active=True): response = self.client.get(self.url) assert TestInstructorDashboard.GRADEBOOK_LEARNER_COUNT_MESSAGE not in response.content.decode('utf-8') self.assertContains(response, 'View Gradebook')
def test_staff_can_see_writable_gradebook(self): """ Test that, when the writable gradebook featue is enabled, a staff member can see it. """ waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] with override_waffle_flag(waffle_flag, active=True): response = self.client.get(self.url) expected_gradebook_url = 'http://gradebook.local.edx.org/{}'.format(self.course.id) self.assertIn(expected_gradebook_url, response.content) self.assertIn('View Gradebook', response.content)
def test_staff_can_see_writable_gradebook_as_subdirectory(self): """ Test that, when the writable gradebook feature is enabled and deployed in a subdirectory, a staff member can see it. """ waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] with override_waffle_flag(waffle_flag, active=True): response = self.client.get(self.url) expected_gradebook_url = f'{settings.WRITABLE_GRADEBOOK_URL}/{self.course.id}' self.assertContains(response, expected_gradebook_url) self.assertContains(response, 'View Gradebook')
def test_staff_can_see_writable_gradebook(self): """ Test that, when the writable gradebook feature is enabled and deployed in another domain, a staff member can see it. """ waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] with override_waffle_flag(waffle_flag, active=True): response = self.client.get(self.url) expected_gradebook_url = f'http://gradebook.local.edx.org/{self.course.id}' self.assertContains(response, expected_gradebook_url) self.assertContains(response, 'View Gradebook')
def wrapped_function(self, request, **kwargs): """ Wraps the given view function. """ course_key = get_course_key(request, kwargs.get('course_id')) if not waffle_flags()[WRITABLE_GRADEBOOK].is_enabled(course_key): raise self.api_error( status_code=status.HTTP_403_FORBIDDEN, developer_message= 'The writable gradebook feature is not enabled for this course.', error_code='feature_not_enabled') return view_func(self, request, **kwargs)
def wrapped_function(self, request, **kwargs): """ Wraps the given view function. """ course_key = get_course_key(request, kwargs.get('course_id')) if not waffle_flags()[WRITABLE_GRADEBOOK].is_enabled(course_key): raise self.api_error( status_code=status.HTTP_403_FORBIDDEN, developer_message='The writable gradebook feature is not enabled for this course.', error_code='feature_not_enabled' ) return view_func(self, request, **kwargs)
def test_no_gradebook_learner_count_message(self): """ Test that, when the writable gradebook featue IS enabled, there is NOT a message that the feature is only available for courses with small numbers of learners. """ waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] with override_waffle_flag(waffle_flag, active=True): response = self.client.get(self.url) self.assertNotIn( TestInstructorDashboard.GRADEBOOK_LEARNER_COUNT_MESSAGE, response.content ) self.assertIn('View Gradebook', response.content)
def writable_gradebook(request, course_id): """ Show the writable gradebook for this course: - Only displayed to course staff """ course_key = CourseKey.from_string(course_id) if not waffle_flags()[WRITABLE_GRADEBOOK].is_enabled(course_key): return HttpResponseNotFound() course = get_course_with_access(request.user, 'load', course_key) course_grade = CourseGradeFactory().read(request.user, course) courseware_summary = course_grade.chapter_grades.values() course_sections = [] for chapter in courseware_summary: chapter_name = chapter['display_name'] for section in chapter['sections']: if section.problem_scores and section.graded and chapter_name not in course_sections: course_sections.append(chapter_name) return render_to_response( 'courseware/writable_gradebook.html', { 'number_of_students': 2, 'course': course, 'course_id': course_key, 'course_sections': course_sections, # Checked above 'staff_access': True, 'ordered_grades': sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True), })
def _section_student_admin(course, access): """ Provide data for the corresponding dashboard section """ course_key = course.id is_small_course = _is_small_course(course_key) section_data = { 'section_key': 'student_admin', 'section_display_name': _('Student Admin'), 'access': access, 'is_small_course': is_small_course, 'get_student_enrollment_status_url': reverse( 'get_student_enrollment_status', kwargs={'course_id': unicode(course_key)} ), 'get_student_progress_url_url': reverse('get_student_progress_url', kwargs={'course_id': unicode(course_key)}), 'enrollment_url': reverse('students_update_enrollment', kwargs={'course_id': unicode(course_key)}), 'reset_student_attempts_url': reverse('reset_student_attempts', kwargs={'course_id': unicode(course_key)}), 'reset_student_attempts_for_entrance_exam_url': reverse( 'reset_student_attempts_for_entrance_exam', kwargs={'course_id': unicode(course_key)}, ), 'rescore_problem_url': reverse('rescore_problem', kwargs={'course_id': unicode(course_key)}), 'override_problem_score_url': reverse('override_problem_score', kwargs={'course_id': unicode(course_key)}), 'rescore_entrance_exam_url': reverse('rescore_entrance_exam', kwargs={'course_id': unicode(course_key)}), 'student_can_skip_entrance_exam_url': reverse( 'mark_student_can_skip_entrance_exam', kwargs={'course_id': unicode(course_key)}, ), 'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': unicode(course_key)}), 'list_entrace_exam_instructor_tasks_url': reverse('list_entrance_exam_instructor_tasks', kwargs={'course_id': unicode(course_key)}), 'spoc_gradebook_url': reverse('spoc_gradebook', kwargs={'course_id': unicode(course_key)}), } if waffle_flags()[WRITABLE_GRADEBOOK].is_enabled(course_key) and settings.WRITABLE_GRADEBOOK_URL: section_data['writable_gradebook_url'] = urljoin(settings.WRITABLE_GRADEBOOK_URL, '/' + text_type(course_key)) return section_data
def setUp(self): super(FreezeGradingAfterCourseEndTest, self).setUp() self.users = [UserFactory.create() for _ in range(12)] self.user = self.users[0] self.freeze_grade_flag = waffle_flags( )[ENFORCE_FREEZE_GRADE_AFTER_COURSE_END]
def setUp(self): super(FreezeGradingAfterCourseEndTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments self.users = [UserFactory.create() for _ in range(12)] self.user = self.users[0] self.freeze_grade_flag = waffle_flags( )[ENFORCE_FREEZE_GRADE_AFTER_COURSE_END]
def setUpClass(cls): super(GradebookViewTestBase, cls).setUpClass() cls.namespaced_url = 'grades_api:v1:course_gradebook' cls.waffle_flag = waffle_flags()[WRITABLE_GRADEBOOK] cls.course = CourseFactory.create(display_name='test-course', run='run-1') cls.course_key = cls.course.id cls.course_overview = CourseOverviewFactory.create(id=cls.course.id) cls.chapter_1 = ItemFactory.create( category='chapter', parent_location=cls.course.location, display_name="Chapter 1", ) cls.chapter_2 = ItemFactory.create( category='chapter', parent_location=cls.course.location, display_name="Chapter 2", ) cls.subsections = { cls.chapter_1.location: [ ItemFactory.create( category='sequential', parent_location=cls.chapter_1.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='HW 1', format='Homework', graded=True, ), ItemFactory.create( category='sequential', parent_location=cls.chapter_1.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='Lab 1', format='Lab', graded=True, ), ], cls.chapter_2.location: [ ItemFactory.create( category='sequential', parent_location=cls.chapter_2.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='HW 2', format='Homework', graded=True, ), ItemFactory.create( category='sequential', parent_location=cls.chapter_2.location, due=datetime(2017, 12, 18, 11, 30, 00), display_name='Lab 2', format='Lab', graded=True, ), ], } cls.course_data = CourseData(None, course=cls.course) # we have to force the collection of course data from the block_structure API # so that CourseGrade.course_data objects can later have a non-null effective_structure _ = cls.course_data.collected_structure
def setUp(self): super(FreezeGradingAfterCourseEndTest, self).setUp() self.users = [UserFactory.create() for _ in xrange(12)] self.user = self.users[0] self.freeze_grade_flag = waffle_flags()[ENFORCE_FREEZE_GRADE_AFTER_COURSE_END]