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)
Exemplo n.º 2
0
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))
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
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))
Exemplo n.º 5
0
    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))
Exemplo n.º 6
0
    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))
Exemplo n.º 7
0
    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)
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
    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)
Exemplo n.º 13
0
    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)
Exemplo n.º 14
0
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
Exemplo n.º 15
0
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))
Exemplo n.º 17
0
 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))
Exemplo n.º 18
0
 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))
Exemplo n.º 19
0
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
Exemplo n.º 20
0
    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)
Exemplo n.º 21
0
    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)
Exemplo n.º 22
0
    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)
Exemplo n.º 23
0
    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)
Exemplo n.º 24
0
 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))
Exemplo n.º 25
0
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