Example #1
0
    def get_message_html(self, body_html, title=None):
        """
        Returns the entire HTML snippet for the message.

        Classes that extend this base class can override the message styling
        by implementing their own version of this function. Messages that do
        not use a title can just pass the body_html.
        """
        if title:
            return Text(_('{header_open}{title}{header_close}{body}')).format(
                header_open=HTML('<div class="message-header">'),
                title=title,
                body=body_html,
                header_close=HTML('</div>')
            )
        return body_html
Example #2
0
def _register_course_goal_message(request, course):
    """
    Register a message to let a learner specify a course goal.
    """
    course_goal_options = get_course_goal_options()
    goal_choices_html = Text(
        _('To start, set a course goal by selecting the option below that best describes '
          'your learning plan. {goal_options_container}')).format(
              goal_options_container=HTML(
                  '<div class="row goal-options-container">'))

    # Add the dismissible option for users that are unsure of their goal
    goal_choices_html += Text('{initial_tag}{choice}{closing_tag}').format(
        initial_tag=HTML(
            '<div tabindex="0" aria-label="{aria_label_choice}" class="goal-option dismissible" '
            'data-choice="{goal_key}">').format(
                goal_key=GOAL_KEY_CHOICES.unsure,
                aria_label_choice=Text(_("Set goal to: {choice}")).format(
                    choice=course_goal_options[GOAL_KEY_CHOICES.unsure], ),
            ),
        choice=Text(_('{choice}')).format(
            choice=course_goal_options[GOAL_KEY_CHOICES.unsure], ),
        closing_tag=HTML('</div>'),
    )

    # Add the option to set a goal to earn a certificate,
    # complete the course or explore the course
    course_goal_keys = course_goal_options.keys()
    course_goal_keys.remove(GOAL_KEY_CHOICES.unsure)
    for goal_key in course_goal_keys:
        goal_text = course_goal_options[goal_key]
        goal_choices_html += HTML(
            '{initial_tag}{goal_text}{closing_tag}'
        ).format(initial_tag=HTML(
            '<button tabindex="0" aria-label="{aria_label_choice}" class="goal-option {col_sel} btn" '
            'data-choice="{goal_key}">').format(
                goal_key=goal_key,
                aria_label_choice=Text(_("Set goal to: {goal_text}")).format(
                    goal_text=Text(_(goal_text))),
                col_sel='col-' +
                str(int(math.floor(12 / len(course_goal_keys))))),
                 goal_text=goal_text,
                 closing_tag=HTML('</button>'))

    CourseHomeMessages.register_info_message(
        request,
        HTML('{goal_choices_html}{closing_tag}').format(
            goal_choices_html=goal_choices_html, closing_tag=HTML('</div>')),
        title=Text(_('Welcome to {course_display_name}')).format(
            course_display_name=course.display_name))
def _register_course_home_messages(request, course, user_access, course_start_data):
    """
    Register messages to be shown in the course home content page.
    """
    allow_anonymous = check_public_access(course, [COURSE_VISIBILITY_PUBLIC])

    if user_access['is_anonymous'] and not allow_anonymous:
        sign_in_or_register_text = (_(u'{sign_in_link} or {register_link} and then enroll in this course.')
                                    if not CourseMode.is_masters_only(course.id)
                                    else _(u'{sign_in_link} or {register_link}.'))
        CourseHomeMessages.register_info_message(
            request,
            Text(sign_in_or_register_text).format(
                sign_in_link=HTML(u'<a href="/login?next={current_url}">{sign_in_label}</a>').format(
                    sign_in_label=_('Sign in'),
                    current_url=urlquote_plus(request.path),
                ),
                register_link=HTML(u'<a href="/register?next={current_url}">{register_label}</a>').format(
                    register_label=_('register'),
                    current_url=urlquote_plus(request.path),
                )
            ),
            title=Text(_('You must be enrolled in the course to see course content.'))
        )
    if not user_access['is_anonymous'] and not user_access['is_staff'] and \
            not user_access['is_enrolled']:

        title = Text(_(u'Welcome to {course_display_name}')).format(
            course_display_name=course.display_name
        )

        if CourseMode.is_masters_only(course.id):
            # if a course is a Master's only course, we will not offer user ability to self-enroll
            CourseHomeMessages.register_info_message(
                request,
                Text(_('You must be enrolled in the course to see course content. '
                       'Please contact your degree administrator or edX Support if you have questions.')),
                title=title
            )
        elif not course.invitation_only:
            CourseHomeMessages.register_info_message(
                request,
                Text(_(
                    u'{open_enroll_link}Enroll now{close_enroll_link} to access the full course.'
                )).format(
                    open_enroll_link=HTML('<button class="enroll-btn btn-link">'),
                    close_enroll_link=HTML('</button>')
                ),
                title=title
            )
        else:
            CourseHomeMessages.register_info_message(
                request,
                Text(_('You must be enrolled in the course to see course content.')),
            )
Example #4
0
    def from_xml(cls, xml_data, system, id_generator):
        """
        Transforms the xml_data from <$custom_tag attr="" attr=""/> to
        <customtag attr="" attr="" impl="$custom_tag"/>
        """

        xml_object = etree.fromstring(xml_data)
        system.error_tracker(Text('WARNING: the <{tag}> tag is deprecated.  '
                             'Instead, use <customtag impl="{tag}" attr1="..." attr2="..."/>. ')
                             .format(tag=xml_object.tag))

        tag = xml_object.tag
        xml_object.tag = 'customtag'
        xml_object.attrib['impl'] = tag

        return system.process_xml(etree.tostring(xml_object))
Example #5
0
def _register_course_goal_message(request, course):
    """
    Register a message to let a learner specify a course goal.
    """
    course_goal_options = get_course_goal_options()
    goal_choices_html = Text(
        _('To start, set a course goal by selecting the option below that best describes '
          'your learning plan. {goal_options_container}')).format(
              goal_options_container=HTML(
                  '<div class="row goal-options-container">'))

    # Add the dismissible option for users that are unsure of their goal
    goal_choices_html += Text('{initial_tag}{choice}{closing_tag}').format(
        initial_tag=HTML(
            '<div tabindex="0" aria-label="{aria_label_choice}" class="goal-option dismissible" '
            'data-choice="{goal_key}">').format(
                goal_key=GOAL_KEY_CHOICES.unsure,
                aria_label_choice=Text(_("Set goal to: {choice}")).format(
                    choice=course_goal_options[GOAL_KEY_CHOICES.unsure], ),
            ),
        choice=Text(_('{choice}')).format(
            choice=course_goal_options[GOAL_KEY_CHOICES.unsure], ),
        closing_tag=HTML('</div>'),
    )

    # Add the option to set a goal to earn a certificate,
    # complete the course or explore the course
    course_goals_by_commitment_level = valid_course_goals_ordered()
    for goal in course_goals_by_commitment_level:
        goal_key, goal_text = goal
        goal_choices_html += HTML(
            '{initial_tag}{goal_text}{closing_tag}'
        ).format(
            initial_tag=HTML(
                '<button tabindex="0" aria-label="{aria_label_choice}" class="goal-option btn-outline-primary" '
                'data-choice="{goal_key}">').format(
                    goal_key=goal_key,
                    aria_label_choice=Text(
                        _("Set goal to: {goal_text}")).format(
                            goal_text=Text(_(goal_text))  # lint-amnesty, pylint: disable=translation-of-non-string
                        )),
            goal_text=goal_text,
            closing_tag=HTML('</button>'))

    CourseHomeMessages.register_info_message(
        request,
        HTML('{goal_choices_html}{closing_tag}').format(
            goal_choices_html=goal_choices_html, closing_tag=HTML('</div>')),
        title=Text(_('Welcome to {course_display_name}')).format(
            course_display_name=course.display_name))
Example #6
0
def learner_profile(request, username):
    """Render the profile page for the specified username.

    Args:
        request (HttpRequest)
        username (str): username of user whose profile is requested.

    Returns:
        HttpResponse: 200 if the page was sent successfully
        HttpResponse: 302 if not logged in (redirect to login page)
        HttpResponse: 405 if using an unsupported HTTP method
    Raises:
        Http404: 404 if the specified user is not authorized or does not exist

    Example usage:
        GET /account/profile
    """
    try:
        context = learner_profile_context(request, username, request.user.is_staff)
        # TODO: LEARNER-2554: 09/2017: Remove message and cookie logic when we no longer want this message
        message_viewed = False
        if (context['own_profile'] and
                SHOW_PROFILE_MESSAGE.is_enabled() and
                request.COOKIES.get('profile-message-viewed', '') != 'True'):
            message_text = Text(_(
                'Welcome to the new learner profile page. Your full profile now displays more '
                'information to other learners. You can instead choose to display a limited '
                'profile. {learn_more_link_start}Learn more{learn_more_link_end}'
            )).format(
                learn_more_link_start=HTML(
                    '<a href="http://edx.readthedocs.io/projects/open-edx-learner-guide/en/'
                    'latest/SFD_dashboard_profile_SectionHead.html#adding-profile-information">'
                ),
                learn_more_link_end=HTML('</a>')
            )
            PageLevelMessages.register_info_message(request, message_text, dismissable=True)
            message_viewed = True
        response = render_to_response(
            'learner_profile/learner_profile.html',
            context
        )

        if message_viewed:
            response.set_cookie('profile-message-viewed', 'True')
        return response
    except (UserNotAuthorized, UserNotFound, ObjectDoesNotExist):
        raise Http404
Example #7
0
def get_enterprise_learner_portal_enabled_message(request):
    """
    Returns message to be displayed in dashboard if the user is linked to an Enterprise with the Learner Portal enabled.

    Note: request.session[ENTERPRISE_CUSTOMER_KEY_NAME] will be used in case the user is linked to
        multiple Enterprises. Otherwise, it won't exist and the Enterprise Learner data
        will be used. If that doesn't exist return None.

    Args:
        request: request made to the LMS dashboard
    """
    enterprise_customer = enterprise_customer_from_session(request)
    if enterprise_customer is _CACHE_MISS:
        learner_data = get_enterprise_learner_data_from_db(request.user)
        enterprise_customer = learner_data[0][
            'enterprise_customer'] if learner_data else None
        # Add to session cache regardless of whether it is null
        LOGGER.info(
            '[ENTERPRISE DSC] Updating Session. User: [%s], UserAuthenticated: [%s], EnterpriseCustomer: [%s]',
            request.user.username, request.user.is_authenticated,
            enterprise_customer)
        add_enterprise_customer_to_session(request, enterprise_customer)
        if enterprise_customer:
            cache_enterprise(enterprise_customer)

    if not enterprise_customer:
        return None

    if enterprise_customer.get('enable_learner_portal', False):
        learner_portal_url = settings.ENTERPRISE_LEARNER_PORTAL_BASE_URL + '/' + enterprise_customer[
            'slug']
        return Text(
            _("Your organization {bold_start}{enterprise_customer_name}{bold_end} uses a custom dashboard for learning. "
              "{link_start}Click here {screen_reader_start}for your {enterprise_customer_name} dashboard,"
              "{screen_reader_end}{link_end} to continue in that experience.")
        ).format(
            enterprise_customer_name=enterprise_customer['name'],
            link_start=HTML("<a href='{learner_portal_url}'>").format(
                learner_portal_url=learner_portal_url, ),
            link_end=HTML("</a>"),
            bold_start=HTML("<b>"),
            bold_end=HTML("</b>"),
            screen_reader_start=HTML("<span class='sr-only'>"),
            screen_reader_end=HTML("</span>"),
        )
    else:
        return None
Example #8
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 terms of service and honor code checkboxes
        if self._is_field_visible("terms_of_service"):
            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
        )

        form_desc.add_field(
            "honor_code",
            label=label,
            field_type="checkbox",
            default=False,
            required=required,
            error_messages={
                "required": error_msg
            },
        )
Example #9
0
def _do_third_party_auth(request):
    """
    User is already authenticated via 3rd party, now try to find and return their associated Django user.
    """
    running_pipeline = pipeline.get(request)
    username = running_pipeline['kwargs'].get('username')
    backend_name = running_pipeline['backend']
    third_party_uid = running_pipeline['kwargs']['uid']
    requested_provider = provider.Registry.get_from_pipeline(running_pipeline)
    platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)

    try:
        return pipeline.get_authenticated_user(requested_provider, username, third_party_uid)
    except User.DoesNotExist:
        AUDIT_LOG.info(
            u"Login failed - user with username {username} has no social auth "
            "with backend_name {backend_name}".format(
                username=username, backend_name=backend_name)
        )
        message = _(
            "You've successfully logged into your {provider_name} account, "
            "but this account isn't linked with an {platform_name} account yet."
        ).format(
            platform_name=platform_name,
            provider_name=requested_provider.name,
        )
        message += "<br/><br/>"
        message += _(
            "Use your {platform_name} username and password to log into {platform_name} below, "
            "and then link your {platform_name} account with {provider_name} from your dashboard."
        ).format(
            platform_name=platform_name,
            provider_name=requested_provider.name,
        )
        message += "<br/><br/>"
        message += Text(_(
            "If you don't have an {platform_name} account yet, "
            "click {register_label_strong} at the top of the page."
        )).format(
            platform_name=platform_name,
            register_label_strong=HTML('<strong>{register_text}</strong>').format(
                register_text=_('Register')
            )
        )

        raise AuthFailedError(message)
def _section_course_info(course, access):
    """ Provide data for the corresponding dashboard section """
    course_key = course.id

    section_data = {
        'section_key': 'course_info',
        'section_display_name': _('Course Info'),
        'access': access,
        'course_id': course_key,
        'course_display_name': course.display_name_with_default,
        'course_org': course.display_org_with_default,
        'course_number': course.display_number_with_default,
        'has_started': course.has_started(),
        'has_ended': course.has_ended(),
        'start_date': course.start,
        'end_date': course.end,
        'num_sections': len(course.children),
        'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': str(course_key)}),
    }

    if settings.FEATURES.get('DISPLAY_ANALYTICS_ENROLLMENTS'):
        section_data['enrollment_count'] = CourseEnrollment.objects.enrollment_counts(course_key)

    if show_analytics_dashboard_message(course_key):
        #  dashboard_link is already made safe in _get_dashboard_link
        dashboard_link = _get_dashboard_link(course_key)
        #  so we can use Text() here so it's not double-escaped and rendering HTML on the front-end
        message = Text(
            _("Enrollment data is now available in {dashboard_link}.")
        ).format(dashboard_link=dashboard_link)
        section_data['enrollment_message'] = message

    try:
        sorted_cutoffs = sorted(list(course.grade_cutoffs.items()), key=lambda i: i[1], reverse=True)
        advance = lambda memo, letter_score_tuple: f"{letter_score_tuple[0]}: {letter_score_tuple[1]}, " \
                                                   + memo
        section_data['grade_cutoffs'] = reduce(advance, sorted_cutoffs, "")[:-2]
    except Exception:  # pylint: disable=broad-except
        section_data['grade_cutoffs'] = "Not Available"

    try:
        section_data['course_errors'] = [(escape(a), '') for (a, _unused) in modulestore().get_course_errors(course.id)]
    except Exception:  # pylint: disable=broad-except
        section_data['course_errors'] = [('Error fetching errors', '')]

    return section_data
Example #11
0
    def test_programs_displayed(self):
        """Verify that the programs tab and creation button can be rendered when config is enabled."""

        # When no data is provided, expect creation prompt.
        self.create_programs_config()
        self.mock_programs_api(data={'results': []})

        response = self.client.get(self.studio_home)
        self.assertIn(Text("You haven't created any programs yet."),
                      response.content)

        # When data is provided, expect a program listing.
        self.mock_programs_api()

        response = self.client.get(self.studio_home)
        for program_name in self.PROGRAM_NAMES:
            self.assertIn(program_name, response.content)
Example #12
0
    def render(self, request):
        """
        Render the index page.
        """
        self._redirect_if_needed_to_pay_for_course()
        self._prefetch_and_bind_course(request)

        if self.course.has_children_at_depth(CONTENT_DEPTH):
            self._reset_section_to_exam_if_required()
            self.chapter = self._find_chapter()
            self.section = self._find_section()

            if self.chapter and self.section:
                self._redirect_if_not_requested_section()
                self._save_positions()
                self._prefetch_and_bind_section()

            check_content_start_date_for_masquerade_user(self.course_key, self.effective_user, request,
                                                         self.course.start, self.chapter.start, self.section.start)

        if not request.user.is_authenticated:
            qs = six.moves.urllib.parse.urlencode({
                'course_id': self.course_key,
                'enrollment_action': 'enroll',
                'email_opt_in': False,
            })

            allow_anonymous = allow_public_access(self.course, [COURSE_VISIBILITY_PUBLIC])

            if not allow_anonymous:
                PageLevelMessages.register_warning_message(
                    request,
                    Text(_(u"You are not signed in. To see additional course content, {sign_in_link} or "
                           u"{register_link}, and enroll in this course.")).format(
                        sign_in_link=HTML(u'<a href="{url}">{sign_in_label}</a>').format(
                            sign_in_label=_('sign in'),
                            url='{}?{}'.format(reverse('signin_user'), qs),
                        ),
                        register_link=HTML(u'<a href="/{url}">{register_label}</a>').format(
                            register_label=_('register'),
                            url=u'{}?{}'.format(reverse('register_user'), qs),
                        ),
                    )
                )

        return render_to_response('courseware/courseware.html', self._create_courseware_context(request))
Example #13
0
def get_enterprise_sidebar_context(enterprise_customer):
    """
    Get context information for enterprise sidebar for the given enterprise customer.

    Enterprise Sidebar Context has the following key-value pairs.
    {
        'enterprise_name': 'Enterprise Name',
        'enterprise_logo_url': 'URL of the enterprise logo image',
        'enterprise_branded_welcome_string': 'Human readable welcome message customized for the enterprise',
        'platform_welcome_string': 'Human readable welcome message for an enterprise learner',
    }
    """
    platform_name = configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)

    branding_configuration = enterprise_customer.get('branding_configuration', {})
    logo_url = branding_configuration.get('logo', '') if isinstance(branding_configuration, dict) else ''

    branded_welcome_template = configuration_helpers.get_value(
        'ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE',
        settings.ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE
    )

    branded_welcome_string = Text(branded_welcome_template).format(
        start_bold=HTML('<b>'),
        end_bold=HTML('</b>'),
        line_break=HTML('<br/>'),
        enterprise_name=enterprise_customer['name'],
        platform_name=platform_name,
        privacy_policy_link_start=HTML("<a href='{pp_url}' target='_blank'>").format(
            pp_url=settings.MKTG_URLS.get('PRIVACY', 'https://www.edx.org/edx-privacy-policy')
        ),
        privacy_policy_link_end=HTML("</a>"),
    )

    platform_welcome_template = configuration_helpers.get_value(
        'ENTERPRISE_PLATFORM_WELCOME_TEMPLATE',
        settings.ENTERPRISE_PLATFORM_WELCOME_TEMPLATE
    )
    platform_welcome_string = platform_welcome_template.format(platform_name=platform_name)

    return {
        'enterprise_name': enterprise_customer['name'],
        'enterprise_logo_url': logo_url,
        'enterprise_branded_welcome_string': branded_welcome_string,
        'platform_welcome_string': platform_welcome_string,
    }
Example #14
0
    def render(self, request):
        """
        Render the index page.
        """
        self._redirect_if_needed_to_enter_university_id()
        self._redirect_if_needed_to_pay_for_course()
        self._prefetch_and_bind_course(request)

        if self.course.has_children_at_depth(CONTENT_DEPTH):
            self._reset_section_to_exam_if_required()
            self.chapter = self._find_chapter()
            self.section = self._find_section()

            if self.chapter and self.section:
                self._redirect_if_not_requested_section()
                self._save_positions()
                self._prefetch_and_bind_section()

        if not request.user.is_authenticated:
            qs = urllib.urlencode({
                'course_id': self.course_key,
                'enrollment_action': 'enroll',
                'email_opt_in': False,
            })

            PageLevelMessages.register_warning_message(
                request,
                Text(
                    _("You are not signed in. To see additional course content, {sign_in_link} or "
                      "{register_link}, and enroll in this course.")).format(
                          sign_in_link=HTML(
                              '<a href="{url}">{sign_in_label}</a>').format(
                                  sign_in_label=_('sign in'),
                                  url='{}?{}'.format(reverse('signin_user'),
                                                     qs),
                              ),
                          register_link=HTML(
                              '<a href="/{url}">{register_label}</a>').format(
                                  register_label=_('register'),
                                  url='{}?{}'.format(reverse('register_user'),
                                                     qs),
                              ),
                      ))

        return render_to_response('courseware/courseware.html',
                                  self._create_courseware_context(request))
Example #15
0
    def from_xml(cls, xml_data, system, id_generator):
        """
        Removes sections with single child elements in favor of just embedding
        the child element
        """
        xml_object = etree.fromstring(xml_data)
        system.error_tracker(Text("WARNING: the <{tag}> tag is deprecated.  Please do not use in new content.")
                             .format(tag=xml_object.tag))

        if len(xml_object) == 1:
            for (key, val) in xml_object.items():
                xml_object[0].set(key, val)

            return system.process_xml(etree.tostring(xml_object[0]))
        else:
            xml_object.tag = 'sequential'
            return system.process_xml(etree.tostring(xml_object))
def _handle_failed_authentication(user, authenticated_user):
    """
    Handles updating the failed login count, inactive user notifications, and logging failed authentications.
    """
    if user:
        if LoginFailures.is_feature_enabled():
            LoginFailures.increment_lockout_counter(user)

        if authenticated_user and not user.is_active:
            _log_and_raise_inactive_user_auth_error(user)

        # if we didn't find this username earlier, the account for this email
        # doesn't exist, and doesn't have a corresponding password
        loggable_id = user.id if user else "<unknown>"
        AUDIT_LOG.warning(f"Login failed - password for user.id: {loggable_id} is invalid")

    if user and LoginFailures.is_feature_enabled():
        blocked_threshold, failure_count = LoginFailures.check_user_reset_password_threshold(user)
        if blocked_threshold:
            if not LoginFailures.is_user_locked_out(user):
                max_failures_allowed = settings.MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED
                remaining_attempts = max_failures_allowed - failure_count
                error_message = Text(_('Email or password is incorrect.'
                                       '{li_start}You have {remaining_attempts} more sign-in '
                                       'attempts before your account is temporarily locked.{li_end}'
                                       '{li_start}If you\'ve forgotten your password, click '
                                       '{link_start}here{link_end} to reset.{li_end}')).format(
                                           link_start=HTML(
                                               '<a http="#login" class="form-toggle" data-type="password-reset">'
                                           ),
                                           link_end=HTML('</a>'),
                                           li_start=HTML('<li>'),
                                           li_end=HTML('</li>'),
                                           remaining_attempts=remaining_attempts)
                raise AuthFailedError(
                    error_message,
                    error_code='failed-login-attempt',
                    context={
                        'remaining_attempts': remaining_attempts,
                    }
                )

            _generate_locked_out_error_message()

    raise AuthFailedError(_('Email or password is incorrect.'), error_code='incorrect-email-or-password')
Example #17
0
def _section_course_info(course, access):
    """ Provide data for the corresponding dashboard section """
    course_key = course.id

    section_data = {
        'section_key': 'course_info',
        'section_display_name': _('Course Info'),
        'access': access,
        'course_id': course_key,
        'course_display_name': course.display_name,
        'has_started': course.has_started(),
        'has_ended': course.has_ended(),
        'start_date': get_default_time_display(course.start),
        'end_date': get_default_time_display(course.end) or _('No end date set'),
        'num_sections': len(course.children),
        'list_instructor_tasks_url': reverse('list_instructor_tasks', kwargs={'course_id': unicode(course_key)}),
    }

    if settings.FEATURES.get('DISPLAY_ANALYTICS_ENROLLMENTS'):
        section_data['enrollment_count'] = CourseEnrollment.objects.enrollment_counts(course_key)

    if settings.ANALYTICS_DASHBOARD_URL:
        #  dashboard_link is already made safe in _get_dashboard_link
        dashboard_link = _get_dashboard_link(course_key)
        #  so we can use Text() here so it's not double-escaped and rendering HTML on the front-end
        message = Text(_("Enrollment data is now available in {dashboard_link}.")).format(dashboard_link=dashboard_link)
        section_data['enrollment_message'] = message

    if settings.FEATURES.get('ENABLE_SYSADMIN_DASHBOARD'):
        section_data['detailed_gitlogs_url'] = reverse('gitlogs_detail', kwargs={'course_id': unicode(course_key)})

    try:
        sorted_cutoffs = sorted(course.grade_cutoffs.items(), key=lambda i: i[1], reverse=True)
        advance = lambda memo, (letter, score): "{}: {}, ".format(letter, score) + memo
        section_data['grade_cutoffs'] = reduce(advance, sorted_cutoffs, "")[:-2]
    except Exception:  # pylint: disable=broad-except
        section_data['grade_cutoffs'] = "Not Available"
    # section_data['offline_grades'] = offline_grades_available(course_key)

    try:
        section_data['course_errors'] = [(escape(a), '') for (a, _unused) in modulestore().get_course_errors(course.id)]
    except Exception:  # pylint: disable=broad-except
        section_data['course_errors'] = [('Error fetching errors', '')]

    return section_data
    def student_view(self, context=None):
        """
        Renders student view for LMS.
        """
        fragment = Fragment()

        self.add_resource_urls(fragment)

        login_msg = ''

        if not self.django_user.is_authenticated():
            qs = urllib.urlencode({
                'course_id': self.course_key,
                'enrollment_action': 'enroll',
                'email_opt_in': False,
            })
            login_msg = Text(_("You are not signed in. To view the discussion content, {sign_in_link} or "
                               "{register_link}, and enroll in this course.")).format(
                sign_in_link=HTML('<a href="{url}">{sign_in_label}</a>').format(
                    sign_in_label=_('sign in'),
                    url='{}?{}'.format(reverse('signin_user'), qs),
                ),
                register_link=HTML('<a href="/{url}">{register_label}</a>').format(
                    register_label=_('register'),
                    url='{}?{}'.format(reverse('register_user'), qs),
                ),
            )

        context = {
            'discussion_id': self.discussion_id,
            'display_name': self.display_name if self.display_name else _("Discussion"),
            'user': self.django_user,
            'course_id': self.course_key,
            'discussion_category': self.discussion_category,
            'discussion_target': self.discussion_target,
            'can_create_thread': self.has_permission("create_thread"),
            'can_create_comment': self.has_permission("create_comment"),
            'can_create_subcomment': self.has_permission("create_sub_comment"),
            'login_msg': login_msg,
        }

        fragment.add_content(self.runtime.render_template('discussion/_discussion_inline.html', context))
        fragment.initialize_js('DiscussionInlineBlock')

        return fragment
Example #19
0
    def definition_to_xml(self, resource_fs):
        xml_object = etree.Element(self._tag_name)
        for child in self.get_children():
            if child.location not in self.show_tag_list:
                self.runtime.add_block_as_child_node(child, xml_object)

        if self.show_tag_list:
            show_str = HTML(u'<show sources="{sources}" />').format(
                sources=Text(';'.join(text_type(location) for location in self.show_tag_list)))
            xml_object.append(etree.fromstring(show_str))

        # Overwrite the original sources attribute with the value from sources_list, as
        # Locations may have been changed to Locators.
        stringified_sources_list = [text_type(loc) for loc in self.sources_list]
        self.xml_attributes['sources'] = ';'.join(stringified_sources_list)
        self.xml_attributes[self.conditional_attr] = self.conditional_value
        self.xml_attributes['message'] = self.conditional_message
        return xml_object
Example #20
0
    def test_enterprise_register(self, url_name, ec_present, ec_name, logo_url, is_proxy, mock_get_ec):
        """
        Verify that when an EnterpriseCustomer is received on the login and register views,
        the appropriate sidebar is rendered.
        """
        if ec_present:
            mock_get_ec.return_value = {
                'name': ec_name,
                'branding_configuration': {'logo': logo_url}
            }
        else:
            mock_get_ec.return_value = None

        params = []
        if is_proxy:
            params.append(("proxy_login", "True"))

        response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html")

        enterprise_sidebar_div_id = 'enterprise-content-container'

        if not ec_present:
            self.assertNotContains(response, text=enterprise_sidebar_div_id)
        else:
            self.assertContains(response, text=enterprise_sidebar_div_id)
            if is_proxy:
                welcome_message = settings.ENTERPRISE_PROXY_LOGIN_WELCOME_TEMPLATE
            else:
                welcome_message = settings.ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE
            expected_message = Text(welcome_message).format(
                start_bold=HTML('<b>'),
                end_bold=HTML('</b>'),
                line_break=HTML('<br/>'),
                enterprise_name=ec_name,
                platform_name=settings.PLATFORM_NAME,
                privacy_policy_link_start=HTML("<a href='{pp_url}' rel='noopener' target='_blank'>").format(
                    pp_url=get_privacy_url()
                ),
                privacy_policy_link_end=HTML("</a>"),
            )
            self.assertContains(response, expected_message)
            if logo_url:
                self.assertContains(response, logo_url)
Example #21
0
    def _add_marketing_consent_field(self, form_desc, required=False):
        """Add a marketing email consent field to a form description.
        Arguments:
            form_desc: A form description
        Keyword Arguments:
            required (bool): Whether this field is required; defaults to True
        """

        label = Text(
            _(u"I agree to receiving emails from Edraak team about product updates, recommended courses for me, and news"
              ))

        field_type = 'checkbox'

        form_desc.add_field("marketing_consent",
                            label=label,
                            field_type=field_type,
                            default=False,
                            required=required)
Example #22
0
 def process_request(self, request):  # lint-amnesty, pylint: disable=missing-function-docstring
     user = request.user
     try:
         user_account = UserStanding.objects.get(user=user.id)
         # because user is a unique field in UserStanding, there will either be
         # one or zero user_accounts associated with a UserStanding
     except UserStanding.DoesNotExist:
         pass
     else:
         if user_account.account_status == UserStanding.ACCOUNT_DISABLED:
             msg = Text(
                 _('Your account has been disabled. If you believe '
                   'this was done in error, please contact us at '
                   '{support_email}')
             ).format(support_email=HTML(
                 '<a href="mailto:{address}?subject={subject_line}">{address}</a>'
             ).format(
                 address=settings.DEFAULT_FEEDBACK_EMAIL,
                 subject_line=_('Disabled Account'),
             ), )
             return HttpResponseForbidden(msg)
Example #23
0
    def test_enterprise_register(self, url_name, ec_present, ec_name, logo_url,
                                 mock_get_ec):
        """
        Verify that when an EnterpriseCustomer is received on the login and register views,
        the appropriate sidebar is rendered.
        """
        if ec_present:
            mock_get_ec.return_value = {
                'name': ec_name,
                'branding_configuration': {
                    'logo': logo_url
                }
            }
        else:
            mock_get_ec.return_value = None

        response = self.client.get(reverse(url_name), HTTP_ACCEPT="text/html")

        enterprise_sidebar_div_id = u'enterprise-content-container'

        if not ec_present:
            self.assertNotContains(response, text=enterprise_sidebar_div_id)
        else:
            self.assertContains(response, text=enterprise_sidebar_div_id)
            welcome_message = settings.ENTERPRISE_SPECIFIC_BRANDED_WELCOME_TEMPLATE
            expected_message = Text(welcome_message).format(
                start_bold=HTML('<b>'),
                end_bold=HTML('</b>'),
                line_break=HTML('<br/>'),
                enterprise_name=ec_name,
                platform_name=settings.PLATFORM_NAME,
                privacy_policy_link_start=HTML(
                    "<a href='{pp_url}' target='_blank'>").
                format(pp_url=settings.MKTG_URLS.get(
                    'PRIVACY', 'https://www.edx.org/edx-privacy-policy')),
                privacy_policy_link_end=HTML("</a>"),
            )
            self.assertContains(response, expected_message)
            if logo_url:
                self.assertContains(response, logo_url)
Example #24
0
def _check_user_auth_flow(site, user):
    """
    Check if user belongs to an allowed domain and not whitelisted
    then ask user to login through allowed domain SSO provider.
    """
    if user and ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY.is_enabled():
        allowed_domain = site.configuration.get_value(
            'THIRD_PARTY_AUTH_ONLY_DOMAIN', '').lower()
        email_parts = user.email.split('@')
        if len(email_parts) != 2:
            # User has a nonstandard email so we record their id.
            # we don't record their e-mail in case there is sensitive info accidentally
            # in there.
            set_custom_attribute('login_tpa_domain_shortcircuit_user_id',
                                 user.id)
            log.warn(
                "User %s has nonstandard e-mail. Shortcircuiting THIRD_PART_AUTH_ONLY_DOMAIN check.",
                user.id)
            return
        user_domain = email_parts[1].strip().lower()

        # If user belongs to allowed domain and not whitelisted then user must login through allowed domain SSO
        if user_domain == allowed_domain and not AllowedAuthUser.objects.filter(
                site=site, email=user.email).exists():
            msg = Text(
                _(u'As {allowed_domain} user, You must login with your {allowed_domain} '
                  u'{link_start}{provider} account{link_end}.')
            ).format(
                allowed_domain=allowed_domain,
                link_start=HTML("<a href='{tpa_provider_link}'>").format(
                    tpa_provider_link='{dashboard_url}?tpa_hint={tpa_hint}'.
                    format(
                        dashboard_url=reverse('dashboard'),
                        tpa_hint=site.configuration.get_value(
                            'THIRD_PARTY_AUTH_ONLY_HINT'),
                    )),
                provider=site.configuration.get_value(
                    'THIRD_PARTY_AUTH_ONLY_PROVIDER'),
                link_end=HTML("</a>"))
            raise AuthFailedError(msg)
Example #25
0
def _create_message(site, root_url, allowed_domain):
    """
    Helper function to create error message for those users that belongs
    to an allowed domain and not whitelisted then ask such users to login
    through allowed domain SSO provider.
    """
    msg = Text(
        _(u'As {allowed_domain} user, You must login with your {allowed_domain} '
          u'{link_start}{provider} account{link_end}.')
    ).format(
        allowed_domain=allowed_domain,
        link_start=HTML("<a href='{root_url}{tpa_provider_link}'>").format(
            root_url=root_url if root_url else '',
            tpa_provider_link='{dashboard_url}?tpa_hint={tpa_hint}'.format(
                dashboard_url=reverse('dashboard'),
                tpa_hint=site.configuration.get_value(
                    'THIRD_PARTY_AUTH_ONLY_HINT'),
            )),
        provider=site.configuration.get_value(
            'THIRD_PARTY_AUTH_ONLY_PROVIDER'),
        link_end=HTML("</a>"))
    return msg
Example #26
0
def _generate_locked_out_error_message():
    """
    Helper function to generate error message for users consumed all
    login attempts.
    """

    locked_out_period_in_sec = settings.MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS
    error_message = Text(
        _('To protect your account, it’s been temporarily '
          'locked. Try again in {locked_out_period} minutes.'
          '{li_start}To be on the safe side, you can reset your '
          'password {link_start}here{link_end} before you try again.')
    ).format(link_start=HTML(
        '<a http="#login" class="form-toggle" data-type="password-reset">'),
             link_end=HTML('</a>'),
             li_start=HTML('<li>'),
             li_end=HTML('</li>'),
             locked_out_period=int(locked_out_period_in_sec / 60))
    raise AuthFailedError(
        error_message,
        error_code='account-locked-out',
        context={'locked_out_period': int(locked_out_period_in_sec / 60)})
Example #27
0
def register_course_expired_message(request, course):
    """
    Add a banner notifying the user of the user course expiration date if it exists.
    """
    if not CourseDurationLimitConfig.enabled_for_enrollment(
            user=request.user, course_key=course.id):
        return

    expiration_date = get_user_course_expiration_date(request.user, course)
    if not expiration_date:
        return

    if is_masquerading_as_student(
            request.user, course.id) and timezone.now() > expiration_date:
        upgrade_message = _(
            'This learner would not have access to this course. '
            'Their access expired on {expiration_date}.')
        PageLevelMessages.register_warning_message(
            request,
            HTML(upgrade_message).format(
                expiration_date=expiration_date.strftime('%b %-d')))
    else:
        upgrade_message = _(
            'Your access to this course expires on {expiration_date}. \
                    {a_open}Upgrade now {sronly_span_open}to retain access past {expiration_date}.\
                    {span_close}{a_close}{sighted_only_span_open}for unlimited access.{span_close}'
        )
        PageLevelMessages.register_info_message(
            request,
            Text(upgrade_message).format(
                a_open=HTML('<a href="{upgrade_link}">').format(
                    upgrade_link=verified_upgrade_deadline_link(
                        user=request.user, course=course)),
                sronly_span_open=HTML('<span class="sr-only">'),
                sighted_only_span_open=HTML('<span aria-hidden="true">'),
                span_close=HTML('</span>'),
                a_close=HTML('</a>'),
                expiration_date=expiration_date.strftime('%b %-d'),
            ))
Example #28
0
def test_get_admin_details(admin_type, adg_admin, bu_admin):
    """
    Test that `get_admin_details` function returns the correct admin details.
    """
    if admin_type == ADG_ADMIN_DISPLAY_STRING:
        admin = adg_admin
        UserProfileFactory(user=admin)
        permission = 'ADG Admin'
    else:
        admin = bu_admin
        UserProfileFactory(user=admin)
        permission = f'BU Admin of {admin.business_unit.title}'

    expected_permission = Text(
        '{name}, {span_start}{permission}{span_end}').format(
            name=admin.profile.name,
            span_start=HTML(SPAN_START),
            permission=permission,
            span_end=HTML(SPAN_END),
        )
    details = get_admin_details(admin)

    assert details['permission'] == expected_permission
Example #29
0
def generate_offer_html(user, course):
    """
    Create the actual HTML object with the offer text in it.

    Returns a openedx.core.djangolib.markup.HTML object, or None if the user
    should not be shown an offer message.
    """
    data = generate_offer_data(user, course)
    if not data:
        return None

    # Translator: xgettext:no-python-format
    offer_message = _(
        '{banner_open} Upgrade by {discount_expiration_date} and save {percentage}% '
        '[{strikeout_price}]{span_close}{br}Use code {b_open}{code}{b_close} at checkout! '
        '{a_open}Upgrade Now{a_close}{div_close}')

    message_html = HTML(offer_message).format(
        a_open=HTML('<a id="welcome" href="{upgrade_link}">').format(
            upgrade_link=data['upgrade_url']),
        a_close=HTML('</a>'),
        b_open=HTML('<b>'),
        code=Text(data['code']),
        b_close=HTML('</b>'),
        br=HTML('<br>'),
        banner_open=HTML(
            '<div class="first-purchase-offer-banner" role="note">'
            '<span class="first-purchase-offer-banner-bold"><b>'),
        discount_expiration_date=strftime_localized_html(
            data['expiration_date'], 'SHORT_DATE'),
        percentage=data['percentage'],
        span_close=HTML('</b></span>'),
        div_close=HTML('</div>'),
        strikeout_price=_format_discounted_price(data['original_price'],
                                                 data['discounted_price']),
    )
    return message_html
Example #30
0
def get_enterprise_learner_portal_enabled_message(request):
    """
    Returns message to be displayed in dashboard if the user is linked to an Enterprise with the Learner Portal enabled.

    Note: request.session['enterprise_customer'] will be used in case the user is linked to
        multiple Enterprises. Otherwise, it won't exist and the Enterprise Learner data
        will be used. If that doesn't exist return None.

    Args:
        request: request made to the LMS dashboard
    """
    if 'enterprise_customer' in request.session and request.session[
            'enterprise_customer']:
        enterprise_customer = request.session['enterprise_customer']
    else:
        learner_data = get_enterprise_learner_data(request.user)
        if learner_data:
            enterprise_customer = learner_data[0]['enterprise_customer']
        else:
            return None

    if enterprise_customer['enable_learner_portal']:
        learner_portal_url = settings.ENTERPRISE_LEARNER_PORTAL_BASE_URL + '/' + enterprise_customer[
            'slug']
        return Text(
            _("Your organization {bold_start}{enterprise_customer_name}{bold_end} uses a custom dashboard for learning. "
              "{link_start}Click here{link_end} to continue in that experience."
              )).format(
                  enterprise_customer_name=enterprise_customer['name'],
                  link_start=HTML("<a href='{learner_portal_url}'>").format(
                      learner_portal_url=learner_portal_url, ),
                  link_end=HTML("</a>"),
                  bold_start=HTML("<b>"),
                  bold_end=HTML("</b>"),
              )
    else:
        return None