예제 #1
0
 def test_setting_override(self, is_enabled, override_choice, expected_result):
     RequestCache.clear_request_cache()
     self.set_waffle_course_override(override_choice, is_enabled)
     override_value = WaffleFlagCourseOverrideModel.override_value(
         self.WAFFLE_TEST_NAME, self.TEST_COURSE_KEY
     )
     self.assertEqual(override_value, expected_result)
예제 #2
0
    def test_grades_csv(self):
        self.course.enable_ccx = True
        RequestCache.clear_request_cache()

        url = reverse(
            'ccx_grades_csv',
            kwargs={'course_id': self.ccx_key}
        )
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        # Are the grades downloaded as an attachment?
        self.assertEqual(
            response['content-disposition'],
            'attachment'
        )
        rows = response.content.strip().split('\r')
        headers = rows[0]

        # picking first student records
        data = dict(zip(headers.strip().split(','), rows[1].strip().split(',')))
        self.assertNotIn('HW 04', data)
        self.assertEqual(data['HW 01'], '0.75')
        self.assertEqual(data['HW 02'], '0.5')
        self.assertEqual(data['HW 03'], '0.25')
        self.assertEqual(data['HW Avg'], '0.5')
    def instrument_course_progress_render(self, course_width, enable_ccx, queries, reads, xblocks):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        self.setup_course(course_width, enable_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                get_cache(cache).clear()

            # Refill the metadata inheritance cache
            modulestore().get_course(self.course.id, depth=None)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_request_cache()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(queries):
                with check_mongo_calls(reads):
                    with check_sum_of_calls(XBlock, ['__init__'], xblocks, xblocks, include_arguments=False):
                        self.grade_course(self.course)
예제 #4
0
    def test_get_template_path(self):
        """
        Tests to make sure the get_template_path function works as expected.
        """
        # if the current site has associated SiteTheme then get_template_path should return the argument as is.
        with patch(
            "openedx.core.djangoapps.theming.helpers.current_request_has_associated_site_theme",
            Mock(return_value=True),
        ):
            with patch(
                "openedx.core.djangoapps.theming.helpers.microsite.is_request_in_microsite",
                Mock(return_value=True),
            ):
                with patch("microsite_configuration.microsite.TEMPLATES_BACKEND") as mock_microsite_backend:
                    mock_microsite_backend.get_template = Mock(return_value="/microsite/about.html")
                    self.assertEqual(theming_helpers.get_template_path("about.html"), "about.html")

        RequestCache.clear_request_cache()

        # if the current site does not have associated SiteTheme then get_template_path should return microsite override
        with patch(
            "openedx.core.djangoapps.theming.helpers.current_request_has_associated_site_theme",
            Mock(return_value=False),
        ):
            with patch(
                "openedx.core.djangoapps.theming.helpers.microsite.is_request_in_microsite",
                Mock(return_value=True),
            ):
                with patch("microsite_configuration.microsite.TEMPLATES_BACKEND") as mock_microsite_backend:
                    mock_microsite_backend.get_template_path = Mock(return_value="/microsite/about.html")
                    self.assertEqual(theming_helpers.get_template_path("about.html"), "/microsite/about.html")
예제 #5
0
    def test_request_cached_with_caches_despite_changing_wrapped_result(self):
        """
        Ensure that after caching a result, we always send it back, even if the underlying result changes.
        """
        RequestCache.clear_request_cache()

        to_be_wrapped = Mock()
        to_be_wrapped.side_effect = [1, 2, 3]
        self.assertEqual(to_be_wrapped.call_count, 0)

        def mock_wrapper(*args, **kwargs):
            """Simple wrapper to let us decorate our mock."""
            return to_be_wrapped(*args, **kwargs)

        wrapped = request_cached(mock_wrapper)
        result = wrapped()
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 1)

        result = wrapped()
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 1)

        direct_result = mock_wrapper()
        self.assertEqual(direct_result, 2)
        self.assertEqual(to_be_wrapped.call_count, 2)

        result = wrapped()
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 2)

        direct_result = mock_wrapper()
        self.assertEqual(direct_result, 3)
        self.assertEqual(to_be_wrapped.call_count, 3)
    def instrument_course_progress_render(
            self, course_width, enable_ccx, view_as_ccx,
            sql_queries, mongo_reads,
    ):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        course_key = self.setup_course(course_width, enable_ccx, view_as_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                caches[cache].clear()

            # Refill the metadata inheritance cache
            get_course_in_cache(course_key)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_request_cache()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(sql_queries, using='default'):
                with self.assertNumQueries(0, using='student_module_history'):
                    with self.assertMongoCallCount(mongo_reads):
                        with self.assertXBlockInstantiations(1):
                            self.grade_course(course_key)
예제 #7
0
    def test_grades_csv(self):
        self.course.enable_ccx = True
        RequestCache.clear_request_cache()

        url = reverse(
            'ccx_grades_csv',
            kwargs={'course_id': self.ccx_key}
        )
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        # Are the grades downloaded as an attachment?
        self.assertEqual(
            response['content-disposition'],
            'attachment'
        )
        rows = response.content.strip().split('\r')
        headers = rows[0]

        records = dict()
        for i in range(1, len(rows)):
            data = dict(zip(headers.strip().split(','), rows[i].strip().split(',')))
            records[data['username']] = data

        student_data = records[self.student.username]  # pylint: disable=no-member

        self.assertNotIn('HW 04', student_data)
        self.assertEqual(student_data['HW 01'], '0.75')
        self.assertEqual(student_data['HW 02'], '0.5')
        self.assertEqual(student_data['HW 03'], '0.25')
        self.assertEqual(student_data['HW Avg'], '0.5')
예제 #8
0
    def test_undefined_waffle_flag(self, data):
        """
        Test flag with various defaults provided for undefined waffle flags.
        """
        RequestCache.clear_request_cache()

        test_course_flag = CourseWaffleFlag(
            self.TEST_NAMESPACE,
            self.FLAG_NAME,
            flag_undefined_default=data['flag_undefined_default']
        )

        with patch.object(
            WaffleFlagCourseOverrideModel,
            'override_value',
            return_value=WaffleFlagCourseOverrideModel.ALL_CHOICES.unset
        ):
            # check twice to test that the result is properly cached
            self.assertEqual(test_course_flag.is_enabled(self.TEST_COURSE_KEY), data['result'])
            self.assertEqual(test_course_flag.is_enabled(self.TEST_COURSE_KEY), data['result'])
            # result is cached, so override check should happen once
            WaffleFlagCourseOverrideModel.override_value.assert_called_once_with(
                self.NAMESPACED_FLAG_NAME,
                self.TEST_COURSE_KEY
            )
예제 #9
0
    def test_course_waffle_flag(self, data):
        """
        Tests various combinations of a flag being set in waffle and overridden
        for a course.
        """
        RequestCache.clear_request_cache()

        with patch.object(WaffleFlagCourseOverrideModel, 'override_value', return_value=data['course_override']):
            with override_flag(self.NAMESPACED_FLAG_NAME, active=data['waffle_enabled']):
                # check twice to test that the result is properly cached
                self.assertEqual(self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_KEY), data['result'])
                self.assertEqual(self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_KEY), data['result'])
                # result is cached, so override check should happen once
                WaffleFlagCourseOverrideModel.override_value.assert_called_once_with(
                    self.NAMESPACED_FLAG_NAME,
                    self.TEST_COURSE_KEY
                )

        # check flag for a second course
        if data['course_override'] == WaffleFlagCourseOverrideModel.ALL_CHOICES.unset:
            # When course override wasn't set for the first course, the second course will get the same
            # cached value from waffle.
            self.assertEqual(self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_2_KEY), data['waffle_enabled'])
        else:
            # When course override was set for the first course, it should not apply to the second
            # course which should get the default value of False.
            self.assertEqual(self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_2_KEY), False)
예제 #10
0
 def test_setting_override_multiple_times(self):
     RequestCache.clear_request_cache()
     self.set_waffle_course_override(self.OVERRIDE_CHOICES.on)
     self.set_waffle_course_override(self.OVERRIDE_CHOICES.off)
     override_value = WaffleFlagCourseOverrideModel.override_value(
         self.WAFFLE_TEST_NAME, self.TEST_COURSE_KEY
     )
     self.assertEqual(override_value, self.OVERRIDE_CHOICES.off)
예제 #11
0
    def handle(self, *args, **options):  # pylint: disable=unused-argument
        """
        Iterates through each course, serializes them into graphs, and saves
        those graphs to neo4j.
        """
        # first, make sure that there's a valid neo4j configuration
        if settings.NEO4J_CONFIG is None:
            raise CommandError(
                "No neo4j configuration (NEO4J_CONFIG) defined in lms.auth.json."
            )

        auth_params = ["{host}:{https_port}", "{user}", "{password}"]
        authenticate(*[param.format(**settings.NEO4J_CONFIG) for param in auth_params])

        graph = Graph(**settings.NEO4J_CONFIG)

        mss = ModuleStoreSerializer()

        total_number_of_courses = len(mss.all_courses)

        for index, course in enumerate(mss.all_courses):
            # first, clear the request cache to prevent memory leaks
            RequestCache.clear_request_cache()

            log.info(
                "Now exporting %s to neo4j: course %d of %d total courses",
                course.id,
                index + 1,
                total_number_of_courses
            )
            nodes, relationships = mss.serialize_course(course.id)
            log.info(
                "%d nodes and %d relationships in %s",
                len(nodes),
                len(relationships),
                course.id
            )

            transaction = graph.begin()
            try:
                # first, delete existing course
                transaction.run(
                    "MATCH (n:item) WHERE n.course_key='{}' DETACH DELETE n".format(
                        six.text_type(course.id)
                    )
                )

                # now, re-add it
                self.add_to_transaction(nodes, transaction)
                self.add_to_transaction(relationships, transaction)
                transaction.commit()

            except Exception:  # pylint: disable=broad-except
                log.exception(
                    "Error trying to dump course %s to neo4j, rolling back",
                    six.text_type(course.id)
                )
                transaction.rollback()
예제 #12
0
def lti_consumer_fields_editing_flag(course_id, enabled_for_course=False):
    """
    Yields CourseEditLTIFieldsEnabledFlag record for unit tests

    Arguments:
        course_id (CourseLocator): course locator to control this feature for.
        enabled_for_course (bool): whether feature is enabled for 'course_id'
    """
    RequestCache.clear_request_cache()
    CourseEditLTIFieldsEnabledFlag.objects.create(course_id=course_id, enabled=enabled_for_course)
    yield
예제 #13
0
    def assert_access_to_gated_content(self, user, expected_access):
        """
        Verifies access to gated content for the given user is as expected.
        """
        # clear the request cache to flush any cached access results
        RequestCache.clear_request_cache()

        # access to gating content (seq1) remains constant
        self.assertTrue(bool(has_access(user, 'load', self.seq1, self.course.id)))

        # access to gated content (seq2) is as expected
        self.assertEquals(bool(has_access(user, 'load', self.seq2, self.course.id)), expected_access)
예제 #14
0
    def test_gradebook(self):
        self.course.enable_ccx = True
        RequestCache.clear_request_cache()

        url = reverse("ccx_gradebook", kwargs={"course_id": self.ccx_key})
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        # Max number of student per page is one.  Patched setting MAX_STUDENTS_PER_PAGE_GRADE_BOOK = 1
        self.assertEqual(len(response.mako_context["students"]), 1)  # pylint: disable=no-member
        student_info = response.mako_context["students"][0]  # pylint: disable=no-member
        self.assertEqual(student_info["grade_summary"]["percent"], 0.5)
        self.assertEqual(student_info["grade_summary"]["grade_breakdown"][0]["percent"], 0.5)
        self.assertEqual(len(student_info["grade_summary"]["section_breakdown"]), 4)
예제 #15
0
def persistent_grades_feature_flags(
        global_flag,
        enabled_for_all_courses=False,
        course_id=None,
        enabled_for_course=False
):
    """
    Most test cases will use a single call to this manager,
    as they need to set the global setting and the course-specific
    setting for a single course.
    """
    RequestCache.clear_request_cache()
    PersistentGradesEnabledFlag.objects.create(enabled=global_flag, enabled_for_all_courses=enabled_for_all_courses)
    if course_id:
        CoursePersistentGradesFlag.objects.create(course_id=course_id, enabled=enabled_for_course)
    yield
예제 #16
0
 def link_func(self):
     """
     Returns a function that computes the URL for this tab.
     """
     request = RequestCache.get_current_request()
     url_name = self.main_course_url_name(request)
     return link_reverse_func(url_name)
예제 #17
0
    def handle(self, *args, **options):
        "Execute the command"
        if len(args) != 2:
            raise CommandError("clone requires two arguments: <source-course_id> <dest-course_id>")

        source_course_id = args[0]
        dest_course_id = args[1]

        mstore = modulestore('direct')
        cstore = contentstore()

        mstore.metadata_inheritance_cache_subsystem = CACHE
        mstore.request_cache = RequestCache.get_request_cache()
        org, course_num, run = dest_course_id.split("/")
        mstore.ignore_write_events_on_courses.append('{0}/{1}'.format(org, course_num))

        print("Cloning course {0} to {1}".format(source_course_id, dest_course_id))

        source_location = CourseDescriptor.id_to_location(source_course_id)
        dest_location = CourseDescriptor.id_to_location(dest_course_id)

        if clone_course(mstore, cstore, source_location, dest_location):
            # be sure to recompute metadata inheritance after all those updates
            mstore.refresh_cached_metadata_inheritance_tree(dest_location)

            print("copying User permissions...")
            _copy_course_group(source_location, dest_location)
예제 #18
0
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError("delete_course requires one or more arguments: <location> |commit|")

        course_id = args[0]

        commit = False
        if len(args) == 2:
            commit = args[1] == 'commit'

        if commit:
            print 'Actually going to delete the course from DB....'

        ms = modulestore('direct')
        cs = contentstore()

        ms.metadata_inheritance_cache_subsystem = CACHE
        ms.request_cache = RequestCache.get_request_cache()
        org, course_num, run = course_id.split("/")
        ms.ignore_write_events_on_courses.append('{0}/{1}'.format(org, course_num))

        if query_yes_no("Deleting course {0}. Confirm?".format(course_id), default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!", default="no"):
                loc = CourseDescriptor.id_to_location(course_id)
                if delete_course(ms, cs, loc, commit):
                    print 'removing User permissions from course....'
                    # in the django layer, we need to remove all the user permissions groups associated with this course
                    if commit:
                        _delete_course_group(loc)
예제 #19
0
def new_assets_page_feature_flags(
        global_flag,
        enabled_for_all_courses=False,
        course_id=None,
        enabled_for_course=False
):
    """
    Most test cases will use a single call to this manager,
    as they need to set the global setting and the course-specific
    setting for a single course.
    """
    RequestCache.clear_request_cache()
    NewAssetsPageFlag.objects.create(enabled=global_flag, enabled_for_all_courses=enabled_for_all_courses)
    if course_id:
        CourseNewAssetsPageFlag.objects.create(course_id=course_id, enabled=enabled_for_course)
    yield
예제 #20
0
def get_group_info_for_cohort(cohort, use_cached=False):
    """
    Get the ids of the group and partition to which this cohort has been linked
    as a tuple of (int, int).

    If the cohort has not been linked to any group/partition, both values in the
    tuple will be None.

    The partition group info is cached for the duration of a request. Pass
    use_cached=True to use the cached value instead of fetching from the
    database.
    """
    request_cache = RequestCache.get_request_cache()
    cache_key = u"cohorts.get_group_info_for_cohort.{}".format(cohort.id)

    if use_cached and cache_key in request_cache.data:
        return request_cache.data[cache_key]

    request_cache.data.pop(cache_key, None)

    try:
        partition_group = CourseUserGroupPartitionGroup.objects.get(course_user_group=cohort)
        return request_cache.data.setdefault(cache_key, (partition_group.group_id, partition_group.partition_id))
    except CourseUserGroupPartitionGroup.DoesNotExist:
        pass

    return request_cache.data.setdefault(cache_key, (None, None))
예제 #21
0
def create_modulestore_instance(engine, options):
    """
    This will return a new instance of a modulestore given an engine and options
    """
    class_ = load_function(engine)

    _options = {}
    _options.update(options)

    for key in FUNCTION_KEYS:
        if key in _options and isinstance(_options[key], basestring):
            _options[key] = load_function(_options[key])

    if HAS_REQUEST_CACHE:
        request_cache = RequestCache.get_request_cache()
    else:
        request_cache = None

    try:
        metadata_inheritance_cache = get_cache('mongo_metadata_inheritance')
    except InvalidCacheBackendError:
        metadata_inheritance_cache = get_cache('default')

    return class_(
        metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
        request_cache=request_cache,
        modulestore_update_signal=Signal(providing_args=['modulestore', 'course_id', 'location']),
        **_options
    )
예제 #22
0
def create_modulestore_instance(engine, doc_store_config, options, i18n_service=None):
    """
    This will return a new instance of a modulestore given an engine and options
    """
    class_ = load_function(engine)

    _options = {}
    _options.update(options)

    for key in FUNCTION_KEYS:
        if key in _options and isinstance(_options[key], basestring):
            _options[key] = load_function(_options[key])

    if HAS_REQUEST_CACHE:
        request_cache = RequestCache.get_request_cache()
    else:
        request_cache = None

    try:
        metadata_inheritance_cache = get_cache('mongo_metadata_inheritance')
    except InvalidCacheBackendError:
        metadata_inheritance_cache = get_cache('default')

    return class_(
        metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
        request_cache=request_cache,
        modulestore_update_signal=Signal(providing_args=['modulestore', 'course_id', 'location']),
        xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
        xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
        doc_store_config=doc_store_config,
        i18n_service=i18n_service or ModuleI18nService(),
        **_options
    )
예제 #23
0
    def clear_caches(cls):
        """
        Clear all of the caches defined in settings.CACHES.
        """
        # N.B. As of 2016-04-20, Django won't return any caches
        # from django.core.cache.caches.all() that haven't been
        # accessed using caches[name] previously, so we loop
        # over our list of overridden caches, instead.
        for cache in settings.CACHES:
            caches[cache].clear()

        # The sites framework caches in a module-level dictionary.
        # Clear that.
        sites.models.SITE_CACHE.clear()

        RequestCache.clear_request_cache()
예제 #24
0
def get_template_request_context():
    """
    Returns the template processing context to use for the current request,
    or returns None if there is not a current request.
    """
    request = getattr(REQUEST_CONTEXT, "request", None)
    if not request:
        return None

    request_cache_dict = RequestCache.get_request_cache().data
    cache_key = "edxmako_request_context"
    if cache_key in request_cache_dict:
        return request_cache_dict[cache_key]

    context = RequestContext(request)
    context['is_secure'] = request.is_secure()
    context['site'] = safe_get_host(request)

    # This used to happen when a RequestContext object was initialized but was
    # moved to a different part of the logic when template engines were introduced.
    # Since we are not using template engines we do this here.
    # https://github.com/django/django/commit/37505b6397058bcc3460f23d48a7de9641cd6ef0
    for processor in get_template_context_processors():
        context.update(processor(request))

    request_cache_dict[cache_key] = context

    return context
예제 #25
0
파일: django.py 프로젝트: rhndg/openedx
def create_modulestore_instance(
    engine,
    content_store,
    doc_store_config,
    options,
    i18n_service=None,
    fs_service=None,
    user_service=None,
    signal_handler=None,
):
    """
    This will return a new instance of a modulestore given an engine and options
    """
    class_ = load_function(engine)

    _options = {}
    _options.update(options)

    FUNCTION_KEYS = ["render_template"]
    for key in FUNCTION_KEYS:
        if key in _options and isinstance(_options[key], basestring):
            _options[key] = load_function(_options[key])

    if HAS_REQUEST_CACHE:
        request_cache = RequestCache.get_request_cache()
    else:
        request_cache = None

    try:
        metadata_inheritance_cache = get_cache("mongo_metadata_inheritance")
    except InvalidCacheBackendError:
        metadata_inheritance_cache = get_cache("default")

    if issubclass(class_, MixedModuleStore):
        _options["create_modulestore_instance"] = create_modulestore_instance

    if issubclass(class_, BranchSettingMixin):
        _options["branch_setting_func"] = _get_modulestore_branch_setting

    if HAS_USER_SERVICE and not user_service:
        xb_user_service = DjangoXBlockUserService(get_current_user())
    else:
        xb_user_service = None

    if "read_preference" in doc_store_config:
        doc_store_config["read_preference"] = getattr(ReadPreference, doc_store_config["read_preference"])

    return class_(
        contentstore=content_store,
        metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
        request_cache=request_cache,
        xblock_mixins=getattr(settings, "XBLOCK_MIXINS", ()),
        xblock_select=getattr(settings, "XBLOCK_SELECT_FUNCTION", None),
        doc_store_config=doc_store_config,
        i18n_service=i18n_service or ModuleI18nService(),
        fs_service=fs_service or xblock.reference.plugins.FSService(),
        user_service=user_service or xb_user_service,
        signal_handler=signal_handler or SignalHandler(class_),
        **_options
    )
예제 #26
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError("check_course requires one argument: <location>")

        loc_str = args[0]

        loc = CourseDescriptor.id_to_location(loc_str)
        store = modulestore()

        # setup a request cache so we don't throttle the DB with all the metadata inheritance requests
        store.set_modulestore_configuration({
            'metadata_inheritance_cache_subsystem': CACHE,
            'request_cache': RequestCache.get_request_cache()
        })

        course = store.get_item(loc, depth=3)

        err_cnt = 0

        def _xlint_metadata(module):
            err_cnt = check_module_metadata_editability(module)
            for child in module.get_children():
                err_cnt = err_cnt + _xlint_metadata(child)
            return err_cnt

        err_cnt = err_cnt + _xlint_metadata(course)

        # we've had a bug where the xml_attributes field can we rewritten as a string rather than a dict
        def _check_xml_attributes_field(module):
            err_cnt = 0
            if hasattr(module, 'xml_attributes') and isinstance(module.xml_attributes, basestring):
                print 'module = {0} has xml_attributes as a string. It should be a dict'.format(module.location.url())
                err_cnt = err_cnt + 1
            for child in module.get_children():
                err_cnt = err_cnt + _check_xml_attributes_field(child)
            return err_cnt

        err_cnt = err_cnt + _check_xml_attributes_field(course)

        # check for dangling discussion items, this can cause errors in the forums
        def _get_discussion_items(module):
            discussion_items = []
            if module.location.category == 'discussion':
                discussion_items = discussion_items + [module.location.url()]

            for child in module.get_children():
                discussion_items = discussion_items + _get_discussion_items(child)

            return discussion_items

        discussion_items = _get_discussion_items(course)

        # now query all discussion items via get_items() and compare with the tree-traversal
        queried_discussion_items = store.get_items(['i4x', course.location.org, course.location.course,
                                                    'discussion', None, None])

        for item in queried_discussion_items:
            if item.location.url() not in discussion_items:
                print 'Found dangling discussion module = {0}'.format(item.location.url())
예제 #27
0
def get_current_request():
    """
    Return current request instance.

    Returns:
         (HttpRequest): returns cirrent request
    """
    return RequestCache.get_current_request()
예제 #28
0
    def test_course_waffle_flag(self, data):
        """
        Tests various combinations of a flag being set in waffle and overridden
        for a course.
        """
        RequestCache.clear_request_cache()

        with patch.object(WaffleFlagCourseOverrideModel, 'override_value', return_value=data['course_override']):
            with override_flag(self.NAMESPACED_FLAG_NAME, active=data['waffle_enabled']):
                # check twice to test that the result is properly cached
                self.assertEqual(self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_KEY), data['result'])
                self.assertEqual(self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_KEY), data['result'])
                # result is cached, so override check should happen once
                WaffleFlagCourseOverrideModel.override_value.assert_called_once_with(
                    self.NAMESPACED_FLAG_NAME,
                    self.TEST_COURSE_KEY
                )
예제 #29
0
    def test_gradebook(self):
        self.course.enable_ccx = True
        RequestCache.clear_request_cache()

        url = reverse(
            'ccx_gradebook',
            kwargs={'course_id': self.ccx_key}
        )
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        student_info = response.mako_context['students'][0]  # pylint: disable=no-member
        self.assertEqual(student_info['grade_summary']['percent'], 0.5)
        self.assertEqual(
            student_info['grade_summary']['grade_breakdown'][0]['percent'],
            0.5)
        self.assertEqual(
            len(student_info['grade_summary']['section_breakdown']), 4)
예제 #30
0
    def test_request_cached_with_changing_kwargs(self):
        """
        Ensure that calling a decorated function with different keyword arguments
        will not use a cached value invoked by a previous call with different arguments.
        """
        RequestCache.clear_request_cache()

        to_be_wrapped = Mock()
        to_be_wrapped.side_effect = [1, 2, 3, 4, 5, 6]
        self.assertEqual(to_be_wrapped.call_count, 0)

        def mock_wrapper(*args, **kwargs):
            """Simple wrapper to let us decorate our mock."""
            return to_be_wrapped(*args, **kwargs)

        wrapped = request_cached(mock_wrapper)

        # This will be a miss, and make an underlying call.
        result = wrapped(1, foo=1)
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 1)

        # This will be a miss, and make an underlying call.
        result = wrapped(2, foo=2)
        self.assertEqual(result, 2)
        self.assertEqual(to_be_wrapped.call_count, 2)

        # This is bypass of the decorator.
        direct_result = mock_wrapper(3, foo=3)
        self.assertEqual(direct_result, 3)
        self.assertEqual(to_be_wrapped.call_count, 3)

        # These will be hits, and not make an underlying call.
        result = wrapped(1, foo=1)
        self.assertEqual(result, 1)
        self.assertEqual(to_be_wrapped.call_count, 3)

        result = wrapped(2, foo=2)
        self.assertEqual(result, 2)
        self.assertEqual(to_be_wrapped.call_count, 3)

        # Since we're changing foo, this will be a miss.
        result = wrapped(2, foo=5)
        self.assertEqual(result, 4)
        self.assertEqual(to_be_wrapped.call_count, 4)
    def instrument_course_progress_render(
        self,
        course_width,
        enable_ccx,
        view_as_ccx,
        sql_queries,
        mongo_reads,
    ):
        """
        Renders the progress page, instrumenting Mongo reads and SQL queries.
        """
        course_key = self.setup_course(course_width, enable_ccx, view_as_ccx)

        # Switch to published-only mode to simulate the LMS
        with self.settings(MODULESTORE_BRANCH='published-only'):
            # Clear all caches before measuring
            for cache in settings.CACHES:
                caches[cache].clear()

            # Refill the metadata inheritance cache
            get_course_in_cache(course_key)

            # We clear the request cache to simulate a new request in the LMS.
            RequestCache.clear_request_cache()

            # Reset the list of provider classes, so that our django settings changes
            # can actually take affect.
            OverrideFieldData.provider_classes = None

            with self.assertNumQueries(
                    sql_queries,
                    using='default',
                    table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
                with self.assertNumQueries(0, using='student_module_history'):
                    with self.assertMongoCallCount(mongo_reads):
                        with self.assertXBlockInstantiations(1):
                            self.grade_course(course_key)
예제 #32
0
    def setUp(self, **kwargs):
        """
        Creates a test User if `create_user` is True.
        Returns the password for the test User.

        Args:
            create_user - specifies whether or not to create a test User.  Default is True.
        """
        settings_override = override_settings(MODULESTORE=self.MODULESTORE)
        settings_override.__enter__()
        self.addCleanup(settings_override.__exit__, None, None, None)

        # Clear out any existing modulestores,
        # which will cause them to be re-created
        clear_existing_modulestores()

        self.addCleanup(drop_mongo_collections)
        self.addCleanup(RequestCache().clear_request_cache)

        # Enable XModuleFactories for the space of this test (and its setUp).
        self.addCleanup(XMODULE_FACTORY_LOCK.disable)
        XMODULE_FACTORY_LOCK.enable()

        # When testing CCX, we should make sure that
        # OverrideFieldData.provider_classes is always reset to `None` so
        # that they're recalculated for every test
        OverrideFieldData.provider_classes = None

        super(ModuleStoreTestCase, self).setUp()

        self.store = modulestore()

        uname = 'testuser'
        email = '*****@*****.**'
        password = '******'

        if kwargs.pop('create_user', True):
            # Create the user so we can log them in.
            self.user = User.objects.create_user(uname, email, password)

            # Note that we do not actually need to do anything
            # for registration if we directly mark them active.
            self.user.is_active = True

            # Staff has access to view all courses
            self.user.is_staff = True
            self.user.save()

        return password
예제 #33
0
def get_team(commentable_id):
    """ Returns the team that the commentable_id belongs to if it exists. Returns None otherwise. """
    request_cache_dict = RequestCache.get_request_cache().data
    cache_key = u"django_comment_client.team_commentable.{}".format(
        commentable_id)
    if cache_key in request_cache_dict:
        return request_cache_dict[cache_key]

    try:
        team = CourseTeam.objects.get(discussion_topic_id=commentable_id)
    except CourseTeam.DoesNotExist:
        team = None

    request_cache_dict[cache_key] = team
    return team
예제 #34
0
    def _post_teardown(self):
        """
        Flush the ModuleStore after each test.
        """
        self.drop_mongo_collections()
        # Clear out the existing modulestores,
        # which will cause them to be re-created
        # the next time they are accessed.
        # We do this at *both* setup and teardown just to be safe.
        clear_existing_modulestores()
        # clear RequestCache to emulate its clearance after each http request.
        RequestCache().clear_request_cache()

        # Call superclass implementation
        super(ModuleStoreTestCase, self)._post_teardown()
예제 #35
0
파일: test_init.py 프로젝트: eliesmr4/myedx
    def test_course_waffle_flag(self, data):
        """
        Tests various combinations of a flag being set in waffle and overridden
        for a course.
        """
        RequestCache.clear_request_cache()

        with patch.object(WaffleFlagCourseOverrideModel,
                          'override_value',
                          return_value=data['course_override']):
            with override_flag(self.NAMESPACED_FLAG_NAME,
                               active=data['waffle_enabled']):
                # check twice to test that the result is properly cached
                self.assertEqual(
                    self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_KEY),
                    data['result'])
                self.assertEqual(
                    self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_KEY),
                    data['result'])
                # result is cached, so override check should happen once
                WaffleFlagCourseOverrideModel.override_value.assert_called_once_with(
                    self.NAMESPACED_FLAG_NAME, self.TEST_COURSE_KEY)

        # check flag for a second course
        if data['course_override'] == WaffleFlagCourseOverrideModel.ALL_CHOICES.unset:
            # When course override wasn't set for the first course, the second course will get the same
            # cached value from waffle.
            self.assertEqual(
                self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_2_KEY),
                data['waffle_enabled'])
        else:
            # When course override was set for the first course, it should not apply to the second
            # course which should get the default value of False.
            self.assertEqual(
                self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_2_KEY),
                False)
예제 #36
0
 def __init__(self, **kwargs):
     request_cache_dict = RequestCache.get_request_cache().data
     services = kwargs.setdefault('services', {})
     services['fs'] = xblock.reference.plugins.FSService()
     services['i18n'] = ModuleI18nService
     services['library_tools'] = LibraryToolsService(modulestore())
     services['partitions'] = LmsPartitionService(
         user=kwargs.get('user'),
         course_id=kwargs.get('course_id'),
         track_function=kwargs.get('track_function', None),
         cache=request_cache_dict)
     services['settings'] = SettingsService()
     services['user_tags'] = UserTagsService(self)
     self.request_token = kwargs.pop('request_token', None)
     super(LmsModuleSystem, self).__init__(**kwargs)
예제 #37
0
파일: django.py 프로젝트: taozeze/ANALYSE
def create_modulestore_instance(engine,
                                content_store,
                                doc_store_config,
                                options,
                                i18n_service=None,
                                fs_service=None):
    """
    This will return a new instance of a modulestore given an engine and options
    """
    class_ = load_function(engine)

    _options = {}
    _options.update(options)

    FUNCTION_KEYS = ['render_template']
    for key in FUNCTION_KEYS:
        if key in _options and isinstance(_options[key], basestring):
            _options[key] = load_function(_options[key])

    if HAS_REQUEST_CACHE:
        request_cache = RequestCache.get_request_cache()
    else:
        request_cache = None

    try:
        metadata_inheritance_cache = get_cache('mongo_metadata_inheritance')
    except InvalidCacheBackendError:
        metadata_inheritance_cache = get_cache('default')

    if issubclass(class_, MixedModuleStore):
        _options['create_modulestore_instance'] = create_modulestore_instance

    if issubclass(class_, BranchSettingMixin):
        _options['branch_setting_func'] = _get_modulestore_branch_setting

    return class_(
        contentstore=content_store,
        metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
        request_cache=request_cache,
        xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
        xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
        doc_store_config=doc_store_config,
        i18n_service=i18n_service or ModuleI18nService(),
        fs_service=fs_service or xblock.reference.plugins.FSService(),
        **_options)
예제 #38
0
    def handle(self, *args, **options):
        if len(args) != 1 and len(args) != 2:
            raise CommandError(
                "delete_course requires one or more arguments: <location> |commit|"
            )

        course_id = args[0]

        commit = False
        if len(args) == 2:
            commit = args[1] == 'commit'

        if commit:
            print 'Actually going to delete the course from DB....'

        ms = modulestore('direct')
        cs = contentstore()

        ms.set_modulestore_configuration({
            'metadata_inheritance_cache_subsystem':
            CACHE,
            'request_cache':
            RequestCache.get_request_cache()
        })

        org, course_num, run = course_id.split("/")
        ms.ignore_write_events_on_courses.append('{0}/{1}'.format(
            org, course_num))

        if query_yes_no("Deleting course {0}. Confirm?".format(course_id),
                        default="no"):
            if query_yes_no("Are you sure. This action cannot be undone!",
                            default="no"):
                loc = CourseDescriptor.id_to_location(course_id)
                if delete_course(ms, cs, loc, commit):
                    print 'removing User permissions from course....'
                    # in the django layer, we need to remove all the user permissions groups associated with this course
                    if commit:
                        try:
                            _delete_course_group(loc)
                        except Exception as err:
                            print(
                                "Error in deleting course groups for {0}: {1}".
                                format(loc, err))
예제 #39
0
    def __init__(self, **kwargs):
        request_cache_dict = RequestCache.get_request_cache().data
        store = modulestore()

        services = kwargs.setdefault('services', {})
        services['completion'] = CompletionService(
            user=kwargs.get('user'), course_key=kwargs.get('course_id'))
        services['fs'] = xblock.reference.plugins.FSService()
        services['i18n'] = ModuleI18nService
        services['library_tools'] = LibraryToolsService(store)
        services['partitions'] = PartitionService(
            course_id=kwargs.get('course_id'), cache=request_cache_dict)
        services['settings'] = SettingsService()
        services['user_tags'] = UserTagsService(self)
        if badges_enabled():
            services['badging'] = BadgingService(
                course_id=kwargs.get('course_id'), modulestore=store)
        self.request_token = kwargs.pop('request_token', None)
        super(LmsModuleSystem, self).__init__(**kwargs)
예제 #40
0
    def _providers_for_course(cls, course):
        """
        Return a filtered list of enabled providers based
        on the course passed in. Cache this result per request to avoid
        needing to call the provider filter api hundreds of times.

        Arguments:
            course: The course XBlock
        """
        request_cache = RequestCache.get_request_cache()
        enabled_providers = request_cache.data.get(
            ENABLED_OVERRIDE_PROVIDERS_KEY, NOTSET
        )
        if enabled_providers == NOTSET:
            enabled_providers = tuple(
                (provider_class for provider_class in cls.provider_classes if provider_class.enabled_for(course))
            )
            request_cache.data[ENABLED_OVERRIDE_PROVIDERS_KEY] = enabled_providers

        return enabled_providers
예제 #41
0
    def _providers_for_block(cls, block):
        """
        Computes a list of enabled providers based on the given XBlock.
        The result is cached per request to avoid the overhead incurred
        by filtering override providers hundreds of times.

        Arguments:
            block: An XBlock
        """
        course_id = unicode(block.location.course_key)
        cache_key = ENABLED_MODULESTORE_OVERRIDE_PROVIDERS_KEY.format(course_id=course_id)

        request_cache = RequestCache.get_request_cache()
        enabled_providers = request_cache.data.get(cache_key)

        if enabled_providers is None:
            enabled_providers = [
                provider_class for provider_class in cls.provider_classes if provider_class.enabled_for(block)
            ]
            request_cache.data[cache_key] = enabled_providers

        return enabled_providers
예제 #42
0
 def check_team_member(user, content):
     """
     If the content has a commentable_id, verifies that either it is not associated with a team,
     or if it is, that the user is a member of that team.
     """
     if not content:
         return False
     try:
         commentable_id = content['commentable_id']
         request_cache_dict = RequestCache.get_request_cache().data
         cache_key = "django_comment_client.check_team_member.{}.{}".format(user.id, commentable_id)
         if cache_key in request_cache_dict:
             return request_cache_dict[cache_key]
         team = get_team(commentable_id)
         if team is None:
             passes_condition = True
         else:
             passes_condition = team.users.filter(id=user.id).exists()
         request_cache_dict[cache_key] = passes_condition
     except KeyError:
         # We do not expect KeyError in production-- it usually indicates an improper test mock.
         logging.warning("Did not find key commentable_id in content.")
         passes_condition = False
     return passes_condition
예제 #43
0
def invalidate_course_mode_cache(sender, **kwargs):   # pylint: disable=unused-argument
    """Invalidate the cache of course modes. """
    RequestCache.clear_request_cache(name=CourseMode.CACHE_NAMESPACE)
예제 #44
0
def create_modulestore_instance(
    engine,
    content_store,
    doc_store_config,
    options,
    i18n_service=None,
    fs_service=None,
    user_service=None,
    signal_handler=None,
):
    """
    This will return a new instance of a modulestore given an engine and options
    """
    class_ = load_function(engine)

    _options = {}
    _options.update(options)

    FUNCTION_KEYS = ['render_template']
    for key in FUNCTION_KEYS:
        if key in _options and isinstance(_options[key], basestring):
            _options[key] = load_function(_options[key])

    if HAS_REQUEST_CACHE:
        request_cache = RequestCache.get_request_cache()
    else:
        request_cache = None

    try:
        metadata_inheritance_cache = caches['mongo_metadata_inheritance']
    except InvalidCacheBackendError:
        metadata_inheritance_cache = caches['default']

    if issubclass(class_, MixedModuleStore):
        _options['create_modulestore_instance'] = create_modulestore_instance

    if issubclass(class_, BranchSettingMixin):
        _options['branch_setting_func'] = _get_modulestore_branch_setting

    if HAS_USER_SERVICE and not user_service:
        xb_user_service = DjangoXBlockUserService(get_current_user())
    else:
        xb_user_service = None

    if 'read_preference' in doc_store_config:
        doc_store_config['read_preference'] = getattr(
            ReadPreference, doc_store_config['read_preference'])

    if XBlockDisableConfig and settings.FEATURES.get(
            'ENABLE_DISABLING_XBLOCK_TYPES', False):
        disabled_xblock_types = XBlockDisableConfig.disabled_block_types()
    else:
        disabled_xblock_types = ()

    xblock_field_data_wrappers = [
        load_function(path) for path in settings.XBLOCK_FIELD_DATA_WRAPPERS
    ]

    return class_(
        contentstore=content_store,
        metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
        request_cache=request_cache,
        xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
        xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
        xblock_field_data_wrappers=xblock_field_data_wrappers,
        disabled_xblock_types=disabled_xblock_types,
        doc_store_config=doc_store_config,
        i18n_service=i18n_service or ModuleI18nService(),
        fs_service=fs_service or xblock.reference.plugins.FSService(),
        user_service=user_service or xb_user_service,
        signal_handler=signal_handler or SignalHandler(class_),
        **_options)
예제 #45
0
from dogapi import dog_http_api, dog_stats_api
from django.conf import settings
from xmodule.modulestore.django import modulestore
from django.dispatch import Signal
from request_cache.middleware import RequestCache

from django.core.cache import get_cache

CACHE = get_cache('mongo_metadata_inheritance')
for store_name in settings.MODULESTORE:
    store = modulestore(store_name)

    store.set_modulestore_configuration({
        'metadata_inheritance_cache_subsystem': CACHE,
        'request_cache': RequestCache.get_request_cache()
    })

    modulestore_update_signal = Signal(providing_args=['modulestore', 'course_id', 'location'])
    store.modulestore_update_signal = modulestore_update_signal
if hasattr(settings, 'DATADOG_API'):
    dog_http_api.api_key = settings.DATADOG_API
    dog_stats_api.start(api_key=settings.DATADOG_API, statsd=True)
예제 #46
0
    def handle(self, *args, **options):
        if len(args) != 1:
            raise CommandError(
                "check_course requires one argument: <location>")

        loc_str = args[0]

        loc = CourseDescriptor.id_to_location(loc_str)
        store = modulestore()

        # setup a request cache so we don't throttle the DB with all the metadata inheritance requests
        store.set_modulestore_configuration({
            'metadata_inheritance_cache_subsystem':
            CACHE,
            'request_cache':
            RequestCache.get_request_cache()
        })

        course = store.get_item(loc, depth=3)

        err_cnt = 0

        def _xlint_metadata(module):
            err_cnt = check_module_metadata_editability(module)
            for child in module.get_children():
                err_cnt = err_cnt + _xlint_metadata(child)
            return err_cnt

        err_cnt = err_cnt + _xlint_metadata(course)

        # we've had a bug where the xml_attributes field can we rewritten as a string rather than a dict
        def _check_xml_attributes_field(module):
            err_cnt = 0
            if hasattr(module, 'xml_attributes') and isinstance(
                    module.xml_attributes, basestring):
                print 'module = {0} has xml_attributes as a string. It should be a dict'.format(
                    module.location.url())
                err_cnt = err_cnt + 1
            for child in module.get_children():
                err_cnt = err_cnt + _check_xml_attributes_field(child)
            return err_cnt

        err_cnt = err_cnt + _check_xml_attributes_field(course)

        # check for dangling discussion items, this can cause errors in the forums
        def _get_discussion_items(module):
            discussion_items = []
            if module.location.category == 'discussion':
                discussion_items = discussion_items + [module.location.url()]

            for child in module.get_children():
                discussion_items = discussion_items + _get_discussion_items(
                    child)

            return discussion_items

        discussion_items = _get_discussion_items(course)

        # now query all discussion items via get_items() and compare with the tree-traversal
        queried_discussion_items = store.get_items([
            'i4x', course.location.org, course.location.course, 'discussion',
            None, None
        ])

        for item in queried_discussion_items:
            if item.location.url() not in discussion_items:
                print 'Found dangling discussion module = {0}'.format(
                    item.location.url())
예제 #47
0
def get_cohort(user, course_key, assign=True, use_cached=False):
    """Returns the user's cohort for the specified course.

    The cohort for the user is cached for the duration of a request. Pass
    use_cached=True to use the cached value instead of fetching from the
    database.

    Arguments:
        user: a Django User object.
        course_key: CourseKey
        assign (bool): if False then we don't assign a group to user
        use_cached (bool): Whether to use the cached value or fetch from database.

    Returns:
        A CourseUserGroup object if the course is cohorted and the User has a
        cohort, else None.

    Raises:
       ValueError if the CourseKey doesn't exist.
    """
    request_cache = RequestCache.get_request_cache()
    cache_key = u"cohorts.get_cohort.{}.{}".format(user.id, course_key)

    if use_cached and cache_key in request_cache.data:
        return request_cache.data[cache_key]

    request_cache.data.pop(cache_key, None)

    # First check whether the course is cohorted (users shouldn't be in a cohort
    # in non-cohorted courses, but settings can change after course starts)
    course_cohort_settings = get_course_cohort_settings(course_key)
    if not course_cohort_settings.is_cohorted:
        return request_cache.data.setdefault(cache_key, None)

    # If course is cohorted, check if the user already has a cohort.
    try:
        membership = CohortMembership.objects.get(
            course_id=course_key,
            user_id=user.id,
        )
        return request_cache.data.setdefault(cache_key,
                                             membership.course_user_group)
    except CohortMembership.DoesNotExist:
        # Didn't find the group. If we do not want to assign, return here.
        if not assign:
            # Do not cache the cohort here, because in the next call assign
            # may be True, and we will have to assign the user a cohort.
            return None

    # Otherwise assign the user a cohort.
    try:
        with transaction.atomic():
            membership = CohortMembership.objects.create(
                user=user, course_user_group=get_random_cohort(course_key))
            return request_cache.data.setdefault(cache_key,
                                                 membership.course_user_group)
    except IntegrityError as integrity_error:
        # An IntegrityError is raised when multiple workers attempt to
        # create the same row in one of the cohort model entries:
        # CourseCohort, CohortMembership.
        log.info(
            "HANDLING_INTEGRITY_ERROR: IntegrityError encountered for course '%s' and user '%s': %s",
            course_key, user.id, unicode(integrity_error))
        return get_cohort(user, course_key, assign, use_cached)
예제 #48
0
def invalidate_verified_track_cache(sender, **kwargs):   # pylint: disable=unused-argument
    """Invalidate the cache of VerifiedTrackCohortedCourse. """
    RequestCache.clear_request_cache(name=VerifiedTrackCohortedCourse.CACHE_NAMESPACE)
예제 #49
0
파일: django.py 프로젝트: gopinath81/vmss
def create_modulestore_instance(
        engine,
        content_store,
        doc_store_config,
        options,
        i18n_service=None,
        fs_service=None,
        user_service=None,
        signal_handler=None,
):
    """
    This will return a new instance of a modulestore given an engine and options
    """
    class_ = load_function(engine)

    _options = {}
    _options.update(options)

    FUNCTION_KEYS = ['render_template']
    for key in FUNCTION_KEYS:
        if key in _options and isinstance(_options[key], basestring):
            _options[key] = load_function(_options[key])

    if HAS_REQUEST_CACHE:
        request_cache = RequestCache.get_request_cache()
    else:
        request_cache = None

    try:
        metadata_inheritance_cache = caches['mongo_metadata_inheritance']
    except InvalidCacheBackendError:
        metadata_inheritance_cache = caches['default']

    if issubclass(class_, MixedModuleStore):
        _options['create_modulestore_instance'] = create_modulestore_instance

    if issubclass(class_, BranchSettingMixin):
        _options['branch_setting_func'] = _get_modulestore_branch_setting

    if HAS_USER_SERVICE and not user_service:
        xb_user_service = DjangoXBlockUserService(get_current_user())
    else:
        xb_user_service = None

    if 'read_preference' in doc_store_config:
        doc_store_config['read_preference'] = getattr(ReadPreference, doc_store_config['read_preference'])

    xblock_field_data_wrappers = [load_function(path) for path in settings.XBLOCK_FIELD_DATA_WRAPPERS]

    def fetch_disabled_xblock_types():
        """
        Get the disabled xblock names, using the request_cache if possible to avoid hitting
        a database every time the list is needed.
        """
        # If the import could not be loaded, return an empty list.
        if disabled_xblocks is None:
            return []

        if request_cache:
            if 'disabled_xblock_types' not in request_cache.data:
                request_cache.data['disabled_xblock_types'] = [block.name for block in disabled_xblocks()]
            return request_cache.data['disabled_xblock_types']
        else:
            disabled_xblock_types = [block.name for block in disabled_xblocks()]

        return disabled_xblock_types

    return class_(
        contentstore=content_store,
        metadata_inheritance_cache_subsystem=metadata_inheritance_cache,
        request_cache=request_cache,
        xblock_mixins=getattr(settings, 'XBLOCK_MIXINS', ()),
        xblock_select=getattr(settings, 'XBLOCK_SELECT_FUNCTION', None),
        xblock_field_data_wrappers=xblock_field_data_wrappers,
        disabled_xblock_types=fetch_disabled_xblock_types,
        doc_store_config=doc_store_config,
        i18n_service=i18n_service or ModuleI18nService,
        fs_service=fs_service or xblock.reference.plugins.FSService(),
        user_service=user_service or xb_user_service,
        signal_handler=signal_handler or SignalHandler(class_),
        **_options
    )
예제 #50
0
 def setUp(self):
     super(TestCourseWaffleFlag, self).setUp()
     request = RequestFactory().request()
     crum.set_current_request(request)
     RequestCache.clear_request_cache()
예제 #51
0
 def _clear_cache(self):
     """
     Clears the requestcached values on the is_switch_enabled function.
     """
     cache_key = func_call_cache_key(is_switch_enabled.request_cached_contained_func, self.name)
     RequestCache.get_request_cache().data.pop(cache_key, None)
예제 #52
0
def invalidate_credit_requirement_cache(sender, **kwargs):  # pylint: disable=unused-argument
    """Invalidate the cache of credit requirements. """
    RequestCache.clear_request_cache(name=CreditRequirement.CACHE_NAMESPACE)
예제 #53
0
from dogapi import dog_http_api, dog_stats_api
from django.conf import settings
from xmodule.modulestore.django import modulestore
from django.dispatch import Signal
from request_cache.middleware import RequestCache

from django.core.cache import get_cache

CACHE = get_cache('mongo_metadata_inheritance')
for store_name in settings.MODULESTORE:
    store = modulestore(store_name)
    store.metadata_inheritance_cache_subsystem = CACHE
    store.request_cache = RequestCache.get_request_cache()

    modulestore_update_signal = Signal(
        providing_args=['modulestore', 'course_id', 'location'])
    store.modulestore_update_signal = modulestore_update_signal
if hasattr(settings, 'DATADOG_API'):
    dog_http_api.api_key = settings.DATADOG_API
    dog_stats_api.start(api_key=settings.DATADOG_API, statsd=True)
예제 #54
0
    def _create_courseware_context(self):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        request = RequestCache.get_current_request()
        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            self.is_staff,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            True,
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            waffle.flag_is_active(request, UNIFIED_COURSE_VIEW_FLAG),
        }
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        # staff masquerading data
        now = datetime.now(UTC())
        effective_start = _adjust_start_date_for_beta_testers(
            self.effective_user, self.course, self.course_key)
        if not in_preview_mode() and self.is_staff and now < effective_start:
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            courseware_context['disable_student_access'] = True

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(
                STUDENT_VIEW, section_context)
            if self.section.position and self.section.has_children:
                display_items = self.section.get_display_items()
                if display_items:
                    try:
                        courseware_context['sequence_title'] = display_items[self.section.position - 1] \
                            .display_name_with_default
                    except IndexError:
                        log.info(
                            "Course section {} with position {} and total section display items: {}"
                            .format(
                                self.section.display_name_with_default,
                                self.section.position,
                                len(display_items),
                            ))
        return courseware_context
예제 #55
0
def get_cohort(user, course_key, assign=True, use_cached=False):
    """Returns the user's cohort for the specified course.

    The cohort for the user is cached for the duration of a request. Pass
    use_cached=True to use the cached value instead of fetching from the
    database.

    Arguments:
        user: a Django User object.
        course_key: CourseKey
        assign (bool): if False then we don't assign a group to user
        use_cached (bool): Whether to use the cached value or fetch from database.

    Returns:
        A CourseUserGroup object if the course is cohorted and the User has a
        cohort, else None.

    Raises:
       ValueError if the CourseKey doesn't exist.
    """
    request_cache = RequestCache.get_request_cache()
    cache_key = u"cohorts.get_cohort.{}.{}".format(user.id, course_key)

    if use_cached and cache_key in request_cache.data:
        return request_cache.data[cache_key]

    request_cache.data.pop(cache_key, None)

    # First check whether the course is cohorted (users shouldn't be in a cohort
    # in non-cohorted courses, but settings can change after course starts)
    course_cohort_settings = get_course_cohort_settings(course_key)
    if not course_cohort_settings.is_cohorted:
        return request_cache.data.setdefault(cache_key, None)

    # If course is cohorted, check if the user already has a cohort.
    try:
        cohort = CourseUserGroup.objects.get(
            course_id=course_key,
            group_type=CourseUserGroup.COHORT,
            users__id=user.id,
        )
        return request_cache.data.setdefault(cache_key, cohort)
    except CourseUserGroup.DoesNotExist:
        # Didn't find the group. If we do not want to assign, return here.
        if not assign:
            # Do not cache the cohort here, because in the next call assign
            # may be True, and we will have to assign the user a cohort.
            return None

    # Otherwise assign the user a cohort.
    course = courses.get_course(course_key)
    cohorts = get_course_cohorts(course, assignment_type=CourseCohort.RANDOM)
    if cohorts:
        cohort = local_random().choice(cohorts)
    else:
        cohort = CourseCohort.create(
            cohort_name=DEFAULT_COHORT_NAME,
            course_id=course_key,
            assignment_type=CourseCohort.RANDOM
        ).course_user_group

    user.course_groups.add(cohort)

    return request_cache.data.setdefault(cache_key, cohort)
예제 #56
0
    def dump_courses_to_neo4j(self, graph, override_cache=False):
        """
        Parameters
        ----------
        graph: py2neo graph object
        override_cache: serialize the courses even if they'be been recently
            serialized

        Returns two lists: one of the courses that were successfully written
          to neo4j, and one of courses that were not.
        -------
        """
        total_number_of_courses = len(self.course_keys)

        successful_courses = []
        unsuccessful_courses = []

        for index, course_key in enumerate(self.course_keys):
            # first, clear the request cache to prevent memory leaks
            RequestCache.clear_request_cache()

            log.info(
                "Now exporting %s to neo4j: course %d of %d total courses",
                course_key,
                index + 1,
                total_number_of_courses,
            )

            if not (override_cache or self.should_dump_course(course_key)):
                log.info("skipping dumping %s, since it hasn't changed",
                         course_key)
                continue

            nodes, relationships = self.serialize_course(course_key)
            log.info(
                "%d nodes and %d relationships in %s",
                len(nodes),
                len(relationships),
                course_key,
            )

            transaction = graph.begin()
            course_string = six.text_type(course_key)
            try:
                # first, delete existing course
                transaction.run(
                    "MATCH (n:item) WHERE n.course_key='{}' DETACH DELETE n".
                    format(course_string))

                # now, re-add it
                self.add_to_transaction(nodes, transaction)
                self.add_to_transaction(relationships, transaction)
                transaction.commit()

            except Exception:  # pylint: disable=broad-except
                log.exception(
                    "Error trying to dump course %s to neo4j, rolling back",
                    course_string)
                transaction.rollback()
                unsuccessful_courses.append(course_string)

            else:
                COMMAND_LAST_RUN_CACHE.set(course_key)
                successful_courses.append(course_string)

        return successful_courses, unsuccessful_courses
예제 #57
0
 def setUp(self):
     super(OverrideWaffleFlagTests, self).setUp()
     RequestCache.clear_request_cache()