def test_dark_launch_instructor(self): """ Make sure that before course start instructors can access the page for their course. """ instructor_email, instructor_password = self.ACCOUNT_INFO[1] now = datetime.datetime.now(pytz.UTC) tomorrow = now + datetime.timedelta(days=1) course_data = {'start': tomorrow} test_course_data = {'start': tomorrow} self.course = self.update_course(self.course, course_data) self.test_course = self.update_course(self.test_course, test_course_data) # Make the instructor staff in self.course group_name = _course_staff_group_name(self.course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=instructor_email)) self.logout() self.login(instructor_email, instructor_password) # Enroll in the classes---can't see courseware otherwise. self.enroll(self.course, True) self.enroll(self.test_course, True) # should now be able to get to everything for self.course self._check_non_staff_light(self.test_course) self._check_non_staff_dark(self.test_course) self._check_staff(self.course)
def make_instructor(course, user_email): """ Makes a given user an instructor in a course. """ group_name = _course_staff_group_name(course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=user_email))
def test_enrollment_period(self): """ Check that enrollment periods work. """ student_email, student_password = self.ACCOUNT_INFO[0] instructor_email, instructor_password = self.ACCOUNT_INFO[1] # Make courses start in the future now = datetime.datetime.now(pytz.UTC) tomorrow = now + datetime.timedelta(days=1) nextday = tomorrow + datetime.timedelta(days=1) yesterday = now - datetime.timedelta(days=1) course_data = {'enrollment_start': tomorrow, 'enrollment_end': nextday} test_course_data = { 'enrollment_start': yesterday, 'enrollment_end': tomorrow } # self.course's enrollment period hasn't started self.course = self.update_course(self.course, course_data) # test_course course's has self.test_course = self.update_course(self.test_course, test_course_data) # First, try with an enrolled student self.login(student_email, student_password) self.assertFalse(self.enroll(self.course)) self.assertTrue(self.enroll(self.test_course)) # Make the instructor staff in the self.course group_name = _course_staff_group_name(self.course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=instructor_email)) self.logout() self.login(instructor_email, instructor_password) self.assertTrue(self.enroll(self.course)) # now make the instructor global staff, but not in the instructor group group.user_set.remove(User.objects.get(email=instructor_email)) instructor = User.objects.get(email=instructor_email) instructor.is_staff = True instructor.save() # unenroll and try again self.unenroll(self.course) self.assertTrue(self.enroll(self.course))
def _do_test_enrollment_period(self): """Actually do the test, relying on settings to be right.""" # Make courses start in the future tomorrow = datetime.datetime.now(UTC()) + datetime.timedelta(days=1) nextday = tomorrow + datetime.timedelta(days=1) yesterday = datetime.datetime.now(UTC()) - datetime.timedelta(days=1) print "changing" # toy course's enrollment period hasn't started self.toy.enrollment_start = tomorrow self.toy.enrollment_end = nextday # full course's has self.full.enrollment_start = yesterday self.full.enrollment_end = tomorrow print "login" # First, try with an enrolled student print '=== Testing student access....' self.login(self.student, self.password) self.assertFalse(self.try_enroll(self.toy)) self.assertTrue(self.try_enroll(self.full)) print '=== Testing course instructor access....' # Make the instructor staff in the toy course group_name = _course_staff_group_name(self.toy.location) group = Group.objects.create(name=group_name) group.user_set.add(get_user(self.instructor)) print "logout/login" self.logout() self.login(self.instructor, self.password) print "Instructor should be able to enroll in toy course" self.assertTrue(self.try_enroll(self.toy)) print '=== Testing staff access....' # now make the instructor global staff, but not in the instructor group group.user_set.remove(get_user(self.instructor)) instructor = get_user(self.instructor) instructor.is_staff = True instructor.save() # unenroll and try again self.unenroll(self.toy) self.assertTrue(self.try_enroll(self.toy))
def _do_test_enrollment_period(self): """Actually do the test, relying on settings to be right.""" # Make courses start in the future tomorrow = time.time() + 24 * 3600 nextday = tomorrow + 24 * 3600 yesterday = time.time() - 24 * 3600 print "changing" # toy course's enrollment period hasn't started self.toy.enrollment_start = time.gmtime(tomorrow) self.toy.enrollment_end = time.gmtime(nextday) # full course's has self.full.enrollment_start = time.gmtime(yesterday) self.full.enrollment_end = time.gmtime(tomorrow) print "login" # First, try with an enrolled student print '=== Testing student access....' self.login(self.student, self.password) self.assertFalse(self.try_enroll(self.toy)) self.assertTrue(self.try_enroll(self.full)) print '=== Testing course instructor access....' # Make the instructor staff in the toy course group_name = _course_staff_group_name(self.toy.location) group = Group.objects.create(name=group_name) group.user_set.add(get_user(self.instructor)) print "logout/login" self.logout() self.login(self.instructor, self.password) print "Instructor should be able to enroll in toy course" self.assertTrue(self.try_enroll(self.toy)) print '=== Testing staff access....' # now make the instructor global staff, but not in the instructor group group.user_set.remove(get_user(self.instructor)) instructor = get_user(self.instructor) instructor.is_staff = True instructor.save() # unenroll and try again self.unenroll(self.toy) self.assertTrue(self.try_enroll(self.toy))
def test_enrollment_period(self): """ Check that enrollment periods work. """ student_email, student_password = self.ACCOUNT_INFO[0] instructor_email, instructor_password = self.ACCOUNT_INFO[1] # Make courses start in the future now = datetime.datetime.now(pytz.UTC) tomorrow = now + datetime.timedelta(days=1) nextday = tomorrow + datetime.timedelta(days=1) yesterday = now - datetime.timedelta(days=1) course_data = {'enrollment_start': tomorrow, 'enrollment_end': nextday} test_course_data = {'enrollment_start': yesterday, 'enrollment_end': tomorrow} # self.course's enrollment period hasn't started self.course = self.update_course(self.course, course_data) # test_course course's has self.test_course = self.update_course(self.test_course, test_course_data) # First, try with an enrolled student self.login(student_email, student_password) self.assertFalse(self.enroll(self.course)) self.assertTrue(self.enroll(self.test_course)) # Make the instructor staff in the self.course group_name = _course_staff_group_name(self.course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=instructor_email)) self.logout() self.login(instructor_email, instructor_password) self.assertTrue(self.enroll(self.course)) # now make the instructor global staff, but not in the instructor group group.user_set.remove(User.objects.get(email=instructor_email)) instructor = User.objects.get(email=instructor_email) instructor.is_staff = True instructor.save() # unenroll and try again self.unenroll(self.course) self.assertTrue(self.enroll(self.course))
def test_instructor_course_access(self): """ Verify instructor can load the instructor dashboard, the grade views, and student profile pages for their course. """ email, password = self.ACCOUNT_INFO[1] # Make the instructor staff in self.course group_name = _course_staff_group_name(self.course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=email)) self.login(email, password) # Now should be able to get to self.course, but not self.test_course url = reverse('instructor_dashboard', kwargs={'course_id': self.course.id}) check_for_get_code(self, 200, url) url = reverse('instructor_dashboard', kwargs={'course_id': self.test_course.id}) check_for_get_code(self, 404, url)
def setUp(self): xmodule.modulestore.django._MODULESTORES = {} courses = modulestore().get_courses() self.course_id = "edX/toy/2012_Fall" self.toy = modulestore().get_course(self.course_id) # Create two accounts self.student = '*****@*****.**' self.instructor = '*****@*****.**' self.password = '******' self.create_account('u1', self.student, self.password) self.create_account('u2', self.instructor, self.password) self.activate_user(self.student) self.activate_user(self.instructor) group_name = _course_staff_group_name(self.toy.location) g = Group.objects.create(name=group_name) g.user_set.add(User.objects.get(email=self.instructor)) self.logout() self.login(self.instructor, self.password) self.enroll(self.toy)
def setUp(self): clear_existing_modulestores() courses = modulestore().get_courses() self.course_id = "edX/toy/2012_Fall" self.toy = modulestore().get_course(self.course_id) # Create two accounts self.student = '*****@*****.**' self.instructor = '*****@*****.**' self.password = '******' self.create_account('u1', self.student, self.password) self.create_account('u2', self.instructor, self.password) self.activate_user(self.student) self.activate_user(self.instructor) group_name = _course_staff_group_name(self.toy.location) g = Group.objects.create(name=group_name) g.user_set.add(User.objects.get(email=self.instructor)) self.logout() self.login(self.instructor, self.password) self.enroll(self.toy)
def setUp(self): xmodule.modulestore.django._MODULESTORES = {} courses = modulestore().get_courses() self.course_id = "edX/toy/2012_Fall" self.toy = modulestore().get_course(self.course_id) # Create two accounts self.student = '*****@*****.**' self.instructor = '*****@*****.**' self.password = '******' self.create_account('u1', self.student, self.password) self.create_account('u2', self.instructor, self.password) self.activate_user(self.student) self.activate_user(self.instructor) group_name = _course_staff_group_name(self.toy.location) g = Group.objects.create(name=group_name) g.user_set.add(get_user(self.instructor)) self.logout() self.login(self.instructor, self.password) self.enroll(self.toy)
def _get_recipient_queryset(user_id, to_option, course_id, course_location): """ Returns a query set of email recipients corresponding to the requested to_option category. `to_option` is either SEND_TO_MYSELF, SEND_TO_STAFF, or SEND_TO_ALL. Recipients who are in more than one category (e.g. enrolled in the course and are staff or self) will be properly deduped. """ if to_option not in TO_OPTIONS: log.error("Unexpected bulk email TO_OPTION found: %s", to_option) raise Exception("Unexpected bulk email TO_OPTION found: {0}".format(to_option)) if to_option == SEND_TO_MYSELF: recipient_qset = User.objects.filter(id=user_id) else: staff_grpname = _course_staff_group_name(course_location) staff_group, _ = Group.objects.get_or_create(name=staff_grpname) staff_qset = staff_group.user_set.all() instructor_grpname = _course_instructor_group_name(course_location) instructor_group, _ = Group.objects.get_or_create(name=instructor_grpname) instructor_qset = instructor_group.user_set.all() recipient_qset = staff_qset | instructor_qset if to_option == SEND_TO_ALL: # We also require students to have activated their accounts to # provide verification that the provided email address is valid. enrollment_qset = User.objects.filter( is_active=True, courseenrollment__course_id=course_id, courseenrollment__is_active=True ) recipient_qset = recipient_qset | enrollment_qset recipient_qset = recipient_qset.distinct() recipient_qset = recipient_qset.order_by('pk') return recipient_qset
def make_instructor(course): """ Create an instructor for the course. """ group_name = _course_staff_group_name(course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=self.instructor))
def make_instructor(course): group_name = _course_staff_group_name(course.location) g = Group.objects.create(name=group_name) g.user_set.add(get_user(self.instructor))
def delegate_email_batches(email_id, user_id): """ Delegates emails by querying for the list of recipients who should get the mail, chopping up into batches of settings.EMAILS_PER_TASK size, and queueing up worker jobs. Returns the number of batches (workers) kicked off. """ try: email_obj = CourseEmail.objects.get(id=email_id) except CourseEmail.DoesNotExist as exc: # The retry behavior here is necessary because of a race condition between the commit of the transaction # that creates this CourseEmail row and the celery pipeline that starts this task. # We might possibly want to move the blocking into the view function rather than have it in this task. log.warning("Failed to get CourseEmail with id %s, retry %d", email_id, current_task.request.retries) raise delegate_email_batches.retry(arg=[email_id, user_id], exc=exc) to_option = email_obj.to_option course_id = email_obj.course_id try: course = get_course_by_id(course_id, depth=1) except Http404 as exc: log.exception("get_course_by_id failed: %s", exc.args[0]) raise Exception("get_course_by_id failed: " + exc.args[0]) course_url = 'https://{}{}'.format( settings.SITE_NAME, reverse('course_root', kwargs={'course_id': course_id})) image_url = 'https://{}{}'.format(settings.SITE_NAME, course_image_url(course)) if to_option == SEND_TO_MYSELF: recipient_qset = User.objects.filter(id=user_id) elif to_option == SEND_TO_ALL or to_option == SEND_TO_STAFF: staff_grpname = _course_staff_group_name(course.location) staff_group, _ = Group.objects.get_or_create(name=staff_grpname) staff_qset = staff_group.user_set.all() instructor_grpname = _course_instructor_group_name(course.location) instructor_group, _ = Group.objects.get_or_create( name=instructor_grpname) instructor_qset = instructor_group.user_set.all() recipient_qset = staff_qset | instructor_qset if to_option == SEND_TO_ALL: enrollment_qset = User.objects.filter( courseenrollment__course_id=course_id, courseenrollment__is_active=True) recipient_qset = recipient_qset | enrollment_qset recipient_qset = recipient_qset.distinct() else: log.error("Unexpected bulk email TO_OPTION found: %s", to_option) raise Exception( "Unexpected bulk email TO_OPTION found: {0}".format(to_option)) recipient_qset = recipient_qset.order_by('pk') total_num_emails = recipient_qset.count() num_queries = int( math.ceil(float(total_num_emails) / float(settings.EMAILS_PER_QUERY))) last_pk = recipient_qset[0].pk - 1 num_workers = 0 for _ in range(num_queries): recipient_sublist = list( recipient_qset.order_by('pk').filter(pk__gt=last_pk).values( 'profile__name', 'email', 'pk')[:settings.EMAILS_PER_QUERY]) last_pk = recipient_sublist[-1]['pk'] num_emails_this_query = len(recipient_sublist) num_tasks_this_query = int( math.ceil( float(num_emails_this_query) / float(settings.EMAILS_PER_TASK))) chunk = int( math.ceil( float(num_emails_this_query) / float(num_tasks_this_query))) for i in range(num_tasks_this_query): to_list = recipient_sublist[i * chunk:i * chunk + chunk] course_email.delay(email_id, to_list, course.display_name, course_url, image_url, False) num_workers += num_tasks_this_query return num_workers
def _do_test_dark_launch(self): """Actually do the test, relying on settings to be right.""" # Make courses start in the future tomorrow = time.time() + 24 * 3600 self.toy.lms.start = time.gmtime(tomorrow) self.full.lms.start = time.gmtime(tomorrow) self.assertFalse(self.toy.has_started()) self.assertFalse(self.full.has_started()) self.assertFalse(settings.MITX_FEATURES['DISABLE_START_DATES']) def reverse_urls(names, course): """Reverse a list of course urls""" return [ reverse(name, kwargs={'course_id': course.id}) for name in names ] def dark_student_urls(course): """ list of urls that students should be able to see only after launch, but staff should see before """ urls = reverse_urls(['info', 'progress'], course) urls.extend([ reverse('book', kwargs={ 'course_id': course.id, 'book_index': index }) for index, book in enumerate(course.textbooks) ]) return urls def light_student_urls(course): """ list of urls that students should be able to see before launch. """ urls = reverse_urls(['about_course'], course) urls.append(reverse('courses')) return urls def instructor_urls(course): """list of urls that only instructors/staff should be able to see""" urls = reverse_urls( ['instructor_dashboard', 'gradebook', 'grade_summary'], course) return urls def check_non_staff(course): """Check that access is right for non-staff in course""" print '=== Checking non-staff access for {0}'.format(course.id) # Randomly sample a dark url url = random.choice( instructor_urls(course) + dark_student_urls(course) + reverse_urls(['courseware'], course)) print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) # Randomly sample a light url url = random.choice(light_student_urls(course)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) def check_staff(course): """Check that access is right for staff in course""" print '=== Checking staff access for {0}'.format(course.id) # Randomly sample a url url = random.choice( instructor_urls(course) + dark_student_urls(course) + light_student_urls(course)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) # The student progress tab is not accessible to a student # before launch, so the instructor view-as-student feature # should return a 404 as well. # TODO (vshnayder): If this is not the behavior we want, will need # to make access checking smarter and understand both the effective # user (the student), and the requesting user (the prof) url = reverse('student_progress', kwargs={ 'course_id': course.id, 'student_id': get_user(self.student).id }) print 'checking for 404 on view-as-student: {0}'.format(url) self.check_for_get_code(404, url) # The courseware url should redirect, not 200 url = reverse_urls(['courseware'], course)[0] self.check_for_get_code(302, url) # First, try with an enrolled student print '=== Testing student access....' self.login(self.student, self.password) self.enroll(self.toy) self.enroll(self.full) # shouldn't be able to get to anything except the light pages check_non_staff(self.toy) check_non_staff(self.full) print '=== Testing course instructor access....' # Make the instructor staff in the toy course group_name = _course_staff_group_name(self.toy.location) group = Group.objects.create(name=group_name) group.user_set.add(get_user(self.instructor)) self.logout() self.login(self.instructor, self.password) # Enroll in the classes---can't see courseware otherwise. self.enroll(self.toy) self.enroll(self.full) # should now be able to get to everything for toy course check_non_staff(self.full) check_staff(self.toy) print '=== Testing staff access....' # now also make the instructor staff instructor = get_user(self.instructor) instructor.is_staff = True instructor.save() # and now should be able to load both check_staff(self.toy) check_staff(self.full)
def test_instructor_pages(self): """Make sure only instructors for the course or staff can load the instructor dashboard, the grade views, and student profile pages""" # First, try with an enrolled student self.login(self.student, self.password) # shouldn't work before enroll response = self.client.get( reverse('courseware', kwargs={'course_id': self.toy.id})) self.assertRedirectsNoFollow( response, reverse('about_course', args=[self.toy.id])) self.enroll(self.toy) self.enroll(self.full) # should work now -- redirect to first page response = self.client.get( reverse('courseware', kwargs={'course_id': self.toy.id})) self.assertRedirectsNoFollow( response, reverse('courseware_section', kwargs={ 'course_id': self.toy.id, 'chapter': 'Overview', 'section': 'Toy_Videos' })) def instructor_urls(course): "list of urls that only instructors/staff should be able to see" urls = [ reverse(name, kwargs={'course_id': course.id}) for name in ( 'instructor_dashboard', 'gradebook', 'grade_summary', ) ] urls.append( reverse('student_progress', kwargs={ 'course_id': course.id, 'student_id': get_user(self.student).id })) return urls # Randomly sample an instructor page url = random.choice( instructor_urls(self.toy) + instructor_urls(self.full)) # Shouldn't be able to get to the instructor pages print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) # Make the instructor staff in the toy course group_name = _course_staff_group_name(self.toy.location) group = Group.objects.create(name=group_name) group.user_set.add(get_user(self.instructor)) self.logout() self.login(self.instructor, self.password) # Now should be able to get to the toy course, but not the full course url = random.choice(instructor_urls(self.toy)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) url = random.choice(instructor_urls(self.full)) print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) # now also make the instructor staff instructor = get_user(self.instructor) instructor.is_staff = True instructor.save() # and now should be able to load both url = random.choice( instructor_urls(self.toy) + instructor_urls(self.full)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url)
def test_instructor_pages(self): """Make sure only instructors for the course or staff can load the instructor dashboard, the grade views, and student profile pages""" # First, try with an enrolled student self.login(self.student, self.password) # shouldn't work before enroll response = self.client.get(reverse('courseware', kwargs={'course_id': self.toy.id})) self.assertRedirectsNoFollow(response, reverse('about_course', args=[self.toy.id])) self.enroll(self.toy) self.enroll(self.full) # should work now -- redirect to first page response = self.client.get(reverse('courseware', kwargs={'course_id': self.toy.id})) self.assertRedirectsNoFollow(response, reverse('courseware_section', kwargs={'course_id': self.toy.id, 'chapter': 'Overview', 'section': 'Toy_Videos'})) def instructor_urls(course): "list of urls that only instructors/staff should be able to see" urls = [reverse(name, kwargs={'course_id': course.id}) for name in ( 'instructor_dashboard', 'gradebook', 'grade_summary',)] urls.append(reverse('student_progress', kwargs={'course_id': course.id, 'student_id': get_user(self.student).id})) return urls # Randomly sample an instructor page url = random.choice(instructor_urls(self.toy) + instructor_urls(self.full)) # Shouldn't be able to get to the instructor pages print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) # Make the instructor staff in the toy course group_name = _course_staff_group_name(self.toy.location) group = Group.objects.create(name=group_name) group.user_set.add(get_user(self.instructor)) self.logout() self.login(self.instructor, self.password) # Now should be able to get to the toy course, but not the full course url = random.choice(instructor_urls(self.toy)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) url = random.choice(instructor_urls(self.full)) print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) # now also make the instructor staff instructor = get_user(self.instructor) instructor.is_staff = True instructor.save() # and now should be able to load both url = random.choice(instructor_urls(self.toy) + instructor_urls(self.full)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url)
def _do_test_dark_launch(self): """Actually do the test, relying on settings to be right.""" # Make courses start in the future tomorrow = datetime.datetime.now(UTC()) + datetime.timedelta(days=1) self.toy.lms.start = tomorrow self.full.lms.start = tomorrow self.assertFalse(self.toy.has_started()) self.assertFalse(self.full.has_started()) self.assertFalse(settings.MITX_FEATURES['DISABLE_START_DATES']) def reverse_urls(names, course): """Reverse a list of course urls""" return [reverse(name, kwargs={'course_id': course.id}) for name in names] def dark_student_urls(course): """ list of urls that students should be able to see only after launch, but staff should see before """ urls = reverse_urls(['info', 'progress'], course) urls.extend([ reverse('book', kwargs={'course_id': course.id, 'book_index': index}) for index, book in enumerate(course.textbooks) ]) return urls def light_student_urls(course): """ list of urls that students should be able to see before launch. """ urls = reverse_urls(['about_course'], course) urls.append(reverse('courses')) return urls def instructor_urls(course): """list of urls that only instructors/staff should be able to see""" urls = reverse_urls(['instructor_dashboard', 'gradebook', 'grade_summary'], course) return urls def check_non_staff(course): """Check that access is right for non-staff in course""" print '=== Checking non-staff access for {0}'.format(course.id) # Randomly sample a dark url url = random.choice(instructor_urls(course) + dark_student_urls(course) + reverse_urls(['courseware'], course)) print 'checking for 404 on {0}'.format(url) self.check_for_get_code(404, url) # Randomly sample a light url url = random.choice(light_student_urls(course)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) def check_staff(course): """Check that access is right for staff in course""" print '=== Checking staff access for {0}'.format(course.id) # Randomly sample a url url = random.choice(instructor_urls(course) + dark_student_urls(course) + light_student_urls(course)) print 'checking for 200 on {0}'.format(url) self.check_for_get_code(200, url) # The student progress tab is not accessible to a student # before launch, so the instructor view-as-student feature # should return a 404 as well. # TODO (vshnayder): If this is not the behavior we want, will need # to make access checking smarter and understand both the effective # user (the student), and the requesting user (the prof) url = reverse('student_progress', kwargs={'course_id': course.id, 'student_id': get_user(self.student).id}) print 'checking for 404 on view-as-student: {0}'.format(url) self.check_for_get_code(404, url) # The courseware url should redirect, not 200 url = reverse_urls(['courseware'], course)[0] self.check_for_get_code(302, url) # First, try with an enrolled student print '=== Testing student access....' self.login(self.student, self.password) self.enroll(self.toy) self.enroll(self.full) # shouldn't be able to get to anything except the light pages check_non_staff(self.toy) check_non_staff(self.full) print '=== Testing course instructor access....' # Make the instructor staff in the toy course group_name = _course_staff_group_name(self.toy.location) group = Group.objects.create(name=group_name) group.user_set.add(get_user(self.instructor)) self.logout() self.login(self.instructor, self.password) # Enroll in the classes---can't see courseware otherwise. self.enroll(self.toy) self.enroll(self.full) # should now be able to get to everything for toy course check_non_staff(self.full) check_staff(self.toy) print '=== Testing staff access....' # now also make the instructor staff instructor = get_user(self.instructor) instructor.is_staff = True instructor.save() # and now should be able to load both check_staff(self.toy) check_staff(self.full)
def make_instructor(course): group_name = _course_staff_group_name(course.location) group = Group.objects.create(name=group_name) group.user_set.add(User.objects.get(email=self.instructor))
def delegate_email_batches(email_id, user_id): """ Delegates emails by querying for the list of recipients who should get the mail, chopping up into batches of settings.EMAILS_PER_TASK size, and queueing up worker jobs. Returns the number of batches (workers) kicked off. """ try: email_obj = CourseEmail.objects.get(id=email_id) except CourseEmail.DoesNotExist as exc: # The retry behavior here is necessary because of a race condition between the commit of the transaction # that creates this CourseEmail row and the celery pipeline that starts this task. # We might possibly want to move the blocking into the view function rather than have it in this task. log.warning("Failed to get CourseEmail with id %s, retry %d", email_id, current_task.request.retries) raise delegate_email_batches.retry(arg=[email_id, user_id], exc=exc) to_option = email_obj.to_option course_id = email_obj.course_id try: course = get_course_by_id(course_id, depth=1) except Http404 as exc: log.exception("get_course_by_id failed: %s", exc.args[0]) raise Exception("get_course_by_id failed: " + exc.args[0]) course_url = 'https://{}{}'.format( settings.SITE_NAME, reverse('course_root', kwargs={'course_id': course_id}) ) image_url = 'https://{}{}'.format(settings.SITE_NAME, course_image_url(course)) if to_option == SEND_TO_MYSELF: recipient_qset = User.objects.filter(id=user_id) elif to_option == SEND_TO_ALL or to_option == SEND_TO_STAFF: staff_grpname = _course_staff_group_name(course.location) staff_group, _ = Group.objects.get_or_create(name=staff_grpname) staff_qset = staff_group.user_set.all() instructor_grpname = _course_instructor_group_name(course.location) instructor_group, _ = Group.objects.get_or_create(name=instructor_grpname) instructor_qset = instructor_group.user_set.all() recipient_qset = staff_qset | instructor_qset if to_option == SEND_TO_ALL: enrollment_qset = User.objects.filter(courseenrollment__course_id=course_id, courseenrollment__is_active=True) recipient_qset = recipient_qset | enrollment_qset recipient_qset = recipient_qset.distinct() else: log.error("Unexpected bulk email TO_OPTION found: %s", to_option) raise Exception("Unexpected bulk email TO_OPTION found: {0}".format(to_option)) recipient_qset = recipient_qset.order_by('pk') total_num_emails = recipient_qset.count() num_queries = int(math.ceil(float(total_num_emails) / float(settings.EMAILS_PER_QUERY))) last_pk = recipient_qset[0].pk - 1 num_workers = 0 for _ in range(num_queries): recipient_sublist = list(recipient_qset.order_by('pk').filter(pk__gt=last_pk) .values('profile__name', 'email', 'pk')[:settings.EMAILS_PER_QUERY]) last_pk = recipient_sublist[-1]['pk'] num_emails_this_query = len(recipient_sublist) num_tasks_this_query = int(math.ceil(float(num_emails_this_query) / float(settings.EMAILS_PER_TASK))) chunk = int(math.ceil(float(num_emails_this_query) / float(num_tasks_this_query))) for i in range(num_tasks_this_query): to_list = recipient_sublist[i * chunk:i * chunk + chunk] course_email.delay( email_id, to_list, course.display_name, course_url, image_url, False ) num_workers += num_tasks_this_query return num_workers