コード例 #1
0
    def test_remove_user_override(self, initial_date, override_date,
                                  expected_date):
        items = make_items()
        first = items[0]
        block_id = first[0]
        items[0][1]['due'] = initial_date

        api.set_dates_for_course(six.text_type(block_id.course_key), items)

        api.set_date_for_block(block_id.course_key,
                               block_id,
                               'due',
                               override_date,
                               user=self.user)
        DEFAULT_REQUEST_CACHE.clear()
        retrieved = api.get_dates_for_course(block_id.course_key,
                                             user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        assert retrieved[block_id, 'due'] == expected_date

        api.set_date_for_block(block_id.course_key,
                               block_id,
                               'due',
                               None,
                               user=self.user)
        DEFAULT_REQUEST_CACHE.clear()
        retrieved = api.get_dates_for_course(block_id.course_key,
                                             user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        if isinstance(initial_date, timedelta):
            user_initial_date = self.schedule.start_date + initial_date
        else:
            user_initial_date = initial_date
        assert retrieved[block_id, 'due'] == user_initial_date
コード例 #2
0
    def test_set_user_override(self, initial_date, override_date,
                               expected_date):
        items = make_items()
        first = items[0]
        block_id = first[0]
        items[0][1]['due'] = initial_date

        api.set_dates_for_course(str(block_id.course_key), items)

        api.set_date_for_block(block_id.course_key,
                               block_id,
                               'due',
                               override_date,
                               user=self.user)
        DEFAULT_REQUEST_CACHE.clear()
        cache.clear()
        retrieved = api.get_dates_for_course(block_id.course_key,
                                             user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        assert retrieved[block_id, 'due'] == expected_date

        overrides = api.get_overrides_for_block(block_id.course_key, block_id)
        assert len(overrides) == 1
        assert overrides[0][2] == expected_date

        overrides = list(
            api.get_overrides_for_user(block_id.course_key, self.user))
        assert len(overrides) == 1
        assert overrides[0] == {
            'location': block_id,
            'actual_date': expected_date
        }
コード例 #3
0
def set_due_date_extension(course, unit, student, due_date, actor=None):
    """
    Sets a due date extension. Raises DashboardError if the unit or extended
    due date is invalid.
    """
    if due_date:
        try:
            api.set_date_for_block(course.id,
                                   unit.location,
                                   'due',
                                   due_date,
                                   user=student,
                                   reason=None,
                                   actor=actor)
        except api.MissingDateError:
            raise DashboardError(
                _(u"Unit {0} has no due date to extend.").format(
                    unit.location))
        except api.InvalidDateError:
            raise DashboardError(
                _("An extended due date must be later than the original due date."
                  ))
    else:
        api.set_date_for_block(course.id,
                               unit.location,
                               'due',
                               None,
                               user=student,
                               reason=None,
                               actor=actor)
コード例 #4
0
    def test_transform(self, _mock):
        override = datetime.datetime(2020, 1, 1)
        api.set_date_for_block(self.items[0][0].course_key,
                               self.items[0][0],
                               'due',
                               override,
                               user=self.user)
        usage_info = mock.MagicMock()
        usage_info.course_key = self.course_id
        block_structure = mock.MagicMock()
        transformer = field_data.DateOverrideTransformer(self.user)
        transformer.transform(usage_info, block_structure)
        assert block_structure.override_xblock_field.call_count == NUM_OVERRIDES
        args = block_structure.override_xblock_field.call_args_list
        for arg in args:
            call_args = arg[0]
            if call_args[0] == self.items[0][0]:
                assert call_args[2] == override

        # now make it raise exceptions
        # attributeerror is swallowed
        # in the case where a block does not exist for some reason
        block_structure.override_xblock_field.side_effect = AttributeError()
        transformer.transform(usage_info, block_structure)
        # other exceptions should bubble up
        block_structure.override_xblock_field.side_effect = ValueError()
        with self.assertRaises(ValueError):
            transformer.transform(usage_info, block_structure)
コード例 #5
0
    def test_hidden_content_with_transformer_override(self):
        """
        Tests content is hidden if the date changes after collection and
        during the transform phase (for example, by the DateOverrideTransformer).
        """
        with mock_registered_transformers(
            [DateOverrideTransformer, self.TRANSFORMER_CLASS_TO_TEST]):
            transformers = BlockStructureTransformers([
                DateOverrideTransformer(self.student),
                self.TRANSFORMER_CLASS_TO_TEST()
            ])

        block = self.get_block(1)
        block.hide_after_due = True
        update_block(block)
        set_date_for_block(self.course.id, block.location, 'due',
                           self.DueDateType.PAST_DATE)

        # Due date is in the past so some blocks are hidden
        self.assert_transform_results(
            self.student,
            self.ALL_BLOCKS - {1, 3, 4},
            blocks_with_differing_access=None,
            transformers=transformers,
        )

        # Set an override for the due date to be in the future
        set_date_for_block(self.course.id,
                           block.location,
                           'due',
                           self.DueDateType.FUTURE_DATE,
                           user=self.student)
        # this line is just to bust the cache for the user so it returns the updated date.
        get_dates_for_course(self.course.id,
                             user=self.student,
                             use_cached=False)

        # Now all blocks are returned for the student
        self.assert_transform_results(
            self.student,
            self.ALL_BLOCKS,
            blocks_with_differing_access=None,
            transformers=transformers,
        )

        # But not for a different user
        different_user = UserFactory()
        with mock_registered_transformers(
            [DateOverrideTransformer, self.TRANSFORMER_CLASS_TO_TEST]):
            transformers = BlockStructureTransformers([
                DateOverrideTransformer(different_user),
                self.TRANSFORMER_CLASS_TO_TEST()
            ])
        self.assert_transform_results(
            different_user,
            self.ALL_BLOCKS - {1, 3, 4},
            blocks_with_differing_access=None,
            transformers=transformers,
        )
コード例 #6
0
ファイル: test_api.py プロジェクト: edx/edx-when
    def test_set_user_override_invalid_date(self, initial_date, override_date):
        items = make_items()
        first = items[0]
        block_id = first[0]
        items[0][1]['due'] = initial_date
        api.set_dates_for_course(str(block_id.course_key), items)

        with self.assertRaises(api.InvalidDateError):
            api.set_date_for_block(block_id.course_key, block_id, 'due', override_date, user=self.user)
コード例 #7
0
ファイル: test_api.py プロジェクト: edx/edx-when
    def test_set_user_override_invalid_block(self):
        items = make_items()
        first = items[0]
        block_id = first[0]
        api.set_dates_for_course(str(block_id.course_key), items)

        with self.assertRaises(api.MissingDateError):
            # can't set a user override for content without a date
            bad_block_id = make_block_id()
            api.set_date_for_block(bad_block_id.course_key, bad_block_id, 'due', datetime(2019, 4, 6), user=self.user)
コード例 #8
0
ファイル: test_api.py プロジェクト: edx/edx-when
 def test_get_schedules_with_due_date_for_abs_date(self):
     self.schedule.start_date = datetime(2019, 3, 22)
     items = make_items(with_relative=False)
     assignment_date = items[0][1].get('due')
     api.set_date_for_block(items[0][0].course_key, items[0][0], 'due', assignment_date)
     # Specify the actual assignment due date so this will return true
     schedules = api.get_schedules_with_due_date(items[0][0].course_key, datetime.date(assignment_date))
     assert len(schedules) > 0
     for schedule in schedules:
         assert schedule.enrollment.course_id == items[0][0].course_key
         assert schedule.enrollment.user.id == self.user.id
コード例 #9
0
ファイル: test_api.py プロジェクト: edx/edx-when
    def test_set_date_for_block_query_counts(self):
        args = (self.course.id, make_block_id(self.course.id), 'due', datetime(2019, 3, 22))

        # Each date we make has:
        #  1 get & 1 create for the date itself
        #  1 get & 1 create for the sub-policy
        with self.assertNumQueries(4):
            api.set_date_for_block(*args)

        # When setting same items, we should only do initial read
        with self.assertNumQueries(1):
            api.set_date_for_block(*args)
コード例 #10
0
ファイル: test_api.py プロジェクト: edx/edx-when
    def test_set_date_for_block(self, initial_date, override_date, expected_date):
        items = make_items()
        first = items[0]
        block_id = first[0]
        items[0][1]['due'] = initial_date

        api.set_dates_for_course(str(block_id.course_key), items)
        api.set_date_for_block(block_id.course_key, block_id, 'due', override_date)
        TieredCache.dangerous_clear_all_tiers()
        retrieved = api.get_dates_for_course(block_id.course_key, user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        assert retrieved[block_id, 'due'] == expected_date
コード例 #11
0
ファイル: tools.py プロジェクト: digitalsatori/edx-platform
def set_due_date_extension(course, unit, student, due_date, actor=None, reason=''):
    """
    Sets a due date extension. Raises DashboardError if the unit or extended
    due date is invalid.
    """
    if due_date:
        try:
            api.set_date_for_block(course.id, unit.location, 'due', due_date, user=student, reason=reason, actor=actor)
        except api.MissingDateError:
            raise DashboardError(_(u"Unit {0} has no due date to extend.").format(unit.location))
        except api.InvalidDateError:
            raise DashboardError(_("An extended due date must be later than the original due date."))
    else:
        api.set_date_for_block(course.id, unit.location, 'due', None, user=student, reason=reason, actor=actor)
コード例 #12
0
ファイル: test_api.py プロジェクト: edx/edx-when
    def test_get_user_date_no_schedule(self):
        items = make_items()
        course_key = items[0][0].course_key
        api.set_dates_for_course(course_key, items)
        before_override = api.get_dates_for_course(course_key, user=self.user)
        assert len(before_override) == 3

        # Override a date for the user with a relative date, but remove the schedule
        # so that the override can't be applied
        api.set_date_for_block(course_key, items[0][0], 'due', timedelta(days=2), user=self.user)
        self.schedule.delete()

        after_override = api.get_dates_for_course(course_key, user=self.user, use_cached=False)
        assert before_override == after_override
コード例 #13
0
ファイル: test_api.py プロジェクト: edx/edx-when
 def test_get_schedules_with_due_date_for_rel_date(self):
     items = make_items(with_relative=False)
     api.set_dates_for_course(items[0][0].course_key, items)
     relative_date = timedelta(days=2)
     api.set_date_for_block(items[0][0].course_key, items[0][0], 'due', relative_date)
     assignment_date = items[0][1].get('due') + relative_date
     # Move the schedule's start to the first assignment's original due since it's now offset
     self.schedule.start_date = items[0][1].get('due')
     self.schedule.save()
     # Specify the actual assignment due date so this will return true
     schedules = api.get_schedules_with_due_date(items[0][0].course_key, assignment_date.date())
     assert len(schedules) > 0
     for schedule in schedules:
         assert schedule.enrollment.course_id == items[0][0].course_key
         assert schedule.enrollment.user.id == self.user.id
コード例 #14
0
ファイル: test_api.py プロジェクト: edx/edx-when
 def test_get_schedules_with_due_date_for_abs_user_dates(self):
     items = make_items(with_relative=True)
     api.set_dates_for_course(items[0][0].course_key, items)
     assignment_date = items[0][1].get('due')
     api.set_date_for_block(items[0][0].course_key, items[0][0], 'due', assignment_date, user=self.user)
     models.UserDate.objects.create(
         abs_date=assignment_date,
         user=self.user,
         content_date=models.ContentDate.objects.first(),
     )
     # Specify the actual assignment due date so this will return true
     schedules = api.get_schedules_with_due_date(items[0][0].course_key, assignment_date.date())
     assert len(schedules) == 1  # Make sure there's only one schedule, we should not have duplicates
     assert schedules[0].enrollment.course_id == items[0][0].course_key
     assert schedules[0].enrollment.user.id == self.user.id
コード例 #15
0
def move_overrides_to_edx_when(apps, schema_editor):
    from xmodule.fields import Date
    from edx_when import api
    date_field = Date()
    StudentFieldOverride = apps.get_model('courseware', 'StudentFieldOverride')
    log = logging.getLogger(__name__)
    for override in StudentFieldOverride.objects.filter(field='due'):
        try:
            abs_date = date_field.from_json(json.loads(override.value))
            api.set_date_for_block(
                override.course_id,
                override.location,
                'due',
                abs_date,
                user=override.student)
        except Exception:  # pylint: disable=broad-except
            log.exception("migrating %d %r: %r", override.id, override.location, override.value)
コード例 #16
0
def move_overrides_to_edx_when(apps, schema_editor):
    from xmodule.fields import Date
    from edx_when import api
    date_field = Date()
    StudentFieldOverride = apps.get_model('courseware', 'StudentFieldOverride')
    log = logging.getLogger(__name__)
    for override in StudentFieldOverride.objects.filter(field='due'):
        try:
            abs_date = date_field.from_json(json.loads(override.value))
            api.set_date_for_block(
                override.course_id,
                override.location,
                'due',
                abs_date,
                user=override.student)
        except Exception:  # pylint: disable=broad-except
            log.exception("migrating %d %r: %r", override.id, override.location, override.value)
コード例 #17
0
    def test_set_date_for_block(self, initial_date, override_date,
                                expected_date):
        items = make_items()
        first = items[0]
        block_id = first[0]
        items[0][1]['due'] = initial_date

        api.set_dates_for_course(str(block_id.course_key), items)

        api.set_date_for_block(block_id.course_key, block_id, 'due',
                               override_date)
        DEFAULT_REQUEST_CACHE.clear()
        cache.clear()
        retrieved = api.get_dates_for_course(block_id.course_key,
                                             user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        assert retrieved[block_id, 'due'] == expected_date
コード例 #18
0
def set_due_date_extension(course, unit, student, due_date, actor=None, reason=''):
    """
    Sets a due date extension.

    Raises:
        DashboardError if the unit or extended, due date is invalid or user is
        not enrolled in the course.
    """
    mode, __ = CourseEnrollment.enrollment_mode_for_user(user=student, course_id=six.text_type(course.id))
    if not mode:
        raise DashboardError(_("Could not find student enrollment in the course."))

    if due_date:
        try:
            api.set_date_for_block(course.id, unit.location, 'due', due_date, user=student, reason=reason, actor=actor)
        except api.MissingDateError:
            raise DashboardError(_(u"Unit {0} has no due date to extend.").format(unit.location))
        except api.InvalidDateError:
            raise DashboardError(_("An extended due date must be later than the original due date."))
    else:
        api.set_date_for_block(course.id, unit.location, 'due', None, user=student, reason=reason, actor=actor)
コード例 #19
0
ファイル: test_api.py プロジェクト: edx/edx-when
    def test_remove_user_override(self, initial_date, override_date, expected_date):
        items = make_items()
        first = items[0]
        block_id = first[0]
        items[0][1]['due'] = initial_date

        api.set_dates_for_course(str(block_id.course_key), items)

        api.set_date_for_block(block_id.course_key, block_id, 'due', override_date, user=self.user)
        TieredCache.dangerous_clear_all_tiers()
        retrieved = api.get_dates_for_course(block_id.course_key, user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        assert retrieved[block_id, 'due'] == expected_date

        api.set_date_for_block(block_id.course_key, block_id, 'due', None, user=self.user)
        TieredCache.dangerous_clear_all_tiers()
        retrieved = api.get_dates_for_course(block_id.course_key, user=self.user.id)
        assert len(retrieved) == NUM_OVERRIDES
        if isinstance(initial_date, timedelta):
            user_initial_date = self.schedule.start_date + initial_date
        else:
            user_initial_date = initial_date
        assert retrieved[block_id, 'due'] == user_initial_date
コード例 #20
0
def set_due_date_extension(course,
                           unit,
                           student,
                           due_date,
                           actor=None,
                           reason=''):
    """
    Sets a due date extension.

    Raises:
        DashboardError if the unit or extended, due date is invalid or user is
        not enrolled in the course.
    """
    mode, __ = CourseEnrollment.enrollment_mode_for_user(
        user=student, course_id=six.text_type(course.id))
    if not mode:
        raise DashboardError(
            _("Could not find student enrollment in the course."))

    # We normally set dates at the subsection level. But technically dates can be anywhere down the tree (and
    # usually are in self paced courses, where the subsection date gets propagated down).
    # So find all children that we need to set the date on, then set those dates.
    course_dates = api.get_dates_for_course(course.id, user=student)
    blocks_to_set = {
        unit
    }  # always include the requested unit, even if it doesn't appear to have a due date now

    def visit(node):
        """
        Visit a node.  Checks to see if node has a due date and appends to
        `blocks_to_set` if it does.  And recurses into children to search for
        nodes with due dates.
        """
        if (node.location, 'due') in course_dates:
            blocks_to_set.add(node)
        for child in node.get_children():
            visit(child)

    visit(unit)

    for block in blocks_to_set:
        if due_date:
            try:
                api.set_date_for_block(course.id,
                                       block.location,
                                       'due',
                                       due_date,
                                       user=student,
                                       reason=reason,
                                       actor=actor)
            except api.MissingDateError:
                raise DashboardError(
                    _(u"Unit {0} has no due date to extend.").format(
                        unit.location))
            except api.InvalidDateError:
                raise DashboardError(
                    _("An extended due date must be later than the original due date."
                      ))
        else:
            api.set_date_for_block(course.id,
                                   block.location,
                                   'due',
                                   None,
                                   user=student,
                                   reason=reason,
                                   actor=actor)
コード例 #21
0
    def test_allow_relative_dates(self):
        course_key = CourseLocator('testX', 'tt101', '2019')
        block1 = make_block_id(course_key)
        date1 = datetime(2019, 3, 22)
        block2 = make_block_id(course_key)
        date2 = datetime(2019, 3, 23)
        date2_override_delta = timedelta(days=10)
        date2_override = date2 + date2_override_delta
        block3 = make_block_id(course_key)
        date3_delta = timedelta(days=1)
        date3 = self.schedule.start_date + date3_delta
        block4 = make_block_id(course_key)
        date4_delta = timedelta(days=2)
        date4 = self.schedule.start_date + date4_delta
        date4_override = datetime(2019, 4, 24)
        items = [
            (block1, {
                'due': date1
            }),  # absolute
            (block2, {
                'due': date2
            }),  # absolute, to be overwritten by relative date
            (block3, {
                'due': date3_delta
            }),  # relative
            (block4, {
                'due': date4_delta
            }),  # relative, to be overwritten by absolute date
        ]
        api.set_dates_for_course(course_key, items)
        api.set_date_for_block(course_key,
                               block2,
                               'due',
                               date2_override_delta,
                               user=self.user)
        api.set_date_for_block(course_key,
                               block4,
                               'due',
                               date4_override,
                               user=self.user)

        # get_dates_for_course
        dates = [
            ((block1, 'due'), date1),
            ((block2, 'due'), date2),
            ((block3, 'due'), date3),
            ((block4, 'due'), date4),
        ]
        user_dates = [
            ((block1, 'due'), date1),
            ((block2, 'due'), date2_override),
        ]
        assert api.get_dates_for_course(course_key,
                                        schedule=self.schedule) == dict(dates)
        with patch('edx_when.api._are_relative_dates_enabled',
                   return_value=False):
            assert api.get_dates_for_course(
                course_key, schedule=self.schedule) == dict(dates[0:2])
            assert api.get_dates_for_course(course_key,
                                            schedule=self.schedule,
                                            user=self.user) == dict(user_dates)

        # get_date_for_block
        assert api.get_date_for_block(course_key, block2) == date2
        assert api.get_date_for_block(course_key, block4,
                                      user=self.user) == date4_override
        with patch('edx_when.api._are_relative_dates_enabled',
                   return_value=False):
            assert api.get_date_for_block(course_key, block2) == date2
            assert api.get_date_for_block(course_key, block1,
                                          user=self.user) == date1
            assert api.get_date_for_block(course_key, block2,
                                          user=self.user) == date2_override
            assert api.get_date_for_block(course_key, block4,
                                          user=self.user) is None

        # get_overrides_for_block
        block2_overrides = [(self.user.username, 'unknown', date2_override)]
        assert api.get_overrides_for_block(course_key,
                                           block2) == block2_overrides
        with patch('edx_when.api._are_relative_dates_enabled',
                   return_value=False):
            assert api.get_overrides_for_block(course_key, block2) == [
                (self.user.username, 'unknown', date2_override)
            ]

        # get_overrides_for_user
        user_overrides = [
            {
                'location': block4,
                'actual_date': date4_override
            },
            {
                'location': block2,
                'actual_date': date2_override
            },
        ]
        assert list(api.get_overrides_for_user(course_key,
                                               self.user)) == user_overrides
        with patch('edx_when.api._are_relative_dates_enabled',
                   return_value=False):
            assert list(api.get_overrides_for_user(
                course_key, self.user)) == user_overrides