Add message for setting course goal.
LEARNER-2307
This commit is contained in:
committed by
Robert Raposa
parent
a58df6c0fa
commit
bc76ffe5dc
@@ -166,4 +166,5 @@ class IsStaffOrOwner(permissions.BasePermission):
|
||||
return user.is_staff \
|
||||
or (user.username == request.GET.get('username')) \
|
||||
or (user.username == getattr(request, 'data', {}).get('username')) \
|
||||
or (user.username == getattr(request, 'data', {}).get('user')) \
|
||||
or (user.username == getattr(view, 'kwargs', {}).get('username'))
|
||||
|
||||
@@ -16,15 +16,18 @@ COURSE_OUTLINE_PAGE_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'course_outli
|
||||
# Waffle flag to enable a single unified "Course" tab.
|
||||
UNIFIED_COURSE_TAB_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'unified_course_tab')
|
||||
|
||||
# Waffle flag to enable the sock on the footer of the home and courseware pages
|
||||
# Waffle flag to enable the sock on the footer of the home and courseware pages.
|
||||
DISPLAY_COURSE_SOCK_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'display_course_sock')
|
||||
|
||||
# Waffle flag to let learners access a course before its start date
|
||||
# Waffle flag to let learners access a course before its start date.
|
||||
COURSE_PRE_START_ACCESS_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'pre_start_access')
|
||||
|
||||
# Waffle flag to enable a review page link from the unified home page
|
||||
# Waffle flag to enable a review page link from the unified home page.
|
||||
SHOW_REVIEWS_TOOL_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'show_reviews_tool')
|
||||
|
||||
# Waffle flag to enable the setting of course goals.
|
||||
ENABLE_COURSE_GOALS = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'enable_course_goals')
|
||||
|
||||
SHOW_UPGRADE_MSG_ON_COURSE_HOME = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'show_upgrade_msg_on_course_home')
|
||||
|
||||
# Waffle flag to switch between the 'welcome message' and 'latest update' on the course home page.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* globals gettext */
|
||||
|
||||
export class CourseGoals { // eslint-disable-line import/prefer-default-export
|
||||
|
||||
constructor(options) {
|
||||
$('.goal-option').click((e) => {
|
||||
const goalKey = $(e.target).data().choice;
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: options.goalApiUrl,
|
||||
headers: { 'X-CSRFToken': $.cookie('csrftoken') },
|
||||
data: {
|
||||
goal_key: goalKey,
|
||||
course_key: options.courseId,
|
||||
user: options.username,
|
||||
},
|
||||
dataType: 'json',
|
||||
success: () => {
|
||||
// LEARNER-2522 will address the success message
|
||||
const successMsg = gettext('Thank you for setting your course goal!');
|
||||
// xss-lint: disable=javascript-jquery-html
|
||||
$('.message-content').html(`<div class="success-message">${successMsg}</div>`);
|
||||
},
|
||||
error: () => {
|
||||
// LEARNER-2522 will address the error message
|
||||
const errorMsg = gettext('There was an error in setting your goal, please reload the page and try again.'); // eslint-disable-line max-len
|
||||
// xss-lint: disable=javascript-jquery-html
|
||||
$('.message-content').html(`<div class="error-message"> ${errorMsg} </div>`);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Allow goal selection with an enter press for accessibility purposes
|
||||
$('.goal-option').keyup((e) => {
|
||||
if (e.which === 13) {
|
||||
$(e.target).trigger('click');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,18 @@ export class CourseHome { // eslint-disable-line import/prefer-default-export
|
||||
);
|
||||
});
|
||||
|
||||
// Dismissibility for in course messages
|
||||
$(document.body).on('click', '.course-message .dismiss', (event) => {
|
||||
$(event.target).closest('.course-message').hide();
|
||||
});
|
||||
|
||||
// Allow dismiss on enter press for accessibility purposes
|
||||
$(document.body).on('keyup', '.course-message .dismiss', (event) => {
|
||||
if (event.which === 13) {
|
||||
$(event.target).trigger('click');
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(() => {
|
||||
this.configureUpgradeMessage();
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ export class CourseSock { // eslint-disable-line import/prefer-default-export
|
||||
const startFixed = $verificationSock.offset().top + 320;
|
||||
const endFixed = (startFixed + $verificationSock.height()) - 220;
|
||||
|
||||
// Assure update button stays in sock even when max-width is exceeded
|
||||
// Ensure update button stays in sock even when max-width is exceeded
|
||||
const distLeft = ($verificationSock.offset().left + $verificationSock.width())
|
||||
- ($upgradeToVerifiedButton.width() + 22);
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
<%!
|
||||
from django.utils.translation import get_language_bidi
|
||||
from django.utils.translation import ugettext as _
|
||||
from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
from openedx.core.djangolib.markup import HTML
|
||||
from openedx.features.course_experience import CourseHomeMessages
|
||||
%>
|
||||
@@ -17,14 +19,22 @@ is_rtl = get_language_bidi()
|
||||
% for message in course_home_messages:
|
||||
<div class="course-message grid-manual">
|
||||
% if not is_rtl:
|
||||
<img class="message-author col col-2" src="${static.url(image_src)}"/>
|
||||
<img class="message-author" alt="${_('Course message author')}" role="none" src="${static.url(image_src)}"/>
|
||||
% endif
|
||||
<div class="message-content col col-9">
|
||||
<div class="message-content">
|
||||
${HTML(message.message_html)}
|
||||
</div>
|
||||
% if is_rtl:
|
||||
<img class="message-author col col-2" src="${static.url(image_src)}"/>
|
||||
<img class="message-author" alt="${_('Course message author')}" role="none" src="${static.url(image_src)}"/>
|
||||
% endif
|
||||
</div>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
<%static:webpack entry="CourseGoals">
|
||||
new CourseGoals({
|
||||
goalApiUrl: "${goal_api_url | n, js_escaped_string}",
|
||||
courseId: "${course_id | n, js_escaped_string}",
|
||||
username: "${username | n, js_escaped_string}",
|
||||
});
|
||||
</%static:webpack>
|
||||
|
||||
@@ -16,6 +16,7 @@ from waffle.testutils import override_flag
|
||||
|
||||
from commerce.models import CommerceConfiguration
|
||||
from commerce.utils import EcommerceService
|
||||
from lms.djangoapps.course_goals.api import add_course_goal, remove_course_goal
|
||||
from course_modes.models import CourseMode
|
||||
from courseware.tests.factories import StaffFactory
|
||||
from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES, override_waffle_flag
|
||||
@@ -25,14 +26,14 @@ from openedx.features.course_experience import (
|
||||
UNIFIED_COURSE_TAB_FLAG
|
||||
)
|
||||
from student.models import CourseEnrollment
|
||||
from student.tests.factories import UserFactory
|
||||
from student.tests.factories import UserFactory, CourseEnrollmentFactory
|
||||
from util.date_utils import strftime_localized
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.tests.django_utils import CourseUserType, ModuleStoreTestCase, SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls
|
||||
from .helpers import add_course_mode
|
||||
from .test_course_updates import create_course_update, remove_course_updates
|
||||
from ... import COURSE_PRE_START_ACCESS_FLAG
|
||||
from ... import COURSE_PRE_START_ACCESS_FLAG, ENABLE_COURSE_GOALS
|
||||
|
||||
TEST_PASSWORD = 'test'
|
||||
TEST_CHAPTER_NAME = 'Test Chapter'
|
||||
@@ -43,6 +44,8 @@ TEST_COURSE_HOME_MESSAGE = 'course-message'
|
||||
TEST_COURSE_HOME_MESSAGE_ANONYMOUS = '/login'
|
||||
TEST_COURSE_HOME_MESSAGE_UNENROLLED = 'Enroll now'
|
||||
TEST_COURSE_HOME_MESSAGE_PRE_START = 'Course starts in'
|
||||
TEST_COURSE_GOAL_OPTIONS = 'goal-options-container'
|
||||
COURSE_GOAL_DISMISS_OPTION = 'unsure'
|
||||
|
||||
QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES
|
||||
|
||||
@@ -170,7 +173,7 @@ class TestCourseHomePage(CourseHomePageTestCase):
|
||||
course_home_url(self.course)
|
||||
|
||||
# Fetch the view and verify the query counts
|
||||
with self.assertNumQueries(41, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with self.assertNumQueries(44, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with check_mongo_calls(4):
|
||||
url = course_home_url(self.course)
|
||||
self.client.get(url)
|
||||
@@ -375,11 +378,13 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
|
||||
self.assertContains(response, TEST_COURSE_HOME_MESSAGE)
|
||||
self.assertContains(response, TEST_COURSE_HOME_MESSAGE_UNENROLLED)
|
||||
|
||||
# Verify that enrolled users are not shown a message when enrolled and course has begun
|
||||
# Verify that enrolled users are not shown any state warning message when enrolled and course has begun.
|
||||
CourseEnrollment.enroll(user, self.course.id)
|
||||
url = course_home_url(self.course)
|
||||
response = self.client.get(url)
|
||||
self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE)
|
||||
self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE_ANONYMOUS)
|
||||
self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE_UNENROLLED)
|
||||
self.assertNotContains(response, TEST_COURSE_HOME_MESSAGE_PRE_START)
|
||||
|
||||
# Verify that enrolled users are shown 'days until start' message before start date
|
||||
future_course = self.create_future_course()
|
||||
@@ -389,6 +394,50 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
|
||||
self.assertContains(response, TEST_COURSE_HOME_MESSAGE)
|
||||
self.assertContains(response, TEST_COURSE_HOME_MESSAGE_PRE_START)
|
||||
|
||||
@override_waffle_flag(UNIFIED_COURSE_TAB_FLAG, active=True)
|
||||
@override_waffle_flag(COURSE_PRE_START_ACCESS_FLAG, active=True)
|
||||
@override_waffle_flag(ENABLE_COURSE_GOALS, active=True)
|
||||
def test_course_goals(self):
|
||||
"""
|
||||
Ensure that the following five use cases work as expected.
|
||||
|
||||
1) Unenrolled users are not shown the set course goal message.
|
||||
2) Enrolled users are shown the set course goal message if they have not yet set a course goal.
|
||||
3) Enrolled users are not shown the set course goal message if they have set a course goal.
|
||||
4) Enrolled and verified users are not shown the set course goal message.
|
||||
5) Enrolled users are not shown the set course goal message in a course that cannot be verified.
|
||||
"""
|
||||
# Create a course with a verified track.
|
||||
verifiable_course = CourseFactory.create()
|
||||
add_course_mode(verifiable_course, upgrade_deadline_expired=False)
|
||||
|
||||
# Verify that unenrolled users are not shown the set course goal message.
|
||||
user = self.create_user_for_course(verifiable_course, CourseUserType.UNENROLLED)
|
||||
response = self.client.get(course_home_url(verifiable_course))
|
||||
self.assertNotContains(response, TEST_COURSE_GOAL_OPTIONS)
|
||||
|
||||
# Verify that enrolled users are shown the set course goal message in a verified course.
|
||||
CourseEnrollment.enroll(user, verifiable_course.id)
|
||||
response = self.client.get(course_home_url(verifiable_course))
|
||||
self.assertContains(response, TEST_COURSE_GOAL_OPTIONS)
|
||||
|
||||
# Verify that enrolled users that have set a course goal are not shown the set course goal message.
|
||||
add_course_goal(user, verifiable_course.id, COURSE_GOAL_DISMISS_OPTION)
|
||||
response = self.client.get(course_home_url(verifiable_course))
|
||||
self.assertNotContains(response, TEST_COURSE_GOAL_OPTIONS)
|
||||
|
||||
# Verify that enrolled and verified users are not shown the set course goal message.
|
||||
remove_course_goal(user, verifiable_course.id)
|
||||
CourseEnrollment.enroll(user, verifiable_course.id, CourseMode.VERIFIED)
|
||||
response = self.client.get(course_home_url(verifiable_course))
|
||||
self.assertNotContains(response, TEST_COURSE_GOAL_OPTIONS)
|
||||
|
||||
# Verify that enrolled users are not shown the set course goal message in an audit only course.
|
||||
audit_only_course = CourseFactory.create()
|
||||
CourseEnrollment.enroll(user, audit_only_course.id)
|
||||
response = self.client.get(course_home_url(audit_only_course))
|
||||
self.assertNotContains(response, TEST_COURSE_GOAL_OPTIONS)
|
||||
|
||||
|
||||
class CourseHomeFragmentViewTests(ModuleStoreTestCase):
|
||||
CREATE_USER = False
|
||||
|
||||
@@ -56,7 +56,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
|
||||
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
|
||||
def test_standard_course(self):
|
||||
"""
|
||||
Assure that a course that cannot be verified does
|
||||
Ensure that a course that cannot be verified does
|
||||
not have a visible verification sock.
|
||||
"""
|
||||
response = self.client.get(course_home_url(self.standard_course))
|
||||
@@ -65,7 +65,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
|
||||
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
|
||||
def test_verified_course(self):
|
||||
"""
|
||||
Assure that a course that can be verified has a
|
||||
Ensure that a course that can be verified has a
|
||||
visible verification sock.
|
||||
"""
|
||||
response = self.client.get(course_home_url(self.verified_course))
|
||||
@@ -74,7 +74,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
|
||||
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
|
||||
def test_verified_course_updated_expired(self):
|
||||
"""
|
||||
Assure that a course that has an expired upgrade
|
||||
Ensure that a course that has an expired upgrade
|
||||
date does not display the verification sock.
|
||||
"""
|
||||
response = self.client.get(course_home_url(self.verified_course_update_expired))
|
||||
@@ -83,7 +83,7 @@ class TestCourseSockView(SharedModuleStoreTestCase):
|
||||
@override_waffle_flag(DISPLAY_COURSE_SOCK_FLAG, active=True)
|
||||
def test_verified_course_user_already_upgraded(self):
|
||||
"""
|
||||
Assure that a user that has already upgraded to a
|
||||
Ensure that a user that has already upgraded to a
|
||||
verified status cannot see the verification sock.
|
||||
"""
|
||||
response = self.client.get(course_home_url(self.verified_course_already_enrolled))
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
"""
|
||||
View logic for handling course messages.
|
||||
"""
|
||||
|
||||
from babel.dates import format_date, format_timedelta
|
||||
import math
|
||||
from datetime import datetime
|
||||
|
||||
from courseware.courses import get_course_with_access
|
||||
from babel.dates import format_date, format_timedelta
|
||||
from django.conf import settings
|
||||
from django.contrib import auth
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.http import urlquote_plus
|
||||
from django.utils.timezone import UTC
|
||||
from django.utils.translation import get_language, to_locale
|
||||
from django.utils.translation import ugettext as _
|
||||
from openedx.core.djangolib.markup import Text, HTML
|
||||
from django.utils.translation import get_language, to_locale
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from rest_framework.reverse import reverse
|
||||
from web_fragments.fragment import Fragment
|
||||
|
||||
from course_modes.models import CourseMode
|
||||
from courseware.courses import get_course_with_access
|
||||
from lms.djangoapps.course_goals.api import CourseGoalOption, get_course_goal, get_goal_text
|
||||
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from openedx.features.course_experience import CourseHomeMessages
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
from .. import ENABLE_COURSE_GOALS
|
||||
|
||||
|
||||
class CourseHomeMessageFragmentView(EdxFragmentView):
|
||||
@@ -55,69 +63,140 @@ class CourseHomeMessageFragmentView(EdxFragmentView):
|
||||
}
|
||||
|
||||
# Register the course home messages to be loaded on the page
|
||||
self.register_course_home_messages(request, course, user_access, course_start_data)
|
||||
_register_course_home_messages(request, course_id, user_access, course_start_data)
|
||||
|
||||
# Grab the relevant messages
|
||||
course_home_messages = list(CourseHomeMessages.user_messages(request))
|
||||
|
||||
# Return None if user is enrolled and course has begun
|
||||
if user_access['is_enrolled'] and already_started:
|
||||
return None
|
||||
# Pass in the url used to set a course goal
|
||||
goal_api_url = reverse('course_goals_api:v0:course_goal-list', request=request)
|
||||
|
||||
# Grab the logo
|
||||
image_src = "course_experience/images/home_message_author.png"
|
||||
|
||||
context = {
|
||||
'course_home_messages': course_home_messages,
|
||||
'goal_api_url': goal_api_url,
|
||||
'image_src': image_src,
|
||||
'course_id': course_id,
|
||||
'username': request.user.username,
|
||||
}
|
||||
|
||||
html = render_to_string('course_experience/course-messages-fragment.html', context)
|
||||
return Fragment(html)
|
||||
|
||||
@staticmethod
|
||||
def register_course_home_messages(request, course, user_access, course_start_data):
|
||||
"""
|
||||
Register messages to be shown in the course home content page.
|
||||
"""
|
||||
if user_access['is_anonymous']:
|
||||
CourseHomeMessages.register_info_message(
|
||||
request,
|
||||
Text(_(
|
||||
" {sign_in_link} or {register_link} and then enroll in this course."
|
||||
)).format(
|
||||
sign_in_link=HTML("<a href='/login?next={current_url}'>{sign_in_label}</a>").format(
|
||||
sign_in_label=_("Sign in"),
|
||||
current_url=urlquote_plus(request.path),
|
||||
|
||||
def _register_course_home_messages(request, course_id, user_access, course_start_data):
|
||||
"""
|
||||
Register messages to be shown in the course home content page.
|
||||
"""
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
course = get_course_with_access(request.user, 'load', course_key)
|
||||
if user_access['is_anonymous']:
|
||||
CourseHomeMessages.register_info_message(
|
||||
request,
|
||||
Text(_(
|
||||
" {sign_in_link} or {register_link} and then enroll in this course."
|
||||
)).format(
|
||||
sign_in_link=HTML("<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("<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']:
|
||||
CourseHomeMessages.register_info_message(
|
||||
request,
|
||||
Text(_(
|
||||
"{open_enroll_link} Enroll now{close_enroll_link} to access the full course."
|
||||
)).format(
|
||||
open_enroll_link='',
|
||||
close_enroll_link=''
|
||||
),
|
||||
title=Text(_('Welcome to {course_display_name}')).format(
|
||||
course_display_name=course.display_name
|
||||
)
|
||||
)
|
||||
if user_access['is_enrolled'] and not course_start_data['already_started']:
|
||||
CourseHomeMessages.register_info_message(
|
||||
request,
|
||||
Text(_(
|
||||
"Don't forget to add a calendar reminder!"
|
||||
)),
|
||||
title=Text(_("Course starts in {days_until_start_string} on {course_start_date}.")).format(
|
||||
days_until_start_string=course_start_data['days_until_start_string'],
|
||||
course_start_date=course_start_data['course_start_date']
|
||||
)
|
||||
)
|
||||
|
||||
# Only show the set course goal message for enrolled, unverified
|
||||
# users that have not yet set a goal in a course that allows for
|
||||
# verified statuses.
|
||||
has_verified_mode = CourseMode.has_verified_mode(CourseMode.modes_for_course_dict(unicode(course.id)))
|
||||
is_already_verified = CourseEnrollment.is_enrolled_as_verified(request.user, course_key)
|
||||
user_goal = get_course_goal(auth.get_user(request), course_key) if not request.user.is_anonymous() else None
|
||||
if user_access['is_enrolled'] and has_verified_mode and not is_already_verified and not user_goal \
|
||||
and ENABLE_COURSE_GOALS.is_enabled(course_key) and settings.FEATURES.get('ENABLE_COURSE_GOALS'):
|
||||
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=CourseGoalOption.UNSURE.value,
|
||||
aria_label_choice=Text(_("Set goal to: {choice}")).format(
|
||||
choice=get_goal_text(CourseGoalOption.UNSURE.value)
|
||||
),
|
||||
),
|
||||
choice=Text(_('{choice}')).format(
|
||||
choice=get_goal_text(CourseGoalOption.UNSURE.value),
|
||||
),
|
||||
closing_tag=HTML('</div>'),
|
||||
)
|
||||
|
||||
# Add the option to set a goal to earn a certificate,
|
||||
# complete the course or explore the course
|
||||
goal_options = [CourseGoalOption.CERTIFY.value, CourseGoalOption.COMPLETE.value, CourseGoalOption.EXPLORE.value]
|
||||
for goal_key in goal_options:
|
||||
goal_text = get_goal_text(goal_key)
|
||||
goal_choices_html += HTML(
|
||||
'{initial_tag}{goal_text}{closing_tag}'
|
||||
).format(
|
||||
initial_tag=HTML(
|
||||
'<div 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))
|
||||
),
|
||||
register_link=HTML("<a href='/register?next={current_url}'>{register_label}</a>").format(
|
||||
register_label=_("register"),
|
||||
current_url=urlquote_plus(request.path),
|
||||
)
|
||||
col_sel='col-' + str(int(math.floor(12 / len(goal_options))))
|
||||
),
|
||||
title='You must be enrolled in the course to see course content.'
|
||||
goal_text=goal_text,
|
||||
closing_tag=HTML('</div>')
|
||||
)
|
||||
if not user_access['is_anonymous'] and not user_access['is_staff'] and not user_access['is_enrolled']:
|
||||
CourseHomeMessages.register_info_message(
|
||||
request,
|
||||
Text(_(
|
||||
"{open_enroll_link} Enroll now{close_enroll_link} to access the full course."
|
||||
)).format(
|
||||
open_enroll_link='',
|
||||
close_enroll_link=''
|
||||
),
|
||||
title=Text('Welcome to {course_display_name}').format(
|
||||
course_display_name=course.display_name
|
||||
)
|
||||
)
|
||||
if user_access['is_enrolled'] and not course_start_data['already_started']:
|
||||
CourseHomeMessages.register_info_message(
|
||||
request,
|
||||
Text(_(
|
||||
"Don't forget to add a calendar reminder!"
|
||||
)),
|
||||
title=Text("Course starts in {days_until_start_string} on {course_start_date}.").format(
|
||||
days_until_start_string=course_start_data['days_until_start_string'],
|
||||
course_start_date=course_start_data['course_start_date']
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user