Ejemplo n.º 1
0
    def access_denied_fragment(self, block, user, user_group, allowed_groups):
        course_key = self._get_course_key_from_course_block(block)
        course = CourseOverview.get_from_id(course_key)
        modes = CourseMode.modes_for_course_dict(course=course,
                                                 include_expired=True)
        verified_mode = modes.get(CourseMode.VERIFIED)
        if (verified_mode is None or user_group == FULL_ACCESS
                or user_group in allowed_groups):
            return None

        expiration_datetime = verified_mode.expiration_datetime
        if expiration_datetime and expiration_datetime < datetime.datetime.now(
                pytz.UTC):
            ecommerce_checkout_link = None
        else:
            ecommerce_checkout_link = self._get_checkout_link(
                user, verified_mode.sku)

        request = crum.get_current_request()

        upgrade_price, _ = format_strikeout_price(user, course)

        frag = Fragment(
            render_to_string(
                'content_type_gating/access_denied_message.html', {
                    'mobile_app': request
                    and is_request_from_mobile_app(request),
                    'ecommerce_checkout_link': ecommerce_checkout_link,
                    'min_price': upgrade_price,
                }))
        return frag
Ejemplo n.º 2
0
    def get_ctas(self, xblock, category):
        """
        Return the calls to action associated with the specified category for the given xblock.

        Look at CallToActionService docstring to see what will be returned.
        """
        ctas = []

        # Some checks to disable PLS calls to action until these environments (mobile and MFE) support them natively
        request = get_current_request()
        is_mobile_app = request and is_request_from_mobile_app(request)
        is_learning_mfe = request and is_request_from_learning_mfe(request)
        if is_mobile_app:
            return []

        if category == self.CAPA_SUBMIT_DISABLED:
            # xblock is a capa problem, and the submit button is disabled. Check if it's because of a personalized
            # schedule due date being missed, and if so, we can offer to shift it.
            if self._is_block_shiftable(xblock):
                ctas.append(
                    self._make_reset_deadlines_cta(xblock, is_learning_mfe))

        elif category == self.VERTICAL_BANNER:
            # xblock is a vertical, so we'll check all the problems inside it. If there are any that will show a
            # a "shift dates" CTA under CAPA_SUBMIT_DISABLED, then we'll also show the same CTA as a vertical banner.
            if any(
                    self._is_block_shiftable(item)
                    for item in xblock.get_display_items()):
                ctas.append(
                    self._make_reset_deadlines_cta(xblock, is_learning_mfe))

        return ctas
Ejemplo n.º 3
0
    def _on_user_authentication_failed(request):
        """
        To be called when user authentication fails when processing
        requests in the middleware. Sets a flag to delete the user's
        cookie and redirects the user to the login page.
        """
        _mark_cookie_for_deletion(request)

        # Mobile apps have custom handling of authentication failures. They
        # should *not* be redirected to the website's login page.
        if is_request_from_mobile_app(request):
            return HttpResponse(status=401)

        # .. toggle_name: REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE
        # .. toggle_implementation: SettingToggle
        # .. toggle_default: True
        # .. toggle_description: Turn this toggle off to roll out new functionality,
        #      which returns a 401 rather than redirecting to login, when HTML is not expected by the client.
        # .. toggle_use_cases: temporary
        # .. toggle_creation_date: 2021-10-18
        # .. toggle_target_removal_date: 2021-10-22
        # .. toggle_tickets: https://openedx.atlassian.net/browse/ARCHBOM-1911
        REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE = getattr(
            settings, 'REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE', True)

        if REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE or 'text/html' in request.META.get(
                'HTTP_ACCEPT', ''):
            set_custom_attribute("safe_sessions.auth_failure",
                                 "redirect_to_login")
            return redirect_to_login(request.path)
        set_custom_attribute("safe_sessions.auth_failure", "401")
        return HttpResponse(status=401)
def is_from_mobile_app(request):
    """
    Configuration context for django templates.
    """
    return {
        'is_from_mobile_app': is_request_from_mobile_app(request)
    }
Ejemplo n.º 5
0
def is_from_mobile_app(request):  # pylint: disable=unused-argument
    """
    Configuration context for django templates.
    """
    return {
        'is_from_mobile_app': is_request_from_mobile_app(request)
    }
Ejemplo n.º 6
0
    def get_ctas(self, xblock, category, completed):
        """
        Return the calls to action associated with the specified category for the given xblock.

        Look at CallToActionService docstring to see what will be returned.
        """
        ctas = []
        request = get_current_request()

        course_key = xblock.scope_ids.usage_id.context_key
        missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user)
        # Not showing in the missed_gated_content case because those learners are not eligible
        # to shift due dates.
        if not missed_deadlines or missed_gated_content:
            return []

        # Some checks to disable PLS calls to action until these environments (mobile and MFE) support them natively
        if request and is_request_from_mobile_app(request):
            return []

        is_learning_mfe = request and is_request_from_learning_mfe(request)
        if category == self.CAPA_SUBMIT_DISABLED:
            # xblock is a capa problem, and the submit button is disabled. Check if it's because of a personalized
            # schedule due date being missed, and if so, we can offer to shift it.
            if self._is_block_shiftable(xblock, category):
                ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe))

        elif category == self.VERTICAL_BANNER and not completed:
            # xblock is a vertical, so we'll check all the problems inside it. If there are any that will show a
            # a "shift dates" CTA under CAPA_SUBMIT_DISABLED, then we'll also show the same CTA as a vertical banner.
            if any(self._is_block_shiftable(item, category) for item in xblock.get_display_items()):
                ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe))

        return ctas
Ejemplo n.º 7
0
    def process_response(self, request, response):  # lint-amnesty, pylint: disable=missing-function-docstring
        # If the user is logged in, check for their language preference. Also check for real user
        # if current user is a masquerading user,
        user_pref = None
        current_user = None
        if hasattr(request, 'user'):
            current_user = getattr(request.user, 'real_user', request.user)

        if current_user and current_user.is_authenticated:

            # DarkLangMiddleware has already set this cookie
            if DarkLangConfig.current().enabled and get_user_preference(current_user, DARK_LANGUAGE_KEY):
                return response

            anonymous_cookie_lang = getattr(request, '_anonymous_user_cookie_lang', None)
            if anonymous_cookie_lang:
                user_pref = anonymous_cookie_lang
                set_user_preference(current_user, LANGUAGE_KEY, anonymous_cookie_lang)
            else:
                # Get the user's language preference
                try:
                    user_pref = get_user_preference(current_user, LANGUAGE_KEY)
                except (UserAPIRequestError, UserAPIInternalError):
                    # If we can't find the user preferences, then don't modify the cookie
                    pass

            # If set, set the user_pref in the LANGUAGE_COOKIE_NAME
            if user_pref and not is_request_from_mobile_app(request):
                lang_pref_helpers.set_language_cookie(request, response, user_pref)
            else:
                lang_pref_helpers.unset_language_cookie(response)

        return response
Ejemplo n.º 8
0
    def record_user_activity(cls, user, course_key, request=None, only_if_mobile_app=False):
        '''
        Update the user activity table with a record for this activity.

        Since we store one activity per date, we don't need to query the database
        for every activity on a given date.
        To avoid unnecessary queries, we store a record in a cache once we have an activity for the date,
        which times out at the end of that date (in the user's timezone).

        The request argument is only used to check if the request is coming from a mobile app.
        Once the only_if_mobile_app argument is removed the request argument can be removed as well.

        The return value is the id of the object that was created, or retrieved.
        A return value of None signifies that there was an issue with the parameters (or the user was masquerading).
        '''
        if not (user and user.id) or not course_key:
            return None

        if only_if_mobile_app and request and not is_request_from_mobile_app(request):
            return None

        if is_masquerading(user, course_key):
            return None

        user_preferences = get_user_preferences(user)
        timezone = pytz.timezone(user_preferences.get('time_zone', 'UTC'))
        now = datetime.now(timezone)
        date = now.date()

        cache_key = 'goals_user_activity_{}_{}_{}'.format(str(user.id), str(course_key), str(date))

        cached_value = TieredCache.get_cached_response(cache_key)
        if cached_value.is_found:
            # Temporary debugging log for testing mobile app connection
            if request:
                log.info(
                    'Retrieved cached value with request {} for user and course combination {} {}'.format(
                        str(request.build_absolute_uri()), str(user.id), str(course_key)
                    )
                )
            return cached_value.value, False

        activity_object, __ = cls.objects.get_or_create(user=user, course_key=course_key, date=date)

        # Cache result until the end of the day to avoid unnecessary database requests
        tomorrow = now + timedelta(days=1)
        midnight = datetime(year=tomorrow.year, month=tomorrow.month,
                            day=tomorrow.day, hour=0, minute=0, second=0, tzinfo=timezone)
        seconds_until_midnight = (midnight - now).seconds

        TieredCache.set_all_tiers(cache_key, activity_object.id, seconds_until_midnight)
        # Temporary debugging log for testing mobile app connection
        if request:
            log.info(
                'Set cached value with request {} for user and course combination {} {}'.format(
                    str(request.build_absolute_uri()), str(user.id), str(course_key)
                )
            )
        return activity_object.id
Ejemplo n.º 9
0
    def _get_platform(self, request, user_agent):
        """
        Determines the platform type for mobile app making the request against user_agent.

        Returns:
            None if request app does not belong to one of the supported mobile platforms
            else returns an instance of corresponding mobile platform.
        """
        if is_request_from_mobile_app(request):
            return MobilePlatform.get_instance(user_agent)
Ejemplo n.º 10
0
    def _get_platform(self, request, user_agent):
        """
        Determines the platform type for mobile app making the request against user_agent.

        Returns:
            None if request app does not belong to one of the supported mobile platforms
            else returns an instance of corresponding mobile platform.
        """
        if is_request_from_mobile_app(request):
            return MobilePlatform.get_instance(user_agent)
Ejemplo n.º 11
0
    def access_denied_message(self, block_key, user, user_group, allowed_groups):
        course_key = block_key.course_key
        modes = CourseMode.modes_for_course_dict(course_key)
        verified_mode = modes.get(CourseMode.VERIFIED)
        if (verified_mode is None or not self._is_audit_enrollment(user, course_key) or
                user_group == FULL_ACCESS):
            return None

        request = crum.get_current_request()
        if request and is_request_from_mobile_app(request):
            return _(u"Graded assessments are available to Verified Track learners.")
        else:
            return _(u"Graded assessments are available to Verified Track learners. Upgrade to Unlock.")
Ejemplo n.º 12
0
    def access_denied_fragment(self, block, user, user_group, allowed_groups):
        modes = CourseMode.modes_for_course_dict(block.scope_ids.usage_id.course_key)
        verified_mode = modes.get(CourseMode.VERIFIED)
        if verified_mode is None or not self._is_audit_enrollment(user, block):
            return None
        ecommerce_checkout_link = self._get_checkout_link(user, verified_mode.sku)

        request = crum.get_current_request()
        frag = Fragment(render_to_string('content_type_gating/access_denied_message.html', {
            'mobile_app': is_request_from_mobile_app(request),
            'ecommerce_checkout_link': ecommerce_checkout_link,
            'min_price': str(verified_mode.min_price)
        }))
        return frag
Ejemplo n.º 13
0
    def _on_user_authentication_failed(request):
        """
        To be called when user authentication fails when processing
        requests in the middleware. Sets a flag to delete the user's
        cookie and redirects the user to the login page.
        """
        _mark_cookie_for_deletion(request)

        # Mobile apps have custom handling of authentication failures. They
        # should *not* be redirected to the website's login page.
        if is_request_from_mobile_app(request):
            return HttpResponse(status=401)

        return redirect_to_login(request.path)
Ejemplo n.º 14
0
    def _on_user_authentication_failed(request):
        """
        To be called when user authentication fails when processing
        requests in the middleware. Sets a flag to delete the user's
        cookie and redirects the user to the login page.
        """
        _mark_cookie_for_deletion(request)

        # Mobile apps have custom handling of authentication failures. They
        # should *not* be redirected to the website's login page.
        if is_request_from_mobile_app(request):
            return HttpResponse(status=401)

        return redirect_to_login(request.path)
Ejemplo n.º 15
0
def update_session_language(request):
    """
    Update the language session key.
    """
    response = HttpResponse(200)
    if request.method == 'PATCH':
        data = json.loads(request.body.decode('utf8'))
        language = data.get(LANGUAGE_KEY, settings.LANGUAGE_CODE)
        if request.session.get(LANGUAGE_SESSION_KEY, None) != language:
            request.session[LANGUAGE_SESSION_KEY] = six.text_type(language)
        if not is_request_from_mobile_app(request):
            response.set_cookie(settings.LANGUAGE_COOKIE,
                                language,
                                domain=settings.SESSION_COOKIE_DOMAIN,
                                max_age=COOKIE_DURATION)
    return response
Ejemplo n.º 16
0
    def access_denied_fragment(self, block, user, user_group, allowed_groups):
        course_key = self._get_course_key_from_course_block(block)
        modes = CourseMode.modes_for_course_dict(course_key)
        verified_mode = modes.get(CourseMode.VERIFIED)
        if (verified_mode is None or user_group == FULL_ACCESS or
                user_group in allowed_groups):
            return None

        ecommerce_checkout_link = self._get_checkout_link(user, verified_mode.sku)
        request = crum.get_current_request()
        frag = Fragment(render_to_string('content_type_gating/access_denied_message.html', {
            'mobile_app': request and is_request_from_mobile_app(request),
            'ecommerce_checkout_link': ecommerce_checkout_link,
            'min_price': str(verified_mode.min_price)
        }))
        return frag
Ejemplo n.º 17
0
    def get_ctas(self, xblock, category):
        """
        Return the calls to action associated with the specified category for the given xblock.

        See the CallToActionService class constants for a list of recognized categories.

        Returns: list of dictionaries, describing the calls to action, with the following keys:
                 link, link_name, form_values, and description.
                 If the category is not recognized, an empty list is returned.

        An example of a returned list:
        [{
            'link': 'localhost:18000/skip',  # A link to POST to when the Call To Action is taken
            'link_name': 'Skip this Problem',  # The name of the action
            'form_values': {  # Any parameters to include with the CTA
                'foo': 'bar',
            },
            # A long-form description to be associated with the CTA
            'description': "If you don't want to do this problem, just skip it!"
        }]
        """
        ctas = []

        # Some checks to disable PLS calls to action until these environments (mobile and MFE) support them natively
        request = get_current_request()
        is_mobile_app = request and is_request_from_mobile_app(request)
        is_learning_mfe = request and is_request_from_learning_mfe(request)
        if is_mobile_app or is_learning_mfe:
            return []

        if category == self.CAPA_SUBMIT_DISABLED:
            # xblock is a capa problem, and the submit button is disabled. Check if it's because of a personalized
            # schedule due date being missed, and if so, we can offer to shift it.
            if self._is_block_shiftable(xblock):
                ctas.append(self._make_reset_deadlines_cta(xblock))

        elif category == self.VERTICAL_BANNER:
            # xblock is a vertical, so we'll check all the problems inside it. If there are any that will show a
            # a "shift dates" CTA under CAPA_SUBMIT_DISABLED, then we'll also show the same CTA as a vertical banner.
            if any(self._is_block_shiftable(item) for item in xblock.get_display_items()):
                ctas.append(self._make_reset_deadlines_cta(xblock))

        return ctas
Ejemplo n.º 18
0
    def access_denied_fragment(self, block, user, user_group, allowed_groups):
        course_key = self._get_course_key_from_course_block(block)
        modes = CourseMode.modes_for_course_dict(course_key)
        verified_mode = modes.get(CourseMode.VERIFIED)
        if (verified_mode is None or user_group == FULL_ACCESS
                or user_group in allowed_groups):
            return None

        ecommerce_checkout_link = self._get_checkout_link(
            user, verified_mode.sku)
        request = crum.get_current_request()
        frag = Fragment(
            render_to_string(
                'content_type_gating/access_denied_message.html', {
                    'mobile_app': request
                    and is_request_from_mobile_app(request),
                    'ecommerce_checkout_link': ecommerce_checkout_link,
                    'min_price': str(verified_mode.min_price)
                }))
        return frag
Ejemplo n.º 19
0
    def _on_user_authentication_failed(request):
        """
        To be called when user authentication fails when processing requests in the middleware.
        Sets a flag to delete the user's cookie and does one of the following:
        - Raises 401 for mobile requests and requests that are not specifically requesting a HTML response.
        - Redirects to login in case request expects a HTML response.
        """
        _mark_cookie_for_deletion(request)

        # Mobile apps have custom handling of authentication failures. They
        # should *not* be redirected to the website's login page.
        if is_request_from_mobile_app(request):
            set_custom_attribute("safe_sessions.auth_failure", "mobile")
            return HttpResponse(status=401)

        # only redirect to login if client is expecting html
        if 'text/html' in request.META.get('HTTP_ACCEPT', ''):
            set_custom_attribute("safe_sessions.auth_failure", "redirect_to_login")
            return redirect_to_login(request.path)
        set_custom_attribute("safe_sessions.auth_failure", "401")
        return HttpResponse(status=401)
Ejemplo n.º 20
0
    def process_response(self, request, response):
        # If the user is logged in, check for their language preference. Also check for real user
        # if current user is a masquerading user,
        user_pref = None
        current_user = None
        if hasattr(request, 'user'):
            current_user = getattr(request.user, 'real_user', request.user)

        if current_user and current_user.is_authenticated:
            anonymous_cookie_lang = getattr(request,
                                            '_anonymous_user_cookie_lang',
                                            None)
            if anonymous_cookie_lang:
                user_pref = anonymous_cookie_lang
                set_user_preference(current_user, LANGUAGE_KEY,
                                    anonymous_cookie_lang)
            else:
                # Get the user's language preference
                try:
                    user_pref = get_user_preference(current_user, LANGUAGE_KEY)
                except (UserAPIRequestError, UserAPIInternalError):
                    # If we can't find the user preferences, then don't modify the cookie
                    pass

            # If set, set the user_pref in the LANGUAGE_COOKIE
            if user_pref:
                if not is_request_from_mobile_app(request):
                    response.set_cookie(
                        settings.LANGUAGE_COOKIE,
                        value=user_pref,
                        domain=settings.SESSION_COOKIE_DOMAIN,
                        max_age=COOKIE_DURATION,
                    )
            else:
                response.delete_cookie(settings.LANGUAGE_COOKIE,
                                       domain=settings.SESSION_COOKIE_DOMAIN)

        return response
Ejemplo n.º 21
0
    def process_request(self, request):
        """
        Perform the following checks
            1. Check that the user is authenticated and belongs to an enterprise customer.
            2. Check that the enterprise customer has a language set via the `default_language` column on
                EnterpriseCustomer model.
            3. Check that user has not set a language via its account settings page.

        If all the above checks are satisfied then set request._anonymous_user_cookie_lang to the `default_language` of
        EnterpriseCustomer model instance. This attribute will later be used by the `LanguagePreferenceMiddleware`
        middleware for setting the user preference. Since, this middleware relies on `LanguagePreferenceMiddleware`
        so it must always be followed by `LanguagePreferenceMiddleware`. Otherwise, it will not work.
        """
        # If the user is logged in, check for their language preference and user's enterprise configuration.
        # Also check for real user, if current user is a masquerading user.
        user_pref, current_user = None, None
        if hasattr(request, 'user'):
            current_user = getattr(request.user, 'real_user', request.user)

        if current_user and current_user.is_authenticated:
            enterprise_customer = get_enterprise_customer_for_user(
                current_user)

            if enterprise_customer and enterprise_customer.default_language:
                # Get the user's language preference
                try:
                    user_pref = get_user_preference(current_user, LANGUAGE_KEY)
                except (UserAPIRequestError, UserAPIInternalError):
                    # Ignore errors related to user preferences not found.
                    pass

                # If user's language preference is not set and enterprise customer has a default language configured
                # then set the default language as the learner's language
                if not user_pref and not is_request_from_mobile_app(request):
                    # pylint: disable=protected-access
                    request._anonymous_user_cookie_lang = enterprise_customer.default_language
Ejemplo n.º 22
0
    def _add_honor_code_field(self, form_desc, required=True):
        """Add an honor code field to a form description.
        Arguments:
            form_desc: A form description
        Keyword Arguments:
            required (bool): Whether this field is required; defaults to True
        """

        separate_honor_and_tos = self._is_field_visible("terms_of_service")
        # Separate terms of service and honor code checkboxes
        if separate_honor_and_tos:
            terms_label = _(u"Honor Code")
            terms_link = marketing_link("HONOR")

        # Combine terms of service and honor code checkboxes
        else:
            # Translators: This is a legal document users must agree to
            # in order to register a new account.
            terms_label = _(u"Terms of Service and Honor Code")
            terms_link = marketing_link("HONOR")

        # Translators: "Terms of Service" is a legal document users must agree to
        # in order to register a new account.
        label = Text(
            _(u"I agree to the {platform_name} {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end}"
              )).format(
                  platform_name=configuration_helpers.get_value(
                      "PLATFORM_NAME", settings.PLATFORM_NAME),
                  terms_of_service=terms_label,
                  terms_of_service_link_start=HTML(
                      "<a href='{terms_link}' target='_blank'>").format(
                          terms_link=terms_link),
                  terms_of_service_link_end=HTML("</a>"),
              )

        # Translators: "Terms of Service" is a legal document users must agree to
        # in order to register a new account.
        error_msg = _(
            u"You must agree to the {platform_name} {terms_of_service}"
        ).format(platform_name=configuration_helpers.get_value(
            "PLATFORM_NAME", settings.PLATFORM_NAME),
                 terms_of_service=terms_label)
        field_type = 'checkbox'

        if ENABLE_GDPR_COMPAT_FLAG.is_enabled_without_course_context(
        ) and not separate_honor_and_tos:
            current_request = crum.get_current_request()

            if not is_request_from_mobile_app(current_request):
                field_type = 'plaintext'

            pp_link = marketing_link("PRIVACY")
            label = Text(
                _(u"By creating an account with {platform_name}, you agree \
                  to abide by our {platform_name} \
                  {terms_of_service_link_start}{terms_of_service}{terms_of_service_link_end} \
                  and agree to our {privacy_policy_link_start}Privacy Policy{privacy_policy_link_end}."
                  )).format(
                      platform_name=configuration_helpers.get_value(
                          "PLATFORM_NAME", settings.PLATFORM_NAME),
                      terms_of_service=terms_label,
                      terms_of_service_link_start=HTML(
                          "<a href='{terms_url}' target='_blank'>").format(
                              terms_url=terms_link),
                      terms_of_service_link_end=HTML("</a>"),
                      privacy_policy_link_start=HTML(
                          "<a href='{pp_url}' target='_blank'>").format(
                              pp_url=pp_link),
                      privacy_policy_link_end=HTML("</a>"),
                  )

        form_desc.add_field(
            "honor_code",
            label=label,
            field_type=field_type,
            default=False,
            required=required,
            error_messages={"required": error_msg},
        )
Ejemplo n.º 23
0
def get_blocks(
        request,
        usage_key,
        user=None,
        depth=None,
        nav_depth=None,
        requested_fields=None,
        block_counts=None,
        student_view_data=None,
        return_type='dict',
        block_types_filter=None,
        hide_access_denials=False,
        allow_start_dates_in_future=False,
):
    """
    Return a serialized representation of the course blocks.

    Arguments:
        request (HTTPRequest): Used for calling django reverse.
        usage_key (UsageKey): Identifies the starting block of interest.
        user (User): Optional user object for whom the blocks are being
            retrieved. If None, blocks are returned regardless of access checks.
        depth (integer or None): Identifies the depth of the tree to return
            starting at the root block.  If None, the entire tree starting at
            the root is returned.
        nav_depth (integer): Optional parameter that indicates how far deep to
            traverse into the block hierarchy before bundling all the
            descendants for navigation.
        requested_fields (list): Optional list of names of additional fields
            to return for each block.  Supported fields are listed in
            transformers.SUPPORTED_FIELDS.
        block_counts (list): Optional list of names of block types for which to
            return an aggregate count of blocks.
        student_view_data (list): Optional list of names of block types for
            which blocks to return their student_view_data.
        return_type (string): Possible values are 'dict' or 'list'. Indicates
            the format for returning the blocks.
        block_types_filter (list): Optional list of block type names used to filter
            the final result of returned blocks.
        hide_access_denials (bool): When True, filter out any blocks that were
            denied access to the user, even if they have access denial messages
            attached.
        allow_start_dates_in_future (bool): When True, will allow blocks to be
            returned that can bypass the StartDateTransformer's filter to show
            blocks with start dates in the future.
    """

    if HIDE_ACCESS_DENIALS_FLAG.is_enabled():
        hide_access_denials = True

    # create ordered list of transformers, adding BlocksAPITransformer at end.
    transformers = BlockStructureTransformers()
    if requested_fields is None:
        requested_fields = []
    include_completion = 'completion' in requested_fields
    include_effort_estimation = (EffortEstimationTransformer.EFFORT_TIME in requested_fields or
                                 EffortEstimationTransformer.EFFORT_ACTIVITIES in requested_fields)
    include_gated_sections = 'show_gated_sections' in requested_fields
    include_has_scheduled_content = 'has_scheduled_content' in requested_fields
    include_special_exams = 'special_exam_info' in requested_fields

    if user is not None:
        transformers += course_blocks_api.get_course_block_access_transformers(user)
        transformers += [
            MilestonesAndSpecialExamsTransformer(
                include_special_exams=include_special_exams,
                include_gated_sections=include_gated_sections
            ),
            HiddenContentTransformer()
        ]

    if hide_access_denials:
        transformers += [AccessDeniedMessageFilterTransformer()]

    # TODO: Remove this after REVE-52 lands and old-mobile-app traffic falls to < 5% of mobile traffic
    if is_request_from_mobile_app(request):
        transformers += [HideEmptyTransformer()]

    if include_effort_estimation:
        transformers += [EffortEstimationTransformer()]

    transformers += [
        BlocksAPITransformer(
            block_counts,
            student_view_data,
            depth,
            nav_depth
        )
    ]

    # transform
    blocks = course_blocks_api.get_course_blocks(
        user,
        usage_key,
        transformers,
        allow_start_dates_in_future=allow_start_dates_in_future,
        include_completion=include_completion,
        include_has_scheduled_content=include_has_scheduled_content
    )

    # filter blocks by types
    if block_types_filter:
        block_keys_to_remove = []
        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type not in block_types_filter:
                block_keys_to_remove.append(block_key)
        for block_key in block_keys_to_remove:
            blocks.remove_block(block_key, keep_descendants=True)

    # serialize
    serializer_context = {
        'request': request,
        'block_structure': blocks,
        'requested_fields': requested_fields or [],
    }

    if return_type == 'dict':
        serializer = BlockDictSerializer(blocks, context=serializer_context, many=False)
    else:
        serializer = BlockSerializer(blocks, context=serializer_context, many=True)

    # return serialized data
    return serializer.data
Ejemplo n.º 24
0
 def _is_on_mobile(self):
     """Returns whether the current request is from our mobile app."""
     request = crum.get_current_request()
     return request and is_request_from_mobile_app(request)
Ejemplo n.º 25
0
def get_blocks(
        request,
        usage_key,
        user=None,
        depth=None,
        nav_depth=None,
        requested_fields=None,
        block_counts=None,
        student_view_data=None,
        return_type='dict',
        block_types_filter=None,
        hide_access_denials=False,
):
    """
    Return a serialized representation of the course blocks.

    Arguments:
        request (HTTPRequest): Used for calling django reverse.
        usage_key (UsageKey): Identifies the starting block of interest.
        user (User): Optional user object for whom the blocks are being
            retrieved. If None, blocks are returned regardless of access checks.
        depth (integer or None): Identifies the depth of the tree to return
            starting at the root block.  If None, the entire tree starting at
            the root is returned.
        nav_depth (integer): Optional parameter that indicates how far deep to
            traverse into the block hierarchy before bundling all the
            descendants for navigation.
        requested_fields (list): Optional list of names of additional fields
            to return for each block.  Supported fields are listed in
            transformers.SUPPORTED_FIELDS.
        block_counts (list): Optional list of names of block types for which to
            return an aggregate count of blocks.
        student_view_data (list): Optional list of names of block types for
            which blocks to return their student_view_data.
        return_type (string): Possible values are 'dict' or 'list'. Indicates
            the format for returning the blocks.
        block_types_filter (list): Optional list of block type names used to filter
            the final result of returned blocks.
        hide_access_denials (bool): When True, filter out any blocks that were
            denied access to the user, even if they have access denial messages
            attached.
    """

    course_blocks_namespace = WaffleFlagNamespace(name=u'course_blocks_api')
    hide_access_denials_flag = WaffleFlag(
        waffle_namespace=course_blocks_namespace,
        flag_name=u'hide_access_denials',
        flag_undefined_default=False
    )
    if hide_access_denials_flag.is_enabled():
        hide_access_denials = True

    # create ordered list of transformers, adding BlocksAPITransformer at end.
    transformers = BlockStructureTransformers()
    if requested_fields is None:
        requested_fields = []
    include_completion = 'completion' in requested_fields
    include_special_exams = 'special_exam_info' in requested_fields
    include_gated_sections = 'show_gated_sections' in requested_fields

    if user is not None:
        transformers += course_blocks_api.get_course_block_access_transformers(user)
        transformers += [
            MilestonesAndSpecialExamsTransformer(
                include_special_exams=include_special_exams,
                include_gated_sections=include_gated_sections
            ),
            HiddenContentTransformer()
        ]

    if hide_access_denials:
        transformers += [AccessDeniedMessageFilterTransformer()]

    # TODO: Remove this after REVE-52 lands and old-mobile-app traffic falls to < 5% of mobile traffic
    if is_request_from_mobile_app(request):
        transformers += [HideEmptyTransformer()]

    transformers += [
        BlocksAPITransformer(
            block_counts,
            student_view_data,
            depth,
            nav_depth
        )
    ]

    if include_completion:
        transformers += [BlockCompletionTransformer()]

    # transform
    blocks = course_blocks_api.get_course_blocks(user, usage_key, transformers)

    # filter blocks by types
    if block_types_filter:
        block_keys_to_remove = []
        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type not in block_types_filter:
                block_keys_to_remove.append(block_key)
        for block_key in block_keys_to_remove:
            blocks.remove_block(block_key, keep_descendants=True)

    # serialize
    serializer_context = {
        'request': request,
        'block_structure': blocks,
        'requested_fields': requested_fields or [],
    }

    if return_type == 'dict':
        serializer = BlockDictSerializer(blocks, context=serializer_context, many=False)
    else:
        serializer = BlockSerializer(blocks, context=serializer_context, many=True)

    # return serialized data
    return serializer.data
Ejemplo n.º 26
0
def is_from_mobile_app(request):  # pylint: disable=unused-argument
    """
    Configuration context for django templates.
    """
    return {'is_from_mobile_app': is_request_from_mobile_app(request)}
Ejemplo n.º 27
0
def get_blocks(
        request,
        usage_key,
        user=None,
        depth=None,
        nav_depth=None,
        requested_fields=None,
        block_counts=None,
        student_view_data=None,
        return_type='dict',
        block_types_filter=None,
):
    """
    Return a serialized representation of the course blocks.

    Arguments:
        request (HTTPRequest): Used for calling django reverse.
        usage_key (UsageKey): Identifies the starting block of interest.
        user (User): Optional user object for whom the blocks are being
            retrieved. If None, blocks are returned regardless of access checks.
        depth (integer or None): Identifies the depth of the tree to return
            starting at the root block.  If None, the entire tree starting at
            the root is returned.
        nav_depth (integer): Optional parameter that indicates how far deep to
            traverse into the block hierarchy before bundling all the
            descendants for navigation.
        requested_fields (list): Optional list of names of additional fields
            to return for each block.  Supported fields are listed in
            transformers.SUPPORTED_FIELDS.
        block_counts (list): Optional list of names of block types for which to
            return an aggregate count of blocks.
        student_view_data (list): Optional list of names of block types for
            which blocks to return their student_view_data.
        return_type (string): Possible values are 'dict' or 'list'. Indicates
            the format for returning the blocks.
        block_types_filter (list): Optional list of block type names used to filter
            the final result of returned blocks.
    """
    # create ordered list of transformers, adding BlocksAPITransformer at end.
    transformers = BlockStructureTransformers()
    if requested_fields is None:
        requested_fields = []
    include_completion = 'completion' in requested_fields
    include_special_exams = 'special_exam_info' in requested_fields
    include_gated_sections = 'show_gated_sections' in requested_fields

    if user is not None:
        transformers += course_blocks_api.get_course_block_access_transformers(user)
        transformers += [
            MilestonesAndSpecialExamsTransformer(
                include_special_exams=include_special_exams,
                include_gated_sections=include_gated_sections
            ),
            HiddenContentTransformer()
        ]

    # TODO: Remove this after REVE-52 lands and old-mobile-app traffic falls to < 5% of mobile traffic
    if is_request_from_mobile_app(request):
        transformers += [HideEmptyTransformer()]

    transformers += [
        BlocksAPITransformer(
            block_counts,
            student_view_data,
            depth,
            nav_depth
        )
    ]

    if include_completion:
        transformers += [BlockCompletionTransformer()]

    # transform
    blocks = course_blocks_api.get_course_blocks(user, usage_key, transformers)

    # filter blocks by types
    if block_types_filter:
        block_keys_to_remove = []
        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type not in block_types_filter:
                block_keys_to_remove.append(block_key)
        for block_key in block_keys_to_remove:
            blocks.remove_block(block_key, keep_descendants=True)

    # serialize
    serializer_context = {
        'request': request,
        'block_structure': blocks,
        'requested_fields': requested_fields or [],
    }

    if return_type == 'dict':
        serializer = BlockDictSerializer(blocks, context=serializer_context, many=False)
    else:
        serializer = BlockSerializer(blocks, context=serializer_context, many=True)

    # return serialized data
    return serializer.data