Merge pull request #16834 from edx/HarryJeff/LEARNER-3304-policy-front-end
Policy Front end on the Course Dashboard
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import uuid as uuid_tools
|
||||
from datetime import datetime, timedelta
|
||||
from util.date_utils import strftime_localized
|
||||
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.db import models
|
||||
|
||||
from certificates.models import GeneratedCertificate # pylint: disable=import-error
|
||||
from certificates.models import GeneratedCertificate
|
||||
from model_utils.models import TimeStampedModel
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
|
||||
@@ -214,11 +215,28 @@ class CourseEntitlement(TimeStampedModel):
|
||||
return self.policy.is_entitlement_redeemable(self)
|
||||
|
||||
def to_dict(self):
|
||||
""" Convert entitlement to dictionary representation. """
|
||||
"""
|
||||
Convert entitlement to dictionary representation including relevant policy information.
|
||||
|
||||
Returns:
|
||||
The entitlement UUID
|
||||
The associated course's UUID
|
||||
The date at which the entitlement expired. None if it is still active.
|
||||
The localized string representing the date at which the entitlement expires.
|
||||
"""
|
||||
expiration_date = None
|
||||
if self.get_days_until_expiration() < settings.ENTITLEMENT_EXPIRED_ALERT_PERIOD:
|
||||
expiration_date = strftime_localized(
|
||||
datetime.now(tz=pytz.UTC) + timedelta(days=self.get_days_until_expiration()),
|
||||
'SHORT_DATE'
|
||||
)
|
||||
expired_at = strftime_localized(self.expired_at_datetime, 'SHORT_DATE') if self.expired_at_datetime else None
|
||||
|
||||
return {
|
||||
'uuid': str(self.uuid),
|
||||
'course_uuid': str(self.course_uuid),
|
||||
'expired_at': self.expired_at
|
||||
'expired_at': expired_at,
|
||||
'expiration_date': expiration_date
|
||||
}
|
||||
|
||||
def set_enrollment(self, enrollment):
|
||||
|
||||
@@ -240,6 +240,7 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
|
||||
ENABLED_SIGNALS = ['course_published']
|
||||
TOMORROW = datetime.datetime.now(pytz.utc) + datetime.timedelta(days=1)
|
||||
THREE_YEARS_AGO = datetime.datetime.now(pytz.utc) - datetime.timedelta(days=(365 * 3))
|
||||
MOCK_SETTINGS = {
|
||||
'FEATURES': {
|
||||
'DISABLE_START_DATES': False,
|
||||
@@ -371,6 +372,29 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
self.assertIn('<div class="course-entitlement-selection-container ">', response.content)
|
||||
self.assertIn('Related Programs:', response.content)
|
||||
|
||||
@patch('student.views.get_course_runs_for_course')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
def test_unfulfilled_expired_entitlement(self, mock_course_overview, mock_course_runs):
|
||||
"""
|
||||
When a learner has an unfulfilled, expired entitlement, their course dashboard should have:
|
||||
- a hidden 'View Course' button
|
||||
- a message saying that they can no longer select a session
|
||||
"""
|
||||
CourseEntitlementFactory(user=self.user, created=self.THREE_YEARS_AGO)
|
||||
mock_course_overview.return_value = CourseOverviewFactory(start=self.TOMORROW)
|
||||
mock_course_runs.return_value = [
|
||||
{
|
||||
'key': 'course-v1:FAKE+FA1-MA1.X+3T2017',
|
||||
'enrollment_end': self.TOMORROW,
|
||||
'pacing_type': 'instructor_paced',
|
||||
'type': 'verified'
|
||||
}
|
||||
]
|
||||
response = self.client.get(self.path)
|
||||
self.assertIn('class="enter-course hidden"', response.content)
|
||||
self.assertIn('You can no longer select a session', response.content)
|
||||
self.assertNotIn('<div class="course-entitlement-selection-container ">', response.content)
|
||||
|
||||
@patch('student.views.get_course_runs_for_course')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
@patch('opaque_keys.edx.keys.CourseKey.from_string')
|
||||
@@ -401,6 +425,35 @@ class StudentDashboardTests(SharedModuleStoreTestCase, MilestonesTestCaseMixin):
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 1)
|
||||
self.assertIn('<button class="change-session btn-link "', response.content)
|
||||
|
||||
@patch('student.views.get_course_runs_for_course')
|
||||
@patch.object(CourseOverview, 'get_from_id')
|
||||
@patch('opaque_keys.edx.keys.CourseKey.from_string')
|
||||
def test_fulfilled_expired_entitlement(self, mock_course_key, mock_course_overview, mock_course_runs):
|
||||
"""
|
||||
When a learner has a fulfilled entitlement that is expired, their course dashboard should have:
|
||||
- exactly one course item, meaning it:
|
||||
- has an entitlement card
|
||||
- Message that the learner can no longer change sessions
|
||||
"""
|
||||
mocked_course_overview = CourseOverviewFactory(
|
||||
start=self.TOMORROW, self_paced=True, enrollment_end=self.TOMORROW
|
||||
)
|
||||
mock_course_overview.return_value = mocked_course_overview
|
||||
mock_course_key.return_value = mocked_course_overview.id
|
||||
course_enrollment = CourseEnrollmentFactory(user=self.user, course_id=unicode(mocked_course_overview.id), created=self.THREE_YEARS_AGO)
|
||||
mock_course_runs.return_value = [
|
||||
{
|
||||
'key': mocked_course_overview.id,
|
||||
'enrollment_end': mocked_course_overview.enrollment_end,
|
||||
'pacing_type': 'self_paced',
|
||||
'type': 'verified'
|
||||
}
|
||||
]
|
||||
CourseEntitlementFactory(user=self.user, enrollment_course_run=course_enrollment, created=self.THREE_YEARS_AGO)
|
||||
response = self.client.get(self.path)
|
||||
self.assertEqual(response.content.count('<li class="course-item">'), 1)
|
||||
self.assertIn('You can no longer change sessions.', response.content)
|
||||
|
||||
|
||||
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
|
||||
@override_settings(BRANCH_IO_KEY='test_key')
|
||||
|
||||
@@ -695,10 +695,11 @@ def dashboard(request):
|
||||
|
||||
# Get the entitlements for the user and a mapping to all available sessions for that entitlement
|
||||
course_entitlements = list(CourseEntitlement.objects.filter(user=user).select_related('enrollment_course_run'))
|
||||
course_entitlement_available_sessions = {
|
||||
str(entitlement.uuid): get_course_runs_for_course(str(entitlement.course_uuid))
|
||||
for entitlement in course_entitlements
|
||||
}
|
||||
course_entitlement_available_sessions = {}
|
||||
for course_entitlement in course_entitlements:
|
||||
course_entitlement.update_expired_at()
|
||||
course_entitlement_available_sessions[str(course_entitlement.uuid)] = \
|
||||
get_course_runs_for_course(str(course_entitlement.course_uuid))
|
||||
|
||||
# Record how many courses there are so that we can get a better
|
||||
# understanding of usage patterns on prod.
|
||||
|
||||
@@ -2417,6 +2417,9 @@ SUPPORT_SITE_LINK = ''
|
||||
PASSWORD_RESET_SUPPORT_LINK = ''
|
||||
ACTIVATION_EMAIL_SUPPORT_LINK = ''
|
||||
|
||||
# Days before the expired date that we warn the user
|
||||
ENTITLEMENT_EXPIRED_ALERT_PERIOD = 90
|
||||
|
||||
############################# SOCIAL MEDIA SHARING #############################
|
||||
# Social Media Sharing on Student Dashboard
|
||||
SOCIAL_SHARING_SETTINGS = {
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
availableSessions: [],
|
||||
entitlementUUID: '',
|
||||
currentSessionId: '',
|
||||
courseName: ''
|
||||
courseName: '',
|
||||
expiredAt: null,
|
||||
daysUntilExpiration: Number.MAX_VALUE
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -91,7 +91,9 @@
|
||||
currentSessionId: this.model.isEnrolledInSession() ?
|
||||
this.model.get('course_run_key') : null,
|
||||
enrollUrl: this.model.get('enroll_url'),
|
||||
courseHomeUrl: this.model.get('course_url')
|
||||
courseHomeUrl: this.model.get('course_url'),
|
||||
expiredAt: this.entitlement.expired_at,
|
||||
daysUntilExpiration: this.entitlement.days_until_expiration
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@
|
||||
availableSessions: this.formatDates(JSON.parse(options.availableSessions)),
|
||||
entitlementUUID: options.entitlementUUID,
|
||||
currentSessionId: options.currentSessionId,
|
||||
expiredAt: options.expiredAt,
|
||||
expiresAtDate: this.courseCardModel.formatDate(
|
||||
new moment().utc().add(options.daysUntilExpiration, 'days')
|
||||
),
|
||||
courseName: options.courseName
|
||||
});
|
||||
this.listenTo(this.entitlementModel, 'change', this.render);
|
||||
|
||||
@@ -234,6 +234,47 @@ define([
|
||||
|
||||
expect(view.$('.course-title-link').length).toEqual(0);
|
||||
});
|
||||
it('should show an unfulfilled expired user entitlement not allowing the changing of sessions', function() {
|
||||
course.user_entitlement = {
|
||||
uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
expired_at: '2017-12-06 01:06:12',
|
||||
expiration_date: '2017-12-05 01:06:12'
|
||||
};
|
||||
setupView(course, false);
|
||||
expect(view.$('.info-expires-at').text().trim()).toContain('You can no longer select a session. Your');
|
||||
});
|
||||
|
||||
it('should show an unfulfilled user entitlement allows you to select a session', function() {
|
||||
course.user_entitlement = {
|
||||
uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
expiration_date: '2017-12-05 01:06:12'
|
||||
};
|
||||
setupView(course, false);
|
||||
expect(view.$('.info-expires-at').text().trim()).toContain('You must select a session by');
|
||||
});
|
||||
|
||||
it('should show a fulfilled expired user entitlement does not allow the changing of sessions', function() {
|
||||
course.user_entitlement = {
|
||||
uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
expired_at: '2017-12-06 01:06:12',
|
||||
expiration_date: '2017-12-05 01:06:12'
|
||||
};
|
||||
setupView(course, true);
|
||||
expect(view.$('.info-expires-at').text().trim()).toContain('You can no longer change sessions.');
|
||||
});
|
||||
|
||||
it('should show a fulfilled user entitlement allows the changing of sessions', function() {
|
||||
course.user_entitlement = {
|
||||
uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
course_uuid: '99fc7414c36d4f56b37e8e30acf4c7ba',
|
||||
expiration_date: '2017-12-05 01:06:12'
|
||||
};
|
||||
setupView(course, true);
|
||||
expect(view.$('.info-expires-at').text().trim()).toContain('You can change sessions until');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -349,7 +349,8 @@
|
||||
.action {
|
||||
@include margin-right(0);
|
||||
|
||||
&:hover, &:focus {
|
||||
&:hover,
|
||||
&:focus {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
@@ -361,7 +362,7 @@
|
||||
.course-status {
|
||||
background: $yellow;
|
||||
border: 1px solid $border-color-2;
|
||||
box-shadow: 0 1px 0 0 rgba(255,255,255, 0.6);
|
||||
box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.6);
|
||||
margin-top: 17px;
|
||||
|
||||
@include margin-right(flex-gutter());
|
||||
@@ -971,18 +972,16 @@
|
||||
|
||||
.action-certificate .btn {
|
||||
@extend %btn-inherited-primary;
|
||||
|
||||
@include box-sizing(border-box);
|
||||
|
||||
padding: 7px $baseline*0.75;
|
||||
float: none;
|
||||
border-radius: 3px;
|
||||
display: block;
|
||||
|
||||
@include padding(7px, ($baseline*0.75), 7px, ($baseline*0.75));
|
||||
|
||||
text-align: center;
|
||||
|
||||
a:link, a:visited {
|
||||
a:link,
|
||||
a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
}
|
||||
|
||||
.change-session {
|
||||
@include margin(0, 0, $baseline/4, $baseline/4);
|
||||
@include margin(0, 0, 0, $baseline/4);
|
||||
|
||||
padding: 0;
|
||||
font-size: $font-size-sm;
|
||||
|
||||
@@ -475,7 +475,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.run-period {
|
||||
.run-period,
|
||||
.info-expires-at {
|
||||
color: palette(grayscale, base);
|
||||
font-size: 0.9375em;
|
||||
}
|
||||
@@ -505,7 +506,6 @@
|
||||
vertical-align: top;
|
||||
padding: 0 10px 0 0;
|
||||
float: left;
|
||||
width: calc(100% - 205px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
<%def name="online_help_token()"><% return "learnerdashboard" %></%def>
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
<%!
|
||||
import pytz
|
||||
from datetime import datetime, timedelta
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.template import RequestContext
|
||||
from entitlements.models import CourseEntitlement
|
||||
import third_party_auth
|
||||
from third_party_auth import pipeline
|
||||
from util.date_utils import strftime_localized
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
@@ -126,6 +128,10 @@ from student.models import CourseEnrollment
|
||||
# Check if the course run is an entitlement and if it has an associated session
|
||||
entitlement = enrollment if isinstance(enrollment, CourseEntitlement) else None
|
||||
entitlement_session = entitlement.enrollment_course_run if entitlement else None
|
||||
entitlement_days_until_expiration = entitlement.get_days_until_expiration() if entitlement else None
|
||||
entitlement_expiration = datetime.now(tz=pytz.UTC) + timedelta(days=entitlement_days_until_expiration) if (entitlement and entitlement_days_until_expiration < settings.ENTITLEMENT_EXPIRED_ALERT_PERIOD) else None
|
||||
entitlement_expiration_date = strftime_localized(entitlement_expiration, 'SHORT_DATE') if entitlement and entitlement_expiration else None
|
||||
entitlement_expired_at = strftime_localized(entitlement.expired_at_datetime, 'SHORT_DATE') if entitlement and entitlement.expired_at_datetime else None
|
||||
|
||||
is_fulfilled_entitlement = True if entitlement and entitlement_session else False
|
||||
is_unfulfilled_entitlement = True if entitlement and not entitlement_session else False
|
||||
@@ -167,7 +173,7 @@ from student.models import CourseEnrollment
|
||||
show_consent_link = (session_id in consent_required_courses)
|
||||
course_overview = enrollment.course_overview
|
||||
%>
|
||||
<%include file='dashboard/_dashboard_course_listing.html' args='course_overview=course_overview, course_card_index=dashboard_index, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, is_fulfilled_entitlement=is_fulfilled_entitlement, entitlement=entitlement, entitlement_session=entitlement_session, entitlement_available_sessions=entitlement_available_sessions, show_courseware_link=show_courseware_link, cert_status=cert_status, can_unenroll=can_unenroll, credit_status=credit_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, is_paid_course=is_paid_course, is_course_blocked=is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, user=user, related_programs=related_programs, display_course_modes_on_dashboard=display_course_modes_on_dashboard, show_consent_link=show_consent_link, enterprise_customer_name=enterprise_customer_name' />
|
||||
<%include file='dashboard/_dashboard_course_listing.html' args='course_overview=course_overview, course_card_index=dashboard_index, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, is_fulfilled_entitlement=is_fulfilled_entitlement, entitlement=entitlement, entitlement_session=entitlement_session, entitlement_available_sessions=entitlement_available_sessions, entitlement_expiration_date=entitlement_expiration_date, entitlement_expired_at=entitlement_expired_at, show_courseware_link=show_courseware_link, cert_status=cert_status, can_unenroll=can_unenroll, credit_status=credit_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, is_paid_course=is_paid_course, is_course_blocked=is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, user=user, related_programs=related_programs, display_course_modes_on_dashboard=display_course_modes_on_dashboard, show_consent_link=show_consent_link, enterprise_customer_name=enterprise_customer_name' />
|
||||
% endfor
|
||||
|
||||
</ul>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%page args="course_overview, enrollment, entitlement, entitlement_session, course_card_index, is_unfulfilled_entitlement, is_fulfilled_entitlement, entitlement_available_sessions, show_courseware_link, cert_status, can_unenroll, credit_status, show_email_settings, course_mode_info, is_paid_course, is_course_blocked, verification_status, course_requirements, dashboard_index, share_settings, related_programs, display_course_modes_on_dashboard, show_consent_link, enterprise_customer_name" expression_filter="h"/>
|
||||
<%page args="course_overview, enrollment, entitlement, entitlement_session, course_card_index, is_unfulfilled_entitlement, is_fulfilled_entitlement, entitlement_available_sessions, entitlement_expiration_date, entitlement_expired_at, show_courseware_link, cert_status, can_unenroll, credit_status, show_email_settings, course_mode_info, is_paid_course, is_course_blocked, verification_status, course_requirements, dashboard_index, share_settings, related_programs, display_course_modes_on_dashboard, show_consent_link, enterprise_customer_name" expression_filter="h"/>
|
||||
|
||||
<%!
|
||||
import urllib
|
||||
@@ -131,7 +131,15 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
|
||||
% if is_unfulfilled_entitlement:
|
||||
<span class="info-date-block" aria-live="polite">
|
||||
<span class="icon fa fa-warning" aria-hidden="true"></span>
|
||||
${_('You must select a session to access the course.')}
|
||||
% if entitlement_expired_at:
|
||||
${_('You can no longer select a session, your final day to select a session was {entitlement_expired_at}.').format(entitlement_expired_at=entitlement_expired_at)}
|
||||
% else:
|
||||
% if entitlement_expiration_date:
|
||||
${_('You must select a session by {expiration_date} to access the course.').format(expiration_date=entitlement_expiration_date)}
|
||||
% else:
|
||||
${_('You must select a session to access the course.')}
|
||||
% endif
|
||||
% endif
|
||||
</span>
|
||||
% else:
|
||||
% if isinstance(course_date, basestring):
|
||||
@@ -141,9 +149,21 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
|
||||
% endif
|
||||
% endif
|
||||
% if entitlement:
|
||||
<button class="change-session btn-link ${'hidden' if is_unfulfilled_entitlement else ''}" aria-controls="change-session-${str(entitlement.uuid)}">${_('Change Session')}</button>
|
||||
% if not entitlement_expired_at:
|
||||
<button class="change-session btn-link ${'hidden' if is_unfulfilled_entitlement else ''}" aria-controls="change-session-${str(entitlement.uuid)}">${_('Change Session')}</button>
|
||||
% endif
|
||||
% endif
|
||||
</span>
|
||||
% if entitlement and not is_unfulfilled_entitlement and entitlement_expiration_date:
|
||||
<div class="info-expires-at">
|
||||
<span class="msg-icon fa fa-info" aria-hidden="true"></span>
|
||||
% if entitlement_expired_at:
|
||||
${_('You can no longer change sessions.')}
|
||||
% else:
|
||||
${_('You can change sessions until {entitlement_expiration_date}.').format(entitlement_expiration_date=entitlement_expiration_date)}
|
||||
% endif
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
<div class="wrapper-course-actions">
|
||||
<div class="course-actions">
|
||||
@@ -278,7 +298,7 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
|
||||
<footer class="wrapper-messages-primary">
|
||||
<div class="messages-list">
|
||||
|
||||
% if entitlement:
|
||||
% if entitlement and not entitlement_expired_at:
|
||||
<div class="course-entitlement-selection-container ${'' if is_unfulfilled_entitlement else 'hidden'}"></div>
|
||||
<%static:require_module module_name="js/learner_dashboard/course_entitlement_factory" class_name="EntitlementFactory">
|
||||
EntitlementFactory({
|
||||
@@ -293,7 +313,9 @@ from util.course import get_link_for_about_page, get_encoded_course_sharing_utm_
|
||||
entitlementUUID: '${ entitlement.course_uuid | n, js_escaped_string }',
|
||||
currentSessionId: '${ entitlement_session.course_id if entitlement_session else "" | n, js_escaped_string }',
|
||||
enrollUrl: '${ reverse('entitlements_api:v1:enrollments', args=[str(entitlement.uuid)]) | n, js_escaped_string }',
|
||||
courseHomeUrl: '${ course_target | n, js_escaped_string }'
|
||||
courseHomeUrl: '${ course_target | n, js_escaped_string }',
|
||||
expiredAt: '${ entitlement.expired_at_datetime | n, js_escaped_string }',
|
||||
daysUntilExpiration: '${ entitlement.get_days_until_expiration() | n, js_escaped_string }'
|
||||
});
|
||||
</%static:require_module>
|
||||
%endif
|
||||
|
||||
@@ -17,12 +17,28 @@
|
||||
<% } %>
|
||||
<% if (dateString && !is_unfulfilled_entitlement) { %>
|
||||
<span class="run-period"><%- dateString %></span>
|
||||
<% if (user_entitlement && !is_unfulfilled_entitlement) { %>
|
||||
<% if (user_entitlement && !user_entitlement.expired_at && !is_unfulfilled_entitlement) { %>
|
||||
<button class="change-session btn-link" aria-controls="change-session-<%-user_entitlement.uuid%>"> <%- gettext('Change Session')%></button>
|
||||
<% } %>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<% if (user_entitlement && user_entitlement.expiration_date) { %>
|
||||
<div class="info-expires-at">
|
||||
<% if (is_unfulfilled_entitlement) { %>
|
||||
<% if (user_entitlement.expired_at) { %>
|
||||
<%- StringUtils.interpolate(gettext('You can no longer select a session. Your final day to select a session was {expiration_date}.'), {expiration_date: user_entitlement.expiration_date}) %>
|
||||
<% } else { %>
|
||||
<%- StringUtils.interpolate(gettext('You must select a session by {expiration_date} to access the course.'), {expiration_date: user_entitlement.expiration_date}) %>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<% if (user_entitlement.expired_at) { %>
|
||||
<%- gettext('You can no longer change sessions.')%>
|
||||
<% } else { %>
|
||||
<%- StringUtils.interpolate(gettext('You can change sessions until {expiration_date}.'), {expiration_date: user_entitlement.expiration_date}) %>
|
||||
<% } %>
|
||||
<% } %>
|
||||
</div>
|
||||
<% } %>
|
||||
<div class="course-actions"></div>
|
||||
</div>
|
||||
<div class="course-certificate certificate-status"></div>
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
<%def name="online_help_token()"><% return "learnerdashboard" %></%def>
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
<%!
|
||||
import pytz
|
||||
from courseware.context_processor import user_timezone_locale_prefs
|
||||
from datetime import datetime, timedelta
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.template import RequestContext
|
||||
import third_party_auth
|
||||
from third_party_auth import pipeline
|
||||
from django.core.urlresolvers import reverse
|
||||
import json
|
||||
from util.date_utils import strftime_localized
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
from openedx.core.djangoapps.theming import helpers as theming_helpers
|
||||
@@ -121,6 +124,10 @@ from student.models import CourseEnrollment
|
||||
# Check if the course run is an entitlement and if it has an associated session
|
||||
entitlement = enrollment if isinstance(enrollment, CourseEntitlement) else None
|
||||
entitlement_session = entitlement.enrollment_course_run if entitlement else None
|
||||
entitlement_days_until_expiration = entitlement.get_days_until_expiration() if entitlement else None
|
||||
entitlement_expiration = datetime.now(tz=pytz.UTC) + timedelta(days=entitlement_days_until_expiration) if (entitlement and entitlement_days_until_expiration < settings.ENTITLEMENT_EXPIRED_ALERT_PERIOD) else None
|
||||
entitlement_expiration_date = strftime_localized(entitlement_expiration, 'SHORT_DATE') if entitlement and entitlement_expiration else None
|
||||
entitlement_expired_at = strftime_localized(entitlement.expired_at_datetime, 'SHORT_DATE') if entitlement and entitlement.expired_at_datetime else None
|
||||
|
||||
is_fulfilled_entitlement = True if entitlement and entitlement_session else False
|
||||
is_unfulfilled_entitlement = True if entitlement and not entitlement_session else False
|
||||
@@ -162,7 +169,7 @@ from student.models import CourseEnrollment
|
||||
show_consent_link = (session_id in consent_required_courses)
|
||||
course_overview = enrollment.course_overview
|
||||
%>
|
||||
<%include file='dashboard/_dashboard_course_listing.html' args='course_overview=course_overview, course_card_index=dashboard_index, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, is_fulfilled_entitlement=is_fulfilled_entitlement, entitlement=entitlement, entitlement_session=entitlement_session, entitlement_available_sessions=entitlement_available_sessions, show_courseware_link=show_courseware_link, cert_status=cert_status, can_unenroll=can_unenroll, credit_status=credit_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, is_paid_course=is_paid_course, is_course_blocked=is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, user=user, related_programs=related_programs, display_course_modes_on_dashboard=display_course_modes_on_dashboard, show_consent_link=show_consent_link, enterprise_customer_name=enterprise_customer_name' />
|
||||
<%include file='dashboard/_dashboard_course_listing.html' args='course_overview=course_overview, course_card_index=dashboard_index, enrollment=enrollment, is_unfulfilled_entitlement=is_unfulfilled_entitlement, is_fulfilled_entitlement=is_fulfilled_entitlement, entitlement=entitlement, entitlement_session=entitlement_session, entitlement_available_sessions=entitlement_available_sessions, entitlement_expiration_date=entitlement_expiration_date, entitlement_expired_at=entitlement_expired_at, show_courseware_link=show_courseware_link, cert_status=cert_status, can_unenroll=can_unenroll, credit_status=credit_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info, is_paid_course=is_paid_course, is_course_blocked=is_course_blocked, verification_status=course_verification_status, course_requirements=course_requirements, dashboard_index=dashboard_index, share_settings=share_settings, user=user, related_programs=related_programs, display_course_modes_on_dashboard=display_course_modes_on_dashboard, show_consent_link=show_consent_link, enterprise_customer_name=enterprise_customer_name' />
|
||||
% endfor
|
||||
</ul>
|
||||
% else:
|
||||
|
||||
Reference in New Issue
Block a user