@@ -9,7 +9,7 @@ from collections import namedtuple
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.db.models import Q
|
||||
|
||||
Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices', 'currency'])
|
||||
Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices', 'currency', 'expiration_date'])
|
||||
|
||||
|
||||
class CourseMode(models.Model):
|
||||
@@ -39,7 +39,7 @@ class CourseMode(models.Model):
|
||||
# turn this mode off after the given expiration date
|
||||
expiration_date = models.DateField(default=None, null=True, blank=True)
|
||||
|
||||
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd')
|
||||
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd', None)
|
||||
DEFAULT_MODE_SLUG = 'honor'
|
||||
|
||||
class Meta:
|
||||
@@ -57,8 +57,14 @@ class CourseMode(models.Model):
|
||||
found_course_modes = cls.objects.filter(Q(course_id=course_id) &
|
||||
(Q(expiration_date__isnull=True) |
|
||||
Q(expiration_date__gte=now)))
|
||||
modes = ([Mode(mode.mode_slug, mode.mode_display_name, mode.min_price, mode.suggested_prices, mode.currency)
|
||||
for mode in found_course_modes])
|
||||
modes = ([Mode(
|
||||
mode.mode_slug,
|
||||
mode.mode_display_name,
|
||||
mode.min_price,
|
||||
mode.suggested_prices,
|
||||
mode.currency,
|
||||
mode.expiration_date
|
||||
) for mode in found_course_modes])
|
||||
if not modes:
|
||||
modes = [cls.DEFAULT_MODE]
|
||||
return modes
|
||||
|
||||
@@ -49,7 +49,7 @@ class CourseModeModelTest(TestCase):
|
||||
|
||||
self.create_mode('verified', 'Verified Certificate')
|
||||
modes = CourseMode.modes_for_course(self.course_id)
|
||||
mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd')
|
||||
mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None)
|
||||
self.assertEqual([mode], modes)
|
||||
|
||||
modes_dict = CourseMode.modes_for_course_dict(self.course_id)
|
||||
@@ -61,8 +61,8 @@ class CourseModeModelTest(TestCase):
|
||||
"""
|
||||
Finding the modes when there's multiple modes
|
||||
"""
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd')
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd')
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None)
|
||||
set_modes = [mode1, mode2]
|
||||
for mode in set_modes:
|
||||
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices)
|
||||
@@ -81,9 +81,9 @@ class CourseModeModelTest(TestCase):
|
||||
self.assertEqual(0, CourseMode.min_course_price_for_currency(self.course_id, 'usd'))
|
||||
|
||||
# create some modes
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd')
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd')
|
||||
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny')
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None)
|
||||
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None)
|
||||
set_modes = [mode1, mode2, mode3]
|
||||
for mode in set_modes:
|
||||
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices, mode.currency)
|
||||
@@ -98,14 +98,15 @@ class CourseModeModelTest(TestCase):
|
||||
modes = CourseMode.modes_for_course(self.course_id)
|
||||
self.assertEqual([CourseMode.DEFAULT_MODE], modes)
|
||||
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd')
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None)
|
||||
self.create_mode(mode1.slug, mode1.name, mode1.min_price, mode1.suggested_prices)
|
||||
modes = CourseMode.modes_for_course(self.course_id)
|
||||
self.assertEqual([mode1], modes)
|
||||
|
||||
expired_mode.expiration_date = datetime.now(pytz.UTC) + timedelta(days=1)
|
||||
expiration_date = datetime.now(pytz.UTC) + timedelta(days=1)
|
||||
expired_mode.expiration_date = expiration_date
|
||||
expired_mode.save()
|
||||
expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd')
|
||||
expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', expiration_date.date())
|
||||
modes = CourseMode.modes_for_course(self.course_id)
|
||||
self.assertEqual([expired_mode_value, mode1], modes)
|
||||
|
||||
|
||||
@@ -34,10 +34,19 @@ class ChooseModeView(View):
|
||||
@method_decorator(login_required)
|
||||
def get(self, request, course_id, error=None):
|
||||
""" Displays the course mode choice page """
|
||||
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
|
||||
return redirect(reverse('dashboard'))
|
||||
modes = CourseMode.modes_for_course_dict(course_id)
|
||||
|
||||
enrollment_mode = CourseEnrollment.enrollment_mode_for_user(request.user, course_id)
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
|
||||
# verified users do not need to register or upgrade
|
||||
if enrollment_mode == 'verified':
|
||||
return redirect(reverse('dashboard'))
|
||||
|
||||
# registered users who are not trying to upgrade do not need to re-register
|
||||
if enrollment_mode is not None and upgrade is False:
|
||||
return redirect(reverse('dashboard'))
|
||||
|
||||
modes = CourseMode.modes_for_course_dict(course_id)
|
||||
donation_for_course = request.session.get("donation_for_course", {})
|
||||
chosen_price = donation_for_course.get(course_id, None)
|
||||
|
||||
@@ -50,6 +59,7 @@ class ChooseModeView(View):
|
||||
"course_num": course.display_number_with_default,
|
||||
"chosen_price": chosen_price,
|
||||
"error": error,
|
||||
"upgrade": upgrade,
|
||||
}
|
||||
if "verified" in modes:
|
||||
context["suggested_prices"] = [decimal.Decimal(x) for x in modes["verified"].suggested_prices.split(",")]
|
||||
@@ -70,6 +80,8 @@ class ChooseModeView(View):
|
||||
error_msg = _("Enrollment is closed")
|
||||
return self.get(request, course_id, error=error_msg)
|
||||
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
|
||||
requested_mode = self.get_requested_mode(request.POST.get("mode"))
|
||||
if requested_mode == "verified" and request.POST.get("honor-code"):
|
||||
requested_mode = "honor"
|
||||
@@ -106,13 +118,12 @@ class ChooseModeView(View):
|
||||
if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
|
||||
return redirect(
|
||||
reverse('verify_student_verified',
|
||||
kwargs={'course_id': course_id})
|
||||
kwargs={'course_id': course_id}) + "?upgrade={}".format(upgrade)
|
||||
)
|
||||
|
||||
return redirect(
|
||||
reverse('verify_student_show_requirements',
|
||||
kwargs={'course_id': course_id}),
|
||||
)
|
||||
kwargs={'course_id': course_id}) + "?upgrade={}".format(upgrade))
|
||||
|
||||
def get_requested_mode(self, user_choice):
|
||||
"""
|
||||
@@ -121,6 +132,7 @@ class ChooseModeView(View):
|
||||
"""
|
||||
choices = {
|
||||
"Select Audit": "audit",
|
||||
"Select Certificate": "verified"
|
||||
"Select Certificate": "verified",
|
||||
"Upgrade Your Registration": "verified"
|
||||
}
|
||||
return choices.get(user_choice)
|
||||
|
||||
@@ -2,6 +2,7 @@ from student.models import (User, UserProfile, Registration,
|
||||
CourseEnrollmentAllowed, CourseEnrollment,
|
||||
PendingEmailChange, UserStanding,
|
||||
)
|
||||
from course_modes.models import CourseMode
|
||||
from django.contrib.auth.models import Group
|
||||
from datetime import datetime
|
||||
from factory import DjangoModelFactory, SubFactory, PostGenerationMethodCall, post_generation, Sequence
|
||||
@@ -36,6 +37,16 @@ class UserProfileFactory(DjangoModelFactory):
|
||||
goals = u'World domination'
|
||||
|
||||
|
||||
class CourseModeFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = CourseMode
|
||||
|
||||
course_id = None
|
||||
mode_display_name = u'Honor Code',
|
||||
mode_slug = 'honor'
|
||||
min_price = 0
|
||||
suggested_prices = ''
|
||||
currency = 'usd'
|
||||
|
||||
class RegistrationFactory(DjangoModelFactory):
|
||||
FACTORY_FOR = Registration
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import logging
|
||||
import json
|
||||
import re
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
import pytz
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
@@ -28,8 +30,8 @@ from textwrap import dedent
|
||||
|
||||
from student.models import unique_id_for_user, CourseEnrollment
|
||||
from student.views import (process_survey_link, _cert_info, password_reset, password_reset_confirm_wrapper,
|
||||
change_enrollment)
|
||||
from student.tests.factories import UserFactory
|
||||
change_enrollment, complete_course_mode_info)
|
||||
from student.tests.factories import UserFactory, CourseModeFactory
|
||||
from student.tests.test_email import mock_render_to_string
|
||||
|
||||
import shoppingcart
|
||||
@@ -216,6 +218,45 @@ class CourseEndingTest(TestCase):
|
||||
})
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
|
||||
class DashboardTest(TestCase):
|
||||
"""
|
||||
Tests for dashboard utility functions
|
||||
"""
|
||||
# arbitrary constant
|
||||
COURSE_SLUG = "100"
|
||||
COURSE_NAME = "test_course"
|
||||
COURSE_ORG = "EDX"
|
||||
|
||||
def setUp(self):
|
||||
self.course = CourseFactory.create(org=self.COURSE_ORG, display_name=self.COURSE_NAME, number=self.COURSE_SLUG)
|
||||
self.assertIsNotNone(self.course)
|
||||
self.user = UserFactory.create(username="jack", email="jack@fake.edx.org")
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug='honor',
|
||||
mode_display_name='Honor Code',
|
||||
)
|
||||
|
||||
def test_course_mode_info(self):
|
||||
verified_mode = CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug='verified',
|
||||
mode_display_name='Verified',
|
||||
expiration_date=(datetime.now(pytz.UTC) + timedelta(days=1)).date()
|
||||
)
|
||||
enrollment = CourseEnrollment.enroll(self.user, self.course.id)
|
||||
course_mode_info = complete_course_mode_info(self.course.id, enrollment)
|
||||
self.assertTrue(course_mode_info['show_upsell'])
|
||||
self.assertEquals(course_mode_info['days_for_upsell'], 1)
|
||||
|
||||
verified_mode.expiration_date = datetime.now(pytz.UTC) + timedelta(days=-1)
|
||||
verified_mode.save()
|
||||
course_mode_info = complete_course_mode_info(self.course.id, enrollment)
|
||||
self.assertFalse(course_mode_info['show_upsell'])
|
||||
self.assertIsNone(course_mode_info['days_for_upsell'])
|
||||
|
||||
|
||||
class EnrollInCourseTest(TestCase):
|
||||
"""Tests enrolling and unenrolling in courses."""
|
||||
|
||||
|
||||
@@ -267,6 +267,29 @@ def register_user(request, extra_context=None):
|
||||
return render_to_response('register.html', context)
|
||||
|
||||
|
||||
def complete_course_mode_info(course_id, enrollment):
|
||||
"""
|
||||
We would like to compute some more information from the given course modes
|
||||
and the user's current enrollment
|
||||
|
||||
Returns the given information:
|
||||
- whether to show the course upsell information
|
||||
- numbers of days until they can't upsell anymore
|
||||
"""
|
||||
modes = CourseMode.modes_for_course_dict(course_id)
|
||||
mode_info = {'show_upsell': False, 'days_for_upsell': None}
|
||||
# we want to know if the user is already verified and if verified is an
|
||||
# option
|
||||
if 'verified' in modes and enrollment.mode != 'verified':
|
||||
mode_info['show_upsell'] = True
|
||||
# if there is an expiration date, find out how long from now it is
|
||||
if modes['verified'].expiration_date:
|
||||
today = datetime.datetime.now(UTC).date()
|
||||
mode_info['days_for_upsell'] = (modes['verified'].expiration_date - today).days
|
||||
|
||||
return mode_info
|
||||
|
||||
|
||||
@login_required
|
||||
@ensure_csrf_cookie
|
||||
def dashboard(request):
|
||||
@@ -300,6 +323,7 @@ def dashboard(request):
|
||||
show_courseware_links_for = frozenset(course.id for course, _enrollment in courses
|
||||
if has_access(request.user, course, 'load'))
|
||||
|
||||
course_modes = {course.id: complete_course_mode_info(course.id, enrollment) for course, enrollment in courses}
|
||||
cert_statuses = {course.id: cert_info(request.user, course) for course, _enrollment in courses}
|
||||
|
||||
# only show email settings for Mongo course and when bulk email is turned on
|
||||
@@ -324,6 +348,7 @@ def dashboard(request):
|
||||
'staff_access': staff_access,
|
||||
'errored_courses': errored_courses,
|
||||
'show_courseware_links_for': show_courseware_links_for,
|
||||
'all_course_modes': course_modes,
|
||||
'cert_statuses': cert_statuses,
|
||||
'show_email_settings_for': show_email_settings_for,
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ some xmodules by conditions.
|
||||
|
||||
import json
|
||||
import logging
|
||||
from lazy import lazy
|
||||
from lxml import etree
|
||||
from pkg_resources import resource_string
|
||||
|
||||
@@ -97,10 +98,12 @@ class ConditionalModule(ConditionalFields, XModule):
|
||||
return xml_value, attr_name
|
||||
raise Exception('Error in conditional module: unknown condition "%s"' % xml_attr)
|
||||
|
||||
def is_condition_satisfied(self):
|
||||
self.required_modules = [self.system.get_module(descriptor) for
|
||||
descriptor in self.descriptor.get_required_module_descriptors()]
|
||||
@lazy
|
||||
def required_modules(self):
|
||||
return [self.system.get_module(descriptor) for
|
||||
descriptor in self.descriptor.get_required_module_descriptors()]
|
||||
|
||||
def is_condition_satisfied(self):
|
||||
xml_value, attr_name = self._get_condition()
|
||||
|
||||
if xml_value and self.required_modules:
|
||||
|
||||
@@ -181,7 +181,7 @@ class LTIModule(LTIFields, XModule):
|
||||
]
|
||||
|
||||
# Obtains client_key and client_secret credentials from current course:
|
||||
course_id = self.runtime.course_id
|
||||
course_id = self.course_id
|
||||
course_location = CourseDescriptor.id_to_location(course_id)
|
||||
course = self.descriptor.runtime.modulestore.get_item(course_location)
|
||||
client_key = client_secret = ''
|
||||
|
||||
@@ -519,7 +519,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
error_text = ""
|
||||
problem_list = []
|
||||
try:
|
||||
problem_list_json = self.peer_gs.get_problem_list(self.system.course_id, self.system.anonymous_student_id)
|
||||
problem_list_json = self.peer_gs.get_problem_list(self.course_id, self.system.anonymous_student_id)
|
||||
problem_list_dict = problem_list_json
|
||||
success = problem_list_dict['success']
|
||||
if 'error' in problem_list_dict:
|
||||
@@ -569,7 +569,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
|
||||
ajax_url = self.ajax_url
|
||||
html = self.system.render_template('peer_grading/peer_grading.html', {
|
||||
'course_id': self.system.course_id,
|
||||
'course_id': self.course_id,
|
||||
'ajax_url': ajax_url,
|
||||
'success': success,
|
||||
'problem_list': good_problem_list,
|
||||
@@ -603,7 +603,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
|
||||
html = self.system.render_template('peer_grading/peer_grading_problem.html', {
|
||||
'view_html': '',
|
||||
'problem_location': problem_location,
|
||||
'course_id': self.system.course_id,
|
||||
'course_id': self.course_id,
|
||||
'ajax_url': ajax_url,
|
||||
# Checked above
|
||||
'staff_access': False,
|
||||
|
||||
@@ -133,6 +133,10 @@ class XModuleMixin(XBlockMixin):
|
||||
default=None
|
||||
)
|
||||
|
||||
@property
|
||||
def course_id(self):
|
||||
return self.runtime.course_id
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.location.url()
|
||||
@@ -743,6 +747,7 @@ class XModuleDescriptor(XModuleMixin, HTMLSnippet, ResourceTemplates, XBlock):
|
||||
self.xmodule_runtime.xmodule_instance = descriptor._xmodule # pylint: disable=protected-access
|
||||
return self.xmodule_runtime.xmodule_instance
|
||||
|
||||
course_id = module_attr('course_id')
|
||||
displayable_items = module_attr('displayable_items')
|
||||
get_display_items = module_attr('get_display_items')
|
||||
get_icon_class = module_attr('get_icon_class')
|
||||
|
||||
@@ -2,8 +2,16 @@
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%inherit file="../main.html" />
|
||||
|
||||
<%block name="bodyclass">register verification-process step-select-track</%block>
|
||||
<%block name="title"><title>${_("Register for {} | Choose Your Track").format(course_name)}</title></%block>
|
||||
<%block name="bodyclass">register verification-process step-select-track ${'is-upgrading' if upgrade else ''}</%block>
|
||||
<%block name="title">
|
||||
<title>
|
||||
%if upgrade:
|
||||
${_("Upgrade Your Registration for {} | Choose Your Track").format(course_name)}
|
||||
%else:
|
||||
${_("Register for {} | Choose Your Track").format(course_name)}
|
||||
%endif
|
||||
</title>
|
||||
</%block>
|
||||
|
||||
<%block name="js_extra">
|
||||
<script type="text/javascript">
|
||||
@@ -48,7 +56,10 @@ $(document).ready(function() {
|
||||
|
||||
<div class="wrapper-register-choose wrapper-content-main">
|
||||
<article class="register-choose content-main">
|
||||
|
||||
%if not upgrade:
|
||||
<h3 class="title">${_("Select your track:")}</h3>
|
||||
%endif
|
||||
|
||||
<form class="form-register-choose" method="post" name="enrollment_mode_form" id="enrollment_mode_form">
|
||||
|
||||
@@ -57,9 +68,16 @@ $(document).ready(function() {
|
||||
<div class="wrapper-copy">
|
||||
<span class="deco-ribbon"></span>
|
||||
<h4 class="title">${_("Certificate of Achievement (ID Verified)")}</h4>
|
||||
<div class="copy">
|
||||
<p>${_("Sign up and work toward a verified Certificate of Achievement.")}</p>
|
||||
</div>
|
||||
|
||||
%if upgrade:
|
||||
<div class="copy">
|
||||
<p>${_("Upgrade and work toward a verified Certificate of Achievement.")}</p>
|
||||
</div>
|
||||
%else:
|
||||
<div class="copy">
|
||||
<p>${_("Sign up and work toward a verified Certificate of Achievement.")}</p>
|
||||
</div>
|
||||
%endif
|
||||
</div>
|
||||
|
||||
<div class="field field-certificate-contribution">
|
||||
@@ -115,16 +133,28 @@ $(document).ready(function() {
|
||||
|
||||
<ul class="list-actions">
|
||||
<li class="action action-select">
|
||||
<input type="submit" name="mode" value="Select Certificate" />
|
||||
%if upgrade:
|
||||
<input type="submit" name="mode" value="Upgrade Your Registration" />
|
||||
%else:
|
||||
<input type="submit" name="mode" value="Select Certificate" />
|
||||
%endif
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="help help-register">
|
||||
<h3 class="title">${_("Verified Registration Requirements")}</h3>
|
||||
<div class="copy">
|
||||
<p>${_("To register for a Verified Certificate of Achievement option, you will need a webcam, a credit or debit card, and an ID.")}</p>
|
||||
</div>
|
||||
|
||||
%if upgrade:
|
||||
<div class="copy">
|
||||
<p>${_("To upgrade your registration and work towards a Verified Certificate of Achievement, you will need a webcam, a credit or debit card, and an ID.")}</p>
|
||||
</div>
|
||||
%else:
|
||||
<div class="copy">
|
||||
<p>${_("To register for a Verified Certificate of Achievement option, you will need a webcam, a credit or debit card, and an ID.")}</p>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
<h3 class="title">${_("What is an ID Verified Certificate?")}</h3>
|
||||
<div class="copy">
|
||||
@@ -133,25 +163,29 @@ $(document).ready(function() {
|
||||
</div>
|
||||
% endif
|
||||
|
||||
% if "audit" in modes:
|
||||
<span class="deco-divider">
|
||||
<span class="copy">${_("or")}</span>
|
||||
</span>
|
||||
<div class="register-choice register-choice-audit">
|
||||
<div class="wrapper-copy">
|
||||
<h4 class="title">${_("Audit This Course")}</h4>
|
||||
<div class="copy">
|
||||
<p>${_("Sign up to audit this course for free and track your own progress.")}</p>
|
||||
</div>
|
||||
</div>
|
||||
%if not upgrade:
|
||||
|
||||
<ul class="list-actions">
|
||||
<li class="action action-select">
|
||||
<input type="submit" name="mode" value="Select Audit" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
% if "audit" in modes:
|
||||
<span class="deco-divider">
|
||||
<span class="copy">${_("or")}</span>
|
||||
</span>
|
||||
<div class="register-choice register-choice-audit">
|
||||
<div class="wrapper-copy">
|
||||
<h4 class="title">${_("Audit This Course")}</h4>
|
||||
<div class="copy">
|
||||
<p>${_("Sign up to audit this course for free and track your own progress.")}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="list-actions">
|
||||
<li class="action action-select">
|
||||
<input type="submit" name="mode" value="Select Audit" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
|
||||
%endif
|
||||
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }">
|
||||
</form>
|
||||
|
||||
@@ -35,6 +35,7 @@ Feature: LMS.Verified certificates
|
||||
And I navigate to my dashboard
|
||||
Then I see the course on my dashboard
|
||||
And I see that I am on the verified track
|
||||
And I do not see the upsell link on my dashboard
|
||||
|
||||
# Not easily automated
|
||||
# Scenario: I can re-take photos
|
||||
@@ -70,3 +71,24 @@ Feature: LMS.Verified certificates
|
||||
And the course has an honor mode
|
||||
When I give a reason why I cannot pay
|
||||
Then I should see the course on my dashboard
|
||||
|
||||
Scenario: The upsell offer is on the dashboard if I am auditing.
|
||||
Given I am logged in
|
||||
When I select the audit track
|
||||
And I navigate to my dashboard
|
||||
Then I see the upsell link on my dashboard
|
||||
|
||||
Scenario: I can take the upsell offer and pay for it
|
||||
Given I am logged in
|
||||
And I select the audit track
|
||||
And I navigate to my dashboard
|
||||
When I see the upsell link on my dashboard
|
||||
And I select the upsell link on my dashboard
|
||||
And I select the verified track for upgrade
|
||||
And I submit my photos and confirm
|
||||
And I am at the payment page
|
||||
And I submit valid payment information
|
||||
And I navigate to my dashboard
|
||||
Then I see the course on my dashboard
|
||||
And I see that I am on the verified track
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ from lettuce.django import django_url
|
||||
from course_modes.models import CourseMode
|
||||
from nose.tools import assert_equal
|
||||
|
||||
UPSELL_LINK_CSS = '.message-upsell a.action-upgrade[href*="edx/999/Certificates"]'
|
||||
|
||||
def create_cert_course():
|
||||
world.clear_courses()
|
||||
org = 'edx'
|
||||
@@ -53,7 +55,7 @@ def the_course_has_an_honor_mode(step):
|
||||
mode_slug='honor',
|
||||
mode_display_name='honor mode',
|
||||
min_price=0,
|
||||
)
|
||||
)
|
||||
assert isinstance(honor_mode, CourseMode)
|
||||
|
||||
|
||||
@@ -73,14 +75,28 @@ def select_contribution(amount=32):
|
||||
assert world.css_find(radio_css).selected
|
||||
|
||||
|
||||
def click_verified_track_button():
|
||||
world.wait_for_ajax_complete()
|
||||
btn_css = 'input[value="Select Certificate"]'
|
||||
world.css_click(btn_css)
|
||||
|
||||
|
||||
@step(u'I select the verified track for upgrade')
|
||||
def select_verified_track_upgrade(step):
|
||||
select_contribution(32)
|
||||
world.wait_for_ajax_complete()
|
||||
btn_css = 'input[value="Upgrade Your Registration"]'
|
||||
world.css_click(btn_css)
|
||||
# TODO: might want to change this depending on the changes for upgrade
|
||||
assert world.is_css_present('section.progress')
|
||||
|
||||
|
||||
@step(u'I select the verified track$')
|
||||
def select_the_verified_track(step):
|
||||
create_cert_course()
|
||||
register()
|
||||
select_contribution(32)
|
||||
world.wait_for_ajax_complete()
|
||||
btn_css = 'input[value="Select Certificate"]'
|
||||
world.css_click(btn_css)
|
||||
click_verified_track_button()
|
||||
assert world.is_css_present('section.progress')
|
||||
|
||||
|
||||
@@ -203,6 +219,20 @@ def submitted_photos_to_verify_my_identity(step):
|
||||
step.given('I go to step "4"')
|
||||
|
||||
|
||||
@step(u'I submit my photos and confirm')
|
||||
def submit_photos_and_confirm(step):
|
||||
step.given('I go to step "1"')
|
||||
step.given('I capture my "face" photo')
|
||||
step.given('I approve my "face" photo')
|
||||
step.given('I go to step "2"')
|
||||
step.given('I capture my "photo_id" photo')
|
||||
step.given('I approve my "photo_id" photo')
|
||||
step.given('I go to step "3"')
|
||||
step.given('I select a contribution amount')
|
||||
step.given('I confirm that the details match')
|
||||
step.given('I go to step "4"')
|
||||
|
||||
|
||||
@step(u'I see that my payment was successful')
|
||||
def see_that_my_payment_was_successful(step):
|
||||
title = world.css_find('div.wrapper-content-main h3.title')
|
||||
@@ -221,6 +251,27 @@ def see_the_course_on_my_dashboard(step):
|
||||
assert world.is_css_present(course_link_css)
|
||||
|
||||
|
||||
@step(u'I see the upsell link on my dashboard')
|
||||
def see_upsell_link_on_my_dashboard(step):
|
||||
course_link_css = UPSELL_LINK_CSS
|
||||
assert world.is_css_present(course_link_css)
|
||||
|
||||
|
||||
@step(u'I do not see the upsell link on my dashboard')
|
||||
def see_upsell_link_on_my_dashboard(step):
|
||||
course_link_css = UPSELL_LINK_CSS
|
||||
assert not world.is_css_present(course_link_css)
|
||||
|
||||
|
||||
@step(u'I select the upsell link on my dashboard')
|
||||
def see_upsell_link_on_my_dashboard(step):
|
||||
# expand the upsell section
|
||||
world.css_click('.message-upsell')
|
||||
course_link_css = UPSELL_LINK_CSS
|
||||
# click the actual link
|
||||
world.css_click(course_link_css)
|
||||
|
||||
|
||||
@step(u'I see that I am on the verified track')
|
||||
def see_that_i_am_on_the_verified_track(step):
|
||||
id_verified_css = 'li.course-item article.course.verified'
|
||||
|
||||
@@ -44,12 +44,15 @@ class VerifyView(View):
|
||||
before proceeding to payment
|
||||
|
||||
"""
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
|
||||
# If the user has already been verified within the given time period,
|
||||
# redirect straight to the payment -- no need to verify again.
|
||||
if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user):
|
||||
return redirect(
|
||||
reverse('verify_student_verified',
|
||||
kwargs={'course_id': course_id}))
|
||||
kwargs={'course_id': course_id}) + "?upgrade={}".format(upgrade)
|
||||
)
|
||||
elif CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
|
||||
return redirect(reverse('dashboard'))
|
||||
else:
|
||||
@@ -85,6 +88,7 @@ class VerifyView(View):
|
||||
"currency": verify_mode.currency.upper(),
|
||||
"chosen_price": chosen_price,
|
||||
"min_price": verify_mode.min_price,
|
||||
"upgrade": upgrade,
|
||||
}
|
||||
|
||||
return render_to_response('verify_student/photo_verification.html', context)
|
||||
@@ -100,6 +104,7 @@ class VerifiedView(View):
|
||||
"""
|
||||
Handle the case where we have a get request
|
||||
"""
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
|
||||
return redirect(reverse('dashboard'))
|
||||
verify_mode = CourseMode.mode_for_course(course_id, "verified")
|
||||
@@ -117,6 +122,7 @@ class VerifiedView(View):
|
||||
"purchase_endpoint": get_purchase_endpoint(),
|
||||
"currency": verify_mode.currency.upper(),
|
||||
"chosen_price": chosen_price,
|
||||
"upgrade": upgrade,
|
||||
}
|
||||
return render_to_response('verify_student/verified.html', context)
|
||||
|
||||
@@ -250,6 +256,7 @@ def show_requirements(request, course_id):
|
||||
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == 'verified':
|
||||
return redirect(reverse('dashboard'))
|
||||
|
||||
upgrade = request.GET.get('upgrade', False)
|
||||
course = course_from_id(course_id)
|
||||
context = {
|
||||
"course_id": course_id,
|
||||
@@ -257,5 +264,6 @@ def show_requirements(request, course_id):
|
||||
"course_org": course.display_org_with_default,
|
||||
"course_num": course.display_number_with_default,
|
||||
"is_not_active": not request.user.is_active,
|
||||
"upgrade": upgrade,
|
||||
}
|
||||
return render_to_response("verify_student/show_requirements.html", context)
|
||||
|
||||
@@ -100,3 +100,16 @@
|
||||
// outline: thin dotted !important;
|
||||
}
|
||||
}
|
||||
|
||||
// removes list styling/spacing when using uls, ols for navigation and less content-centric cases
|
||||
%ui-no-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
text-indent: 0;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,4 +282,5 @@
|
||||
border-radius: ($baseline/5);
|
||||
padding: ($baseline/2) $baseline;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.1rem;
|
||||
}
|
||||
|
||||
@@ -227,6 +227,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// course listings
|
||||
.my-courses {
|
||||
float: left;
|
||||
@@ -272,6 +274,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// UI: course list
|
||||
.listing-courses {
|
||||
@extend %ui-no-list;
|
||||
@@ -289,6 +293,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// UI: individual course item
|
||||
.course {
|
||||
@include box-sizing(box);
|
||||
@@ -416,25 +422,27 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// STATE: course mode - verified
|
||||
&.verified {
|
||||
@extend %ui-depth2;
|
||||
margin-top: ($baseline*2.5);
|
||||
border-top: 1px solid $verified-color-lvl3;
|
||||
padding-top: ($baseline*1.25);
|
||||
background: $white;
|
||||
position: relative;
|
||||
|
||||
// FIXME: bad, but needed selector!
|
||||
.info > hgroup .date-block {
|
||||
top: ($baseline*1.25);
|
||||
.cover {
|
||||
border-radius: ($baseline/10);
|
||||
border: 1px solid $verified-color-lvl3;
|
||||
border-bottom: 4px solid $verified-color-lvl3;
|
||||
padding: ($baseline/10);
|
||||
}
|
||||
|
||||
// course enrollment status message
|
||||
.sts-enrollment {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: -28px;
|
||||
right: ($baseline/2);
|
||||
top: 105px;
|
||||
left: 55px;
|
||||
bottom: ($baseline/2);
|
||||
text-align: center;
|
||||
|
||||
.label {
|
||||
@@ -454,53 +462,176 @@
|
||||
@extend %copy-badge;
|
||||
border-radius: 0;
|
||||
padding: ($baseline/4) ($baseline/2) ($baseline/4) $baseline;
|
||||
color: $white;
|
||||
background: $verified-color-lvl3;
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.message-status {
|
||||
// ====================
|
||||
|
||||
// UI: message
|
||||
.message {
|
||||
@include clearfix;
|
||||
border-radius: 3px;
|
||||
display: none;
|
||||
z-index: 10;
|
||||
margin: 20px 0 10px;
|
||||
padding: 15px 20px;
|
||||
margin: $baseline 0 ($baseline/2) 0;
|
||||
padding: ($baseline*0.75) $baseline;
|
||||
font-family: $sans-serif;
|
||||
background: tint($yellow,70%);
|
||||
border: 1px solid #ccc;
|
||||
|
||||
.message-copy {
|
||||
// STATE: shown
|
||||
&.is-shown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
font-family: $sans-serif;
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
|
||||
a {
|
||||
font-family: $sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include clearfix;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.message-title,
|
||||
.message-copy .title {
|
||||
@extend %t-title5;
|
||||
@extend %t-weight4;
|
||||
margin-bottom: ($baseline/4);
|
||||
}
|
||||
|
||||
.message-copy,
|
||||
.message-copy .copy {
|
||||
@extend %t-copy-sub1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// CASE: expandable
|
||||
&.is-expandable {
|
||||
|
||||
.wrapper-tip {
|
||||
|
||||
.message-title, .message-copy {
|
||||
@include transition(color 0.25s ease-in-out 0);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
// STATE: hover
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
||||
.message-title, .message-copy {
|
||||
color: $link-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper-extended {
|
||||
@include transition(opacity 0.25s ease-in-out 0);
|
||||
display: none;
|
||||
opacity: 0.0;
|
||||
}
|
||||
|
||||
// STATE: is expanded
|
||||
&.is-expanded {
|
||||
|
||||
.wrapper-extended {
|
||||
display: block;
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TYPE: upsell
|
||||
.message-upsell {
|
||||
|
||||
.wrapper-tip {
|
||||
@include clearfix();
|
||||
|
||||
.message-title {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.message-copy {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper-extended {
|
||||
padding: ($baseline/2) 0;
|
||||
|
||||
.message-copy {
|
||||
margin-bottom: $baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.action-upgrade {
|
||||
@extend %btn-primary-green;
|
||||
@include clearfix();
|
||||
position: relative;
|
||||
left: ($baseline/2);
|
||||
padding: 8px $baseline 8px ($baseline*2);
|
||||
|
||||
.deco-graphic {
|
||||
position: absolute;
|
||||
top: -($baseline/4);
|
||||
left: -($baseline*0.75);
|
||||
width: ($baseline*2);
|
||||
}
|
||||
|
||||
span {
|
||||
color: $white; // nasty but needed override for poor <span> styling
|
||||
}
|
||||
|
||||
.copy, .copy-sub {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.copy {
|
||||
@extend %t-action3;
|
||||
@extend %t-weight4;
|
||||
margin-right: $baseline;
|
||||
}
|
||||
|
||||
.copy-sub {
|
||||
@extend %t-action4;
|
||||
opacity: 0.875;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TYPE: status
|
||||
.message-status {
|
||||
background: tint($yellow,70%);
|
||||
border-color: #ccc;
|
||||
|
||||
.message-copy {
|
||||
@extend %t-copy-sub1;
|
||||
margin: 0;
|
||||
|
||||
.grade-value {
|
||||
font-size: 1.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
|
||||
a {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
@include clearfix;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
.action {
|
||||
float: left;
|
||||
@@ -589,10 +720,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.is-shown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.course-status-processing {
|
||||
|
||||
}
|
||||
@@ -614,7 +741,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
a.unenroll {
|
||||
float: right;
|
||||
display: block;
|
||||
|
||||
@@ -1,6 +1,87 @@
|
||||
// lms - views - verification flow
|
||||
// ====================
|
||||
|
||||
// MISC: extends - type
|
||||
// application: canned headings
|
||||
%hd-lv1 {
|
||||
@extend %t-title1;
|
||||
@extend %t-weight1;
|
||||
color: $m-gray-d4;
|
||||
margin: 0 0 ($baseline*2) 0;
|
||||
}
|
||||
|
||||
%hd-lv2 {
|
||||
@extend %t-title4;
|
||||
@extend %t-weight1;
|
||||
margin: 0 0 ($baseline*0.75) 0;
|
||||
border-bottom: 1px solid $m-gray-l4;
|
||||
padding-bottom: ($baseline/2);
|
||||
color: $m-gray-d4;
|
||||
}
|
||||
|
||||
%hd-lv3 {
|
||||
@extend %t-title6;
|
||||
@extend %t-weight4;
|
||||
margin: 0 0 ($baseline/4) 0;
|
||||
color: $m-gray-d4;
|
||||
}
|
||||
|
||||
%hd-lv4 {
|
||||
@extend %t-title6;
|
||||
@extend %t-weight2;
|
||||
margin: 0 0 $baseline 0;
|
||||
color: $m-gray-d4;
|
||||
}
|
||||
|
||||
%hd-lv5 {
|
||||
@extend %t-title7;
|
||||
@extend %t-weight4;
|
||||
margin: 0 0 ($baseline/4) 0;
|
||||
color: $m-gray-d4;
|
||||
}
|
||||
|
||||
// application: canned copy
|
||||
%copy-base {
|
||||
@extend %t-copy-base;
|
||||
color: $m-gray-d2;
|
||||
}
|
||||
|
||||
%copy-lead1 {
|
||||
@extend %t-copy-lead2;
|
||||
color: $m-gray;
|
||||
}
|
||||
|
||||
%copy-detail {
|
||||
@extend %t-copy-sub1;
|
||||
@extend %t-weight3;
|
||||
color: $m-gray-d1;
|
||||
}
|
||||
|
||||
%copy-metadata {
|
||||
@extend %t-copy-sub2;
|
||||
color: $m-gray-d1;
|
||||
|
||||
|
||||
%copy-metadata-value {
|
||||
@extend %t-weight2;
|
||||
}
|
||||
|
||||
%copy-metadata-value {
|
||||
@extend %t-weight4;
|
||||
}
|
||||
}
|
||||
|
||||
// application: canned links
|
||||
%copy-link {
|
||||
border-bottom: 1px dotted transparent;
|
||||
|
||||
&:hover, &:active {
|
||||
border-color: $link-color-d1;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================
|
||||
|
||||
// MISC: extends - button
|
||||
%btn-verify-primary {
|
||||
@extend %btn-primary-green;
|
||||
@@ -72,7 +153,7 @@
|
||||
// ====================
|
||||
|
||||
// VIEW: all verification steps
|
||||
.register.verification-process {
|
||||
.verification-process {
|
||||
|
||||
// reset: box-sizing (making things so right its scary)
|
||||
* {
|
||||
@@ -179,12 +260,16 @@
|
||||
// elements - controls
|
||||
.action-primary {
|
||||
@extend %btn-primary-blue;
|
||||
border: none;
|
||||
// needed for override due to .register a:link styling
|
||||
border: 0 !important;
|
||||
color: $white !important;
|
||||
}
|
||||
|
||||
.action-confirm {
|
||||
@extend %btn-verify-primary;
|
||||
border: none;
|
||||
// needed for override due to .register a:link styling
|
||||
border: 0 !important;
|
||||
color: $white !important;
|
||||
}
|
||||
|
||||
// ====================
|
||||
@@ -382,17 +467,19 @@
|
||||
margin-right: ($baseline/4);
|
||||
opacity: 0.80;
|
||||
color: $white;
|
||||
letter-spacing: 0.1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sts-label {
|
||||
@extend %t-title7;
|
||||
@extend %t-weight4;
|
||||
display: block;
|
||||
margin-bottom: ($baseline/2);
|
||||
border-bottom: ($baseline/10) solid $m-gray-l4;
|
||||
padding-bottom: ($baseline/2);
|
||||
color: $m-gray;
|
||||
color: $m-gray-d1;
|
||||
}
|
||||
|
||||
.sts-course {
|
||||
@@ -1816,3 +1903,11 @@
|
||||
width: 32% !important;
|
||||
}
|
||||
}
|
||||
|
||||
// STATE: upgrading registration type
|
||||
.register.is-upgrading {
|
||||
|
||||
.form-register-choose {
|
||||
margin-top: ($baseline*2) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
<%
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
# course_id = module.location.course_id
|
||||
def get_course_id(module):
|
||||
return module.location.org +'/' + module.location.course +'/' + \
|
||||
module.system.ajax_url.split('/')[4]
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
def _message(reqm, message):
|
||||
return message.format(link="<a href={url}>{url_name}</a>".format(
|
||||
url = reverse('jump_to', kwargs=dict(course_id=get_course_id(reqm),
|
||||
url = reverse('jump_to', kwargs=dict(course_id=reqm.course_id,
|
||||
location=reqm.location.url())),
|
||||
url_name = reqm.display_name_with_default))
|
||||
%>
|
||||
|
||||
@@ -14,6 +14,14 @@
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
|
||||
$('.message.is-expandable .wrapper-tip').bind('click', toggleExpandMessage);
|
||||
|
||||
function toggleExpandMessage(e) {
|
||||
(e).preventDefault();
|
||||
|
||||
$(this).closest('.message.is-expandable').toggleClass('is-expanded');
|
||||
}
|
||||
|
||||
$(".email-settings").click(function(event) {
|
||||
$("#email_settings_course_id").val( $(event.target).data("course-id") );
|
||||
$("#email_settings_course_number").text( $(event.target).data("course-number") );
|
||||
@@ -179,7 +187,8 @@
|
||||
<% show_courseware_link = (course.id in show_courseware_links_for) %>
|
||||
<% cert_status = cert_statuses.get(course.id) %>
|
||||
<% show_email_settings = (course.id in show_email_settings_for) %>
|
||||
<%include file='dashboard/dashboard_course_listing.html' args="course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings" />
|
||||
<% course_mode_info = all_course_modes.get(course.id) %>
|
||||
<%include file='dashboard/dashboard_course_listing.html' args="course=course, enrollment=enrollment, show_courseware_link=show_courseware_link, cert_status=cert_status, show_email_settings=show_email_settings, course_mode_info=course_mode_info" />
|
||||
% endfor
|
||||
|
||||
</ul>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%page args="course, enrollment, show_courseware_link, cert_status, show_email_settings" />
|
||||
<%page args="course, enrollment, show_courseware_link, cert_status, show_email_settings, course_mode_info" />
|
||||
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%!
|
||||
@@ -29,11 +29,11 @@
|
||||
% endif
|
||||
|
||||
% if enrollment.mode == "verified":
|
||||
<span class="sts-enrollment">
|
||||
<span class="label">${_("Enrolled as: ")}</span>
|
||||
<img class="deco-graphic" src="${static.url('images/vcert-ribbon-s.png')}" alt="ID Verified Ribbon/Badge">
|
||||
<span class="sts-enrollment-value">${_("ID Verified")}</span>
|
||||
</span>
|
||||
<span class="sts-enrollment">
|
||||
<span class="label">${_("Enrolled as: ")}</span>
|
||||
<img class="deco-graphic" src="${static.url('images/vcert-ribbon-s.png')}" alt="ID Verified Ribbon/Badge" />
|
||||
<span class="sts-enrollment-value">${_("ID Verified")}</span>
|
||||
</span>
|
||||
% endif
|
||||
|
||||
<section class="info">
|
||||
@@ -95,12 +95,12 @@
|
||||
<li class="action">
|
||||
<a class="btn" href="${cert_status['download_url']}"
|
||||
title="${_('This link will open/download a PDF document')}">
|
||||
Download Your PDF Certificate</a></li>
|
||||
${_("Download Your PDF Certificate")}</a></li>
|
||||
% endif
|
||||
|
||||
% if cert_status['show_survey_button']:
|
||||
<li class="action"><a class="cta" href="${cert_status['survey_url']}">
|
||||
${_('Complete our course feedback survey')}</a></li>
|
||||
${_("Complete our course feedback survey")}</a></li>
|
||||
% endif
|
||||
</ul>
|
||||
% endif
|
||||
@@ -108,6 +108,31 @@
|
||||
|
||||
% endif
|
||||
|
||||
%if course_mode_info['show_upsell']:
|
||||
<div class="message message-upsell has-actions is-expandable is-shown">
|
||||
|
||||
<div class="wrapper-tip">
|
||||
<h4 class="message-title">${_("Challenge Yourself!")}</h4>
|
||||
<p class="message-copy">${_("Take this course as an ID-verified student.")}</p>
|
||||
</div>
|
||||
|
||||
<div class="wrapper-extended">
|
||||
<p class="message-copy">${_("You can still sign up for an ID verified certificate for this course. If you plan to complete the whole course, it is a great way to recognize your achievement. {a_start}Learn more about verified certificates{a_end}.").format(a_start='<a href="{}">'.format(marketing_link('WHAT_IS_VERIFIED_CERT')), a_end="</a>")}</p>
|
||||
|
||||
<ul class="actions message-actions">
|
||||
<li class="action-item">
|
||||
<a class="action action-upgrade" href="${reverse('course_modes_choose', kwargs={'course_id': course.id})}?upgrade=True">
|
||||
<img class="deco-graphic" src="${static.url('images/vcert-ribbon-s.png')}" alt="ID Verified Ribbon/Badge">
|
||||
<span class="wrapper-copy">
|
||||
<span class="copy">${_("Upgrade to Verified Track")}</span>
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
% if show_courseware_link:
|
||||
% if course.has_ended():
|
||||
<a href="${course_target}" class="enter-course archived">${_('View Archived Course')}</a>
|
||||
@@ -116,8 +141,6 @@
|
||||
% endif
|
||||
% endif
|
||||
|
||||
|
||||
|
||||
<a href="#unenroll-modal" class="unenroll" rel="leanModal" data-course-id="${course.id}" data-course-number="${course.number}">${_('Unregister')}</a>
|
||||
|
||||
% if show_email_settings:
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
<header class="page-header">
|
||||
<h2 class="title">
|
||||
<span class="sts-label">${_("You are registering for")}</span>
|
||||
%if upgrade:
|
||||
<span class="sts-label">${_("You are upgrading your registration for")}</span>
|
||||
%else:
|
||||
<span class="sts-label">${_("You are registering for")}</span>
|
||||
%endif
|
||||
|
||||
<span class="wrapper-sts">
|
||||
<span class="sts-course">
|
||||
@@ -13,7 +17,11 @@
|
||||
|
||||
<span class="sts-track">
|
||||
<span class="sts-track-value">
|
||||
<span class="context">${_("Registering as: ")}</span> ${_("ID Verified")}
|
||||
%if upgrade:
|
||||
<span class="context">${_("Upgrading to:")}</span> ${_("ID Verified")}
|
||||
%else:
|
||||
<span class="context">${_("Registering as: ")}</span> ${_("ID Verified")}
|
||||
%endif
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -11,14 +11,21 @@
|
||||
</li>
|
||||
|
||||
<li class="help-item help-item-coldfeet">
|
||||
<h3 class="title">${_("Change your mind?")}</h3>
|
||||
<div class="copy">
|
||||
<p>${_("You can always {a_start} audit the course for free {a_end} without verifying.").format(a_start='<a rel="external" href="/course_modes/choose/' + course_id + '">', a_end="</a>")}</p>
|
||||
</div>
|
||||
%if upgrade:
|
||||
<h3 class="title">${_("Change your mind?")}</h3>
|
||||
<div class="copy">
|
||||
<p>${_("You can always continue to audit the course without verifying.")}</p>
|
||||
</div>
|
||||
%else:
|
||||
<h3 class="title">${_("Change your mind?")}</h3>
|
||||
<div class="copy">
|
||||
<p>${_("You can always {a_start} audit the course for free {a_end} without verifying.").format(a_start='<a rel="external" href="/course_modes/choose/' + course_id + '">', a_end="</a>")}</p>
|
||||
</div>
|
||||
%endif
|
||||
</li>
|
||||
|
||||
<li class="help-item help-item-technical">
|
||||
<h3 class="title">${_("Having Technical Trouble?")}</h3>
|
||||
<h3 class="title">${_("Technical Requirements")}</h3>
|
||||
<div class="copy">
|
||||
<p>${_("Please make sure your browser is updated to the {strong_start}{a_start}most recent version possible{a_end}{strong_end}. Also, please make sure your {strong_start}web cam is plugged in, turned on, and allowed to function in your web browser (commonly adjustable in your browser settings).{strong_end}").format(a_start='<a rel="external" href="http://browsehappy.com/">', a_end="</a>", strong_start="<strong>", strong_end="</strong>")}</p>
|
||||
</div>
|
||||
|
||||
@@ -3,8 +3,16 @@
|
||||
<%inherit file="../main.html" />
|
||||
<%namespace name='static' file='/static_content.html'/>
|
||||
|
||||
<%block name="bodyclass">register verification-process step-photos</%block>
|
||||
<%block name="title"><title>${_("Register for {} | Verification").format(course_name)}</title></%block>
|
||||
<%block name="bodyclass">register verification-process step-photos ${'is-upgrading' if upgrade else ''}</%block>
|
||||
<%block name="title">
|
||||
<title>
|
||||
%if upgrade:
|
||||
${_("Upgrade Your Registration for {} | Verification").format(course_name)}
|
||||
%else:
|
||||
${_("Register for {} | Verification").format(course_name)}
|
||||
%endif
|
||||
</title>
|
||||
</%block>
|
||||
|
||||
<%block name="js_extra">
|
||||
<script src="${static.url('js/vendor/responsive-carousel/responsive-carousel.js')}"></script>
|
||||
@@ -172,7 +180,12 @@
|
||||
<dt class="faq-question">${_("What do you do with this picture?")}</dt>
|
||||
<dd class="faq-answer">${_("We only use it to verify your identity. It is not displayed anywhere.")}</dd>
|
||||
<dt class="faq-question">${_("What if my camera isn't working?")}</dt>
|
||||
<dd class="faq-answer">${_("You can always {a_start} audit the course for free {a_end} without verifying.").format(a_start='<a rel="external" href="/course_modes/choose/' + course_id + '">', a_end="</a>")}</dd>
|
||||
|
||||
%if upgrade:
|
||||
<dd class="faq-answer">${_("You can always continue to audit the course without verifying.")}</dd>
|
||||
%else:
|
||||
<dd class="faq-answer">${_("You can always {a_start} audit the course for free {a_end} without verifying.").format(a_start='<a rel="external" href="/course_modes/choose/' + course_id + '">', a_end="</a>")}</dd>
|
||||
%endif
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%inherit file="../main.html" />
|
||||
<%block name="bodyclass">register verification-process step-requirements</%block>
|
||||
<%block name="title"><title>${_("Register for {}").format(course_name)}</title></%block>
|
||||
<%block name="bodyclass">register verification-process step-requirements ${'is-upgrading' if upgrade else ''}</%block>
|
||||
<%block name="title">
|
||||
<title>
|
||||
%if upgrade:
|
||||
${_("Upgrade Your Registration for {}").format(course_name)}
|
||||
%else:
|
||||
${_("Register for {}").format(course_name)}
|
||||
%endif
|
||||
</title>
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
%if is_not_active:
|
||||
@@ -71,11 +79,19 @@
|
||||
|
||||
<div class="wrapper-content-main">
|
||||
<article class="content-main">
|
||||
<h3 class="title">${_("What You Will Need to Register")}</h3>
|
||||
%if upgrade:
|
||||
<h3 class="title">${_("What You Will Need to Upgrade")}</h3>
|
||||
|
||||
<div class="instruction">
|
||||
<p>${_("There are three things you will need to register as an ID verified student:")}</p>
|
||||
</div>
|
||||
<div class="instruction">
|
||||
<p>${_("There are three things you will need to upgrade to being an ID verified student:")}</p>
|
||||
</div>
|
||||
%else:
|
||||
<h3 class="title">${_("What You Will Need to Register")}</h3>
|
||||
|
||||
<div class="instruction">
|
||||
<p>${_("There are three things you will need to register as an ID verified student:")}</p>
|
||||
</div>
|
||||
%endif
|
||||
|
||||
<ul class="list-reqs ${"account-not-activated" if is_not_active else ""}">
|
||||
%if is_not_active:
|
||||
@@ -149,11 +165,16 @@
|
||||
</ul>
|
||||
|
||||
<nav class="nav-wizard ${"is-not-ready" if is_not_active else "is-ready"}">
|
||||
<span class="help help-inline">${_("Missing something? You can always {a_start} audit this course instead {a_end}").format(a_start='<a href="/course_modes/choose/' + course_id + '">', a_end="</a>")}</span>
|
||||
|
||||
%if upgrade:
|
||||
<span class="help help-inline">${_("Missing something? You can always continue to audit this course instead.")}</span>
|
||||
%else:
|
||||
<span class="help help-inline">${_("Missing something? You can always {a_start} audit this course instead {a_end}").format(a_start='<a href="/course_modes/choose/' + course_id + '">', a_end="</a>")}</span>
|
||||
%endif
|
||||
|
||||
<ol class="wizard-steps">
|
||||
<li class="wizard-step">
|
||||
<a class="next action-primary ${"disabled" if is_not_active else ""}" id="face_next_button" href="${reverse('verify_student_verify', kwargs={'course_id': course_id})}">${_("Go to Step 1: Take my Photo")}</a>
|
||||
<a class="next action-primary ${"disabled" if is_not_active else ""}" id="face_next_button" href="${reverse('verify_student_verify', kwargs={'course_id': course_id})}?upgrade=${upgrade}">${_("Go to Step 1: Take my Photo")}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
Reference in New Issue
Block a user