Commit 43d8c7a7 by David Ormsbee

Merge branch 'release'

Conflicts:
	lms/djangoapps/shoppingcart/processors/CyberSource2.py
parents a0a5746e 1a4ad061
...@@ -94,6 +94,7 @@ class ChooseModeView(View): ...@@ -94,6 +94,7 @@ class ChooseModeView(View):
"error": error, "error": error,
"upgrade": upgrade, "upgrade": upgrade,
"can_audit": "audit" in modes, "can_audit": "audit" in modes,
"responsive": True
} }
if "verified" in modes: if "verified" in modes:
context["suggested_prices"] = [ context["suggested_prices"] = [
......
...@@ -485,6 +485,7 @@ class LoginOAuthTokenMixin(object): ...@@ -485,6 +485,7 @@ class LoginOAuthTokenMixin(object):
self._setup_user_response(success=True) self._setup_user_response(success=True)
response = self.client.post(self.url, {"access_token": "dummy"}) response = self.client.post(self.url, {"access_token": "dummy"})
self.assertEqual(response.status_code, 204) self.assertEqual(response.status_code, 204)
self.assertEqual(self.client.session['_auth_user_id'], self.user.id)
def test_invalid_token(self): def test_invalid_token(self):
self._setup_user_response(success=False) self._setup_user_response(success=False)
......
...@@ -265,6 +265,7 @@ class DashboardTest(ModuleStoreTestCase): ...@@ -265,6 +265,7 @@ class DashboardTest(ModuleStoreTestCase):
@unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms')
@patch('courseware.views.log.warning') @patch('courseware.views.log.warning')
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
def test_blocked_course_scenario(self, log_warning): def test_blocked_course_scenario(self, log_warning):
self.client.login(username="jack", password="test") self.client.login(username="jack", password="test")
......
...@@ -1114,6 +1114,7 @@ def login_user(request, error=""): # pylint: disable-msg=too-many-statements,un ...@@ -1114,6 +1114,7 @@ def login_user(request, error=""): # pylint: disable-msg=too-many-statements,un
}) # TODO: this should be status code 400 # pylint: disable=fixme }) # TODO: this should be status code 400 # pylint: disable=fixme
@csrf_exempt
@require_POST @require_POST
@social_utils.strategy("social:complete") @social_utils.strategy("social:complete")
def login_oauth_token(request, backend): def login_oauth_token(request, backend):
...@@ -1134,6 +1135,7 @@ def login_oauth_token(request, backend): ...@@ -1134,6 +1135,7 @@ def login_oauth_token(request, backend):
pass pass
# do_auth can return a non-User object if it fails # do_auth can return a non-User object if it fails
if user and isinstance(user, User): if user and isinstance(user, User):
login(request, user)
return JsonResponse(status=204) return JsonResponse(status=204)
else: else:
# Ensure user does not re-enter the pipeline # Ensure user does not re-enter the pipeline
......
/**
* Adds rwd classes and click handlers.
*/
(function($) {
'use strict';
var rwd = (function() {
var _fn = {
header: 'header.global-new',
footer: '.edx-footer-new',
resultsUrl: 'course-search',
init: function() {
_fn.$header = $( _fn.header );
_fn.$footer = $( _fn.footer );
_fn.$nav = _fn.$header.find('nav');
_fn.$globalNav = _fn.$nav.find('.nav-global');
_fn.add.elements();
_fn.add.classes();
_fn.eventHandlers.init();
},
add: {
classes: function() {
// Add any RWD-specific classes
_fn.$header.addClass('rwd');
_fn.$footer.addClass('rwd');
},
elements: function() {
_fn.add.burger();
_fn.add.registerLink();
},
burger: function() {
_fn.$nav.prepend([
'<a href="#" class="mobile-menu-button" aria-label="menu">',
'<i class="icon-reorder" aria-hidden="true"></i>',
'</a>'
].join(''));
},
registerLink: function() {
var $register = _fn.$nav.find('.cta-register'),
$li = {},
$a = {},
count = 0;
// Add if register link is shown
if ( $register.length > 0 ) {
count = _fn.$globalNav.find('li').length + 1;
// Create new li
$li = $('<li/>');
$li.addClass('desktop-hide nav-global-0' + count);
// Clone register link and remove classes
$a = $register.clone();
$a.removeClass();
// append to DOM
$a.appendTo( $li );
_fn.$globalNav.append( $li );
}
}
},
eventHandlers: {
init: function() {
_fn.eventHandlers.click();
},
click: function() {
// Toggle menu
_fn.$nav.on( 'click', '.mobile-menu-button', _fn.toggleMenu );
}
},
toggleMenu: function( event ) {
event.preventDefault();
_fn.$globalNav.toggleClass('show');
}
};
return {
init: _fn.init
};
})();
setTimeout( function() {
rwd.init();
}, 100);
})(jQuery);
...@@ -10,7 +10,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase ...@@ -10,7 +10,7 @@ from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from helpers import LoginEnrollmentTestCase from helpers import LoginEnrollmentTestCase
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
from course_modes.models import CourseMode
from xmodule.course_module import ( from xmodule.course_module import (
CATALOG_VISIBILITY_CATALOG_AND_ABOUT, CATALOG_VISIBILITY_NONE) CATALOG_VISIBILITY_CATALOG_AND_ABOUT, CATALOG_VISIBILITY_NONE)
...@@ -56,6 +56,7 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -56,6 +56,7 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.course_with_visibility = CourseFactory.create( self.course_with_visibility = CourseFactory.create(
display_name='visible_course', display_name='visible_course',
org='TestMicrositeX', org='TestMicrositeX',
course="foo",
catalog_visibility=CATALOG_VISIBILITY_CATALOG_AND_ABOUT, catalog_visibility=CATALOG_VISIBILITY_CATALOG_AND_ABOUT,
) )
...@@ -190,3 +191,33 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase): ...@@ -190,3 +191,33 @@ class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase):
url = reverse('about_course', args=[self.course_hidden_visibility.id.to_deprecated_string()]) url = reverse('about_course', args=[self.course_hidden_visibility.id.to_deprecated_string()])
resp = self.client.get(url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME) resp = self.client.get(url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
self.assertEqual(resp.status_code, 404) self.assertEqual(resp.status_code, 404)
@override_settings(SITE_NAME=settings.MICROSITE_TEST_HOSTNAME)
def test_paid_course_registration(self):
"""
Make sure that Microsite overrides on the ENABLE_SHOPPING_CART and
ENABLE_PAID_COURSE_ENROLLMENTS are honored
"""
course_mode = CourseMode(
course_id=self.course_with_visibility.id,
mode_slug="honor",
mode_display_name="honor cert",
min_price=10,
)
course_mode.save()
# first try on the non microsite, which
# should pick up the global configuration (where ENABLE_PAID_COURSE_REGISTRATIONS = False)
url = reverse('about_course', args=[self.course_with_visibility.id.to_deprecated_string()])
resp = self.client.get(url)
self.assertEqual(resp.status_code, 200)
self.assertIn("Register for {}".format(self.course_with_visibility.id.course), resp.content)
self.assertNotIn("Add {} to Cart ($10)".format(self.course_with_visibility.id.course), resp.content)
# now try on the microsite
url = reverse('about_course', args=[self.course_with_visibility.id.to_deprecated_string()])
resp = self.client.get(url, HTTP_HOST=settings.MICROSITE_TEST_HOSTNAME)
self.assertEqual(resp.status_code, 200)
self.assertNotIn("Register for {}".format(self.course_with_visibility.id.course), resp.content)
self.assertIn("Add {} to Cart ($10)".format(self.course_with_visibility.id.course), resp.content)
self.assertIn('$("#add_to_cart_post").click', resp.content)
...@@ -49,6 +49,7 @@ from xmodule.tabs import CourseTabList, StaffGradingTab, PeerGradingTab, OpenEnd ...@@ -49,6 +49,7 @@ from xmodule.tabs import CourseTabList, StaffGradingTab, PeerGradingTab, OpenEnd
from xmodule.x_module import STUDENT_VIEW from xmodule.x_module import STUDENT_VIEW
import shoppingcart import shoppingcart
from shoppingcart.models import CourseRegistrationCode from shoppingcart.models import CourseRegistrationCode
from shoppingcart.utils import is_shopping_cart_enabled
from opaque_keys import InvalidKeyError from opaque_keys import InvalidKeyError
from microsite_configuration import microsite from microsite_configuration import microsite
...@@ -731,8 +732,9 @@ def course_about(request, course_id): ...@@ -731,8 +732,9 @@ def course_about(request, course_id):
registration_price = 0 registration_price = 0
in_cart = False in_cart = False
reg_then_add_to_cart_link = "" reg_then_add_to_cart_link = ""
if (settings.FEATURES.get('ENABLE_SHOPPING_CART') and
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')): _is_shopping_cart_enabled = is_shopping_cart_enabled()
if (_is_shopping_cart_enabled):
registration_price = CourseMode.min_course_price_for_currency(course_key, registration_price = CourseMode.min_course_price_for_currency(course_key,
settings.PAID_COURSE_REGISTRATION_CURRENCY[0]) settings.PAID_COURSE_REGISTRATION_CURRENCY[0])
if request.user.is_authenticated(): if request.user.is_authenticated():
...@@ -774,6 +776,8 @@ def course_about(request, course_id): ...@@ -774,6 +776,8 @@ def course_about(request, course_id):
# We do not want to display the internal courseware header, which is used when the course is found in the # We do not want to display the internal courseware header, which is used when the course is found in the
# context. This value is therefor explicitly set to render the appropriate header. # context. This value is therefor explicitly set to render the appropriate header.
'disable_courseware_header': True, 'disable_courseware_header': True,
'is_shopping_cart_enabled': _is_shopping_cart_enabled,
'cart_link': reverse('shoppingcart.views.show_cart'),
}) })
......
...@@ -1636,6 +1636,7 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase ...@@ -1636,6 +1636,7 @@ class TestInstructorAPILevelsAccess(ModuleStoreTestCase, LoginEnrollmentTestCase
@ddt.ddt @ddt.ddt
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE) @override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCase): class TestInstructorAPILevelsDataDump(ModuleStoreTestCase, LoginEnrollmentTestCase):
""" """
Test endpoints that show data without side effects. Test endpoints that show data without side effects.
......
...@@ -5,9 +5,9 @@ navigation. We want to do this in the context_processor to ...@@ -5,9 +5,9 @@ navigation. We want to do this in the context_processor to
1) keep database accesses out of templates (this led to a transaction bug with user email changes) 1) keep database accesses out of templates (this led to a transaction bug with user email changes)
2) because navigation.html is "called" by being included in other templates, there's no "views.py" to put this. 2) because navigation.html is "called" by being included in other templates, there's no "views.py" to put this.
""" """
from django.conf import settings
import shoppingcart from .models import Order, PaidCourseRegistration, CourseRegCodeItem
from microsite_configuration import microsite from .utils import is_shopping_cart_enabled
def user_has_cart_context_processor(request): def user_has_cart_context_processor(request):
...@@ -19,20 +19,12 @@ def user_has_cart_context_processor(request): ...@@ -19,20 +19,12 @@ def user_has_cart_context_processor(request):
display_shopping_cart = ( display_shopping_cart = (
# user is logged in and # user is logged in and
request.user.is_authenticated() and request.user.is_authenticated() and
# settings enable paid course reg # do we have the feature turned on
microsite.get_value( is_shopping_cart_enabled() and
'ENABLE_PAID_COURSE_REGISTRATION',
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')
) and
# settings enable shopping cart
microsite.get_value(
'ENABLE_SHOPPING_CART',
settings.FEATURES.get('ENABLE_SHOPPING_CART')
) and
# user's cart has PaidCourseRegistrations # user's cart has PaidCourseRegistrations
shoppingcart.models.Order.user_cart_has_items( Order.user_cart_has_items(
request.user, request.user,
[shoppingcart.models.PaidCourseRegistration, shoppingcart.models.CourseRegCodeItem] [PaidCourseRegistration, CourseRegCodeItem]
) )
) )
......
"""
This file defines any decorators used by the shopping cart app
"""
from django.http import Http404
from .utils import is_shopping_cart_enabled
def enforce_shopping_cart_enabled(func):
"""
Is a decorator that forces a wrapped method to be run in a runtime
which has the ENABLE_SHOPPING_CART flag set
"""
def func_wrapper(*args, **kwargs):
"""
Wrapper function that does the enforcement that
the shopping cart feature is enabled
"""
if not is_shopping_cart_enabled():
raise Http404
return func(*args, **kwargs)
return func_wrapper
...@@ -352,6 +352,9 @@ class Order(models.Model): ...@@ -352,6 +352,9 @@ class Order(models.Model):
""" """
if self.status == 'purchased': if self.status == 'purchased':
log.error(
u"`purchase` method called on order {}, but order is already purchased.".format(self.id) # pylint: disable=E1101
)
return return
self.status = 'purchased' self.status = 'purchased'
self.purchase_time = datetime.now(pytz.utc) self.purchase_time = datetime.now(pytz.utc)
......
...@@ -367,6 +367,8 @@ def _payment_accepted(order_id, auth_amount, currency, decision): ...@@ -367,6 +367,8 @@ def _payment_accepted(order_id, auth_amount, currency, decision):
total_cost_currency=order.currency total_cost_currency=order.currency
) )
) )
#pylint: disable=attribute-defined-outside-init
ex.order = order ex.order = order
raise ex raise ex
else: else:
......
...@@ -64,6 +64,7 @@ MODULESTORE_CONFIG = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}, incl ...@@ -64,6 +64,7 @@ MODULESTORE_CONFIG = mixed_store_config(settings.COMMON_TEST_DATA_ROOT, {}, incl
@override_settings(MODULESTORE=MODULESTORE_CONFIG) @override_settings(MODULESTORE=MODULESTORE_CONFIG)
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
class ShoppingCartViewsTests(ModuleStoreTestCase): class ShoppingCartViewsTests(ModuleStoreTestCase):
def setUp(self): def setUp(self):
patcher = patch('student.models.tracker') patcher = patch('student.models.tracker')
...@@ -963,8 +964,36 @@ class ShoppingCartViewsTests(ModuleStoreTestCase): ...@@ -963,8 +964,36 @@ class ShoppingCartViewsTests(ModuleStoreTestCase):
((template, _context), _tmp) = render_mock.call_args ((template, _context), _tmp) = render_mock.call_args
self.assertEqual(template, cert_item.single_item_receipt_template) self.assertEqual(template, cert_item.single_item_receipt_template)
def _assert_404(self, url, use_post=False):
"""
Helper method to assert that a given url will return a 404 status code
"""
if use_post:
response = self.client.post(url)
else:
response = self.client.get(url)
self.assertEquals(response.status_code, 404)
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': False})
def test_disabled_paid_courses(self):
"""
Assert that the pages that require ENABLE_PAID_COURSE_REGISTRATION=True return a
HTTP 404 status code when we have this flag turned off
"""
self.login_user()
self._assert_404(reverse('shoppingcart.views.show_cart', args=[]))
self._assert_404(reverse('shoppingcart.views.clear_cart', args=[]))
self._assert_404(reverse('shoppingcart.views.remove_item', args=[]), use_post=True)
self._assert_404(reverse('shoppingcart.views.register_code_redemption', args=["testing"]))
self._assert_404(reverse('shoppingcart.views.use_code', args=[]), use_post=True)
self._assert_404(reverse('shoppingcart.views.update_user_cart', args=[]))
self._assert_404(reverse('shoppingcart.views.reset_code_redemption', args=[]), use_post=True)
self._assert_404(reverse('shoppingcart.views.billing_details', args=[]))
self._assert_404(reverse('shoppingcart.views.register_courses', args=[]))
@override_settings(MODULESTORE=MODULESTORE_CONFIG) @override_settings(MODULESTORE=MODULESTORE_CONFIG)
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_PAID_COURSE_REGISTRATION': True})
class RegistrationCodeRedemptionCourseEnrollment(ModuleStoreTestCase): class RegistrationCodeRedemptionCourseEnrollment(ModuleStoreTestCase):
""" """
Test suite for RegistrationCodeRedemption Course Enrollments Test suite for RegistrationCodeRedemption Course Enrollments
......
...@@ -6,23 +6,19 @@ urlpatterns = patterns('shoppingcart.views', # nopep8 ...@@ -6,23 +6,19 @@ urlpatterns = patterns('shoppingcart.views', # nopep8
url(r'^receipt/(?P<ordernum>[0-9]*)/$', 'show_receipt'), url(r'^receipt/(?P<ordernum>[0-9]*)/$', 'show_receipt'),
url(r'^donation/$', 'donate', name='donation'), url(r'^donation/$', 'donate', name='donation'),
url(r'^csv_report/$', 'csv_report', name='payment_csv_report'), url(r'^csv_report/$', 'csv_report', name='payment_csv_report'),
# These following URLs are only valid if the ENABLE_SHOPPING_CART feature flag is set
url(r'^$', 'show_cart'),
url(r'^clear/$', 'clear_cart'),
url(r'^remove_item/$', 'remove_item'),
url(r'^add/course/{}/$'.format(settings.COURSE_ID_PATTERN), 'add_course_to_cart', name='add_course_to_cart'),
url(r'^register/redeem/(?P<registration_code>[0-9A-Za-z]+)/$', 'register_code_redemption', name='register_code_redemption'),
url(r'^use_code/$', 'use_code'),
url(r'^update_user_cart/$', 'update_user_cart'),
url(r'^reset_code_redemption/$', 'reset_code_redemption'),
url(r'^billing_details/$', 'billing_details', name='billing_details'),
url(r'^register_courses/$', 'register_courses'),
) )
if settings.FEATURES['ENABLE_SHOPPING_CART']:
urlpatterns += patterns(
'shoppingcart.views',
url(r'^$', 'show_cart'),
url(r'^clear/$', 'clear_cart'),
url(r'^remove_item/$', 'remove_item'),
url(r'^add/course/{}/$'.format(settings.COURSE_ID_PATTERN), 'add_course_to_cart', name='add_course_to_cart'),
url(r'^register/redeem/(?P<registration_code>[0-9A-Za-z]+)/$', 'register_code_redemption', name='register_code_redemption'),
url(r'^use_code/$', 'use_code'),
url(r'^update_user_cart/$', 'update_user_cart'),
url(r'^reset_code_redemption/$', 'reset_code_redemption'),
url(r'^billing_details/$', 'billing_details', name='billing_details'),
url(r'^register_courses/$', 'register_courses'),
)
if settings.FEATURES.get('ENABLE_PAYMENT_FAKE'): if settings.FEATURES.get('ENABLE_PAYMENT_FAKE'):
from shoppingcart.tests.payment_fake import PaymentFakeView from shoppingcart.tests.payment_fake import PaymentFakeView
urlpatterns += patterns( urlpatterns += patterns(
......
"""
Utility methods for the Shopping Cart app
"""
from django.conf import settings
from microsite_configuration import microsite
def is_shopping_cart_enabled():
"""
Utility method to check the various configuration to verify that
all of the settings have been enabled
"""
enable_paid_course_registration = microsite.get_value(
'ENABLE_PAID_COURSE_REGISTRATION',
settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION')
)
enable_shopping_cart = microsite.get_value(
'ENABLE_SHOPPING_CART',
settings.FEATURES.get('ENABLE_SHOPPING_CART')
)
return (enable_paid_course_registration and enable_shopping_cart)
...@@ -33,7 +33,7 @@ from .exceptions import ( ...@@ -33,7 +33,7 @@ from .exceptions import (
) )
from .models import ( from .models import (
Order, OrderTypes, Order, OrderTypes,
PaidCourseRegistration, OrderItem, Coupon, CourseRegCodeItem, PaidCourseRegistration, OrderItem, Coupon,
CouponRedemption, CourseRegistrationCode, RegistrationCodeRedemption, CouponRedemption, CourseRegistrationCode, RegistrationCodeRedemption,
Donation, DonationConfiguration Donation, DonationConfiguration
) )
...@@ -44,6 +44,7 @@ from .processors import ( ...@@ -44,6 +44,7 @@ from .processors import (
import json import json
from xmodule_django.models import CourseKeyField from xmodule_django.models import CourseKeyField
from .decorators import enforce_shopping_cart_enabled
log = logging.getLogger("shoppingcart") log = logging.getLogger("shoppingcart")
AUDIT_LOG = logging.getLogger("audit") AUDIT_LOG = logging.getLogger("audit")
...@@ -94,6 +95,7 @@ def add_course_to_cart(request, course_id): ...@@ -94,6 +95,7 @@ def add_course_to_cart(request, course_id):
@login_required @login_required
@enforce_shopping_cart_enabled
def update_user_cart(request): def update_user_cart(request):
""" """
when user change the number-of-students from the UI then when user change the number-of-students from the UI then
...@@ -127,6 +129,7 @@ def update_user_cart(request): ...@@ -127,6 +129,7 @@ def update_user_cart(request):
@login_required @login_required
@enforce_shopping_cart_enabled
def show_cart(request): def show_cart(request):
""" """
This view shows cart items. This view shows cart items.
...@@ -158,6 +161,7 @@ def show_cart(request): ...@@ -158,6 +161,7 @@ def show_cart(request):
@login_required @login_required
@enforce_shopping_cart_enabled
def clear_cart(request): def clear_cart(request):
cart = Order.get_cart_for_user(request.user) cart = Order.get_cart_for_user(request.user)
cart.clear() cart.clear()
...@@ -175,6 +179,7 @@ def clear_cart(request): ...@@ -175,6 +179,7 @@ def clear_cart(request):
@login_required @login_required
@enforce_shopping_cart_enabled
def remove_item(request): def remove_item(request):
""" """
This will remove an item from the user cart and also delete the corresponding coupon codes redemption. This will remove an item from the user cart and also delete the corresponding coupon codes redemption.
...@@ -228,6 +233,7 @@ def remove_code_redemption(order_item_course_id, item_id, item, user): ...@@ -228,6 +233,7 @@ def remove_code_redemption(order_item_course_id, item_id, item, user):
@login_required @login_required
@enforce_shopping_cart_enabled
def reset_code_redemption(request): def reset_code_redemption(request):
""" """
This method reset the code redemption from user cart items. This method reset the code redemption from user cart items.
...@@ -240,6 +246,7 @@ def reset_code_redemption(request): ...@@ -240,6 +246,7 @@ def reset_code_redemption(request):
@login_required @login_required
@enforce_shopping_cart_enabled
def use_code(request): def use_code(request):
""" """
This method may generate the discount against valid coupon code This method may generate the discount against valid coupon code
...@@ -292,6 +299,7 @@ def get_reg_code_validity(registration_code, request, limiter): ...@@ -292,6 +299,7 @@ def get_reg_code_validity(registration_code, request, limiter):
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
@login_required @login_required
@enforce_shopping_cart_enabled
def register_code_redemption(request, registration_code): def register_code_redemption(request, registration_code):
""" """
This view allows the student to redeem the registration code This view allows the student to redeem the registration code
...@@ -383,6 +391,7 @@ def use_coupon_code(coupons, user): ...@@ -383,6 +391,7 @@ def use_coupon_code(coupons, user):
@login_required @login_required
@enforce_shopping_cart_enabled
def register_courses(request): def register_courses(request):
""" """
This method enroll the user for available course(s) This method enroll the user for available course(s)
...@@ -519,6 +528,7 @@ def postpay_callback(request): ...@@ -519,6 +528,7 @@ def postpay_callback(request):
@require_http_methods(["GET", "POST"]) @require_http_methods(["GET", "POST"])
@login_required @login_required
@enforce_shopping_cart_enabled
def billing_details(request): def billing_details(request):
""" """
This is the view for capturing additional billing details This is the view for capturing additional billing details
......
...@@ -1026,6 +1026,7 @@ main_vendor_js = base_vendor_js + [ ...@@ -1026,6 +1026,7 @@ main_vendor_js = base_vendor_js + [
dashboard_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/dashboard/**/*.js')) dashboard_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/dashboard/**/*.js'))
discussion_js = sorted(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/discussion/**/*.js')) discussion_js = sorted(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/discussion/**/*.js'))
rwd_header_footer_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/common_helpers/rwd_header_footer.js'))
staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.js')) staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.js'))
open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.js')) open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.js'))
notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js')) notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js'))
...@@ -1204,6 +1205,10 @@ PIPELINE_JS = { ...@@ -1204,6 +1205,10 @@ PIPELINE_JS = {
'source_filenames': dashboard_js, 'source_filenames': dashboard_js,
'output_filename': 'js/dashboard.js' 'output_filename': 'js/dashboard.js'
}, },
'rwd_header_footer': {
'source_filenames': rwd_header_footer_js,
'output_filename': 'js/rwd_header_footer.js'
},
'student_account': { 'student_account': {
'source_filenames': student_account_js, 'source_filenames': student_account_js,
'output_filename': 'js/student_account.js' 'output_filename': 'js/student_account.js'
......
...@@ -352,6 +352,8 @@ MICROSITE_CONFIGURATION = { ...@@ -352,6 +352,8 @@ MICROSITE_CONFIGURATION = {
"ALWAYS_REDIRECT_HOMEPAGE_TO_DASHBOARD_FOR_AUTHENTICATED_USER": False, "ALWAYS_REDIRECT_HOMEPAGE_TO_DASHBOARD_FOR_AUTHENTICATED_USER": False,
"COURSE_CATALOG_VISIBILITY_PERMISSION": "see_in_catalog", "COURSE_CATALOG_VISIBILITY_PERMISSION": "see_in_catalog",
"COURSE_ABOUT_VISIBILITY_PERMISSION": "see_about_page", "COURSE_ABOUT_VISIBILITY_PERMISSION": "see_about_page",
"ENABLE_SHOPPING_CART": True,
"ENABLE_PAID_COURSE_REGISTRATION": True,
}, },
"default": { "default": {
"university": "default_university", "university": "default_university",
......
@import "neat/neat-helpers"; // or "neat-helpers" when in Rails
/* Change the grid settings */
$max-width: 1200px;
/* Override the default global box-sizing */
$border-box-sizing: false;
/* Breakpoints */
$mobile: new-breakpoint(max-width 320px 4);
$tablet: new-breakpoint(min-width 321px max-width 768px, 8);
$desktop: new-breakpoint(min-width 769px 12);
$xl-desktop: new-breakpoint(min-width 980px 12);
...@@ -173,6 +173,7 @@ $m-blue-d1: #1790C7; ...@@ -173,6 +173,7 @@ $m-blue-d1: #1790C7;
$m-blue-d2: #1580B0; $m-blue-d2: #1580B0;
$m-blue-d3: #126F9A; $m-blue-d3: #126F9A;
$m-blue-d4: #0A4A67; $m-blue-d4: #0A4A67;
$m-blue-d5: #009EE7;
$m-blue-t0: rgba($m-blue,0.125); $m-blue-t0: rgba($m-blue,0.125);
$m-blue-t1: rgba($m-blue,0.25); $m-blue-t1: rgba($m-blue,0.25);
$m-blue-t2: rgba($m-blue,0.50); $m-blue-t2: rgba($m-blue,0.50);
...@@ -423,6 +424,7 @@ $header-sans-serif: 'Open Sans', Arial, Helvetica, sans-serif; ...@@ -423,6 +424,7 @@ $header-sans-serif: 'Open Sans', Arial, Helvetica, sans-serif;
$msg-bg: $action-primary-bg; $msg-bg: $action-primary-bg;
// New Shopping Cart // New Shopping Cart
$dark-gray1: #4a4a4a; $dark-gray1: #4a4a4a;
......
// Open edX: LMS footer // Open edX: LMS footer
// ==================== // ====================
@import '../base/grid-settings';
@import 'neat/neat'; // lib - Neat
.wrapper-footer { .wrapper-footer {
box-shadow: 0 -1px 5px 0 rgba(0,0,0, 0.1); box-shadow: 0 -1px 5px 0 rgba(0,0,0, 0.1);
border-top: 1px solid tint($m-gray,50%); border-top: 1px solid tint($m-gray,50%);
padding: 25px ($baseline/2) ($baseline*1.5) ($baseline/2); padding: 25px ($baseline/2) ($baseline*1.5) ($baseline/2);
background: $footer-bg; background: $footer-bg;
clear: both;
footer { footer {
@include clearfix(); @include clearfix();
...@@ -280,8 +284,6 @@ $edx-footer-bg-color: rgb(252,252,252); ...@@ -280,8 +284,6 @@ $edx-footer-bg-color: rgb(252,252,252);
@extend %t-weight4; @extend %t-weight4;
} }
} }
} }
.edx-footer-new { .edx-footer-new {
...@@ -352,6 +354,7 @@ $edx-footer-bg-color: rgb(252,252,252); ...@@ -352,6 +354,7 @@ $edx-footer-bg-color: rgb(252,252,252);
.footer-nav-title { .footer-nav-title {
@extend %edx-footer-title; @extend %edx-footer-title;
margin-top: $baseline;
} }
.footer-nav-links { .footer-nav-links {
...@@ -372,12 +375,14 @@ $edx-footer-bg-color: rgb(252,252,252); ...@@ -372,12 +375,14 @@ $edx-footer-bg-color: rgb(252,252,252);
.footer-follow-title { .footer-follow-title {
@extend %edx-footer-title; @extend %edx-footer-title;
margin-top: $baseline;
} }
.footer-follow-links { .footer-follow-links {
a { a {
@extend %edx-footer-link; @extend %edx-footer-link;
margin-top: 20px;
.icon, .copy { .icon, .copy {
display: inline-block; display: inline-block;
...@@ -397,4 +402,33 @@ $edx-footer-bg-color: rgb(252,252,252); ...@@ -397,4 +402,33 @@ $edx-footer-bg-color: rgb(252,252,252);
} }
} }
} }
&.rwd {
@include box-sizing(border-box);
@include outer-container;
&.wrapper-footer footer {
min-width: 0;
}
.footer-about,
.footer-nav,
.footer-follow {
@include span-columns(12);
}
@include media( $tablet ) {
}
@include media( $desktop ) {
.footer-about {
@include span-columns(6);
}
.footer-nav,
.footer-follow {
@include span-columns(3);
}
}
}
} }
@import '../base/grid-settings';
@import 'neat/neat'; // lib - Neat
header.global { header.global {
border-bottom: 1px solid $m-gray; border-bottom: 1px solid $m-gray;
box-shadow: 0 1px 5px 0 rgba(0,0,0, 0.1); box-shadow: 0 1px 5px 0 rgba(0,0,0, 0.1);
...@@ -317,7 +320,6 @@ header.global { ...@@ -317,7 +320,6 @@ header.global {
.view-courses .nav-global-02, .view-courses .nav-global-02,
.view-schools .nav-global-03, .view-schools .nav-global-03,
.view-register .nav-global-04 { .view-register .nav-global-04 {
a { a {
text-decoration: none; text-decoration: none;
color: $link-color !important; color: $link-color !important;
...@@ -331,8 +333,10 @@ header.global { ...@@ -331,8 +333,10 @@ header.global {
// CASE: marketing/course discovery // CASE: marketing/course discovery
header.global-new { header.global-new {
@extend %ui-depth1; @extend %ui-depth1;
/* Temp. fix until applied globally */
@include box-sizing(border-box);
position: relative; position: relative;
height: ($baseline*3.75);
width: 100%; width: 100%;
border-bottom: 4px solid $courseware-border-bottom-color; border-bottom: 4px solid $courseware-border-bottom-color;
box-shadow: 0 1px 5px 0 rgba(0,0,0, 0.1); box-shadow: 0 1px 5px 0 rgba(0,0,0, 0.1);
...@@ -340,15 +344,16 @@ header.global-new { ...@@ -340,15 +344,16 @@ header.global-new {
nav { nav {
@include clearfix(); @include clearfix();
@include box-sizing(border-box);
width: grid-width(12); width: grid-width(12);
height: ($baseline*2); height: 74px;
margin: 0 auto; margin: 0 auto;
padding: 18px ($baseline/2) 0; padding: 17px 0;
} }
h1.logo { h1.logo {
float: left; float: left;
margin: -2px 39px 0px 0px; margin: -2px 39px 0 10px;
position: relative; position: relative;
a { a {
...@@ -560,7 +565,7 @@ header.global-new { ...@@ -560,7 +565,7 @@ header.global-new {
} }
} }
.nav-global { %default-header-nav {
margin-top: ($baseline/4); margin-top: ($baseline/4);
list-style: none; list-style: none;
float: left; float: left;
...@@ -568,25 +573,21 @@ header.global-new { ...@@ -568,25 +573,21 @@ header.global-new {
li, li,
div { div {
display: inline-block; display: inline-block;
margin: 0 $baseline+1 0 0; margin: 0;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0 !important; letter-spacing: 0 !important;
&:last-child {
margin-right: 0;
}
a { a {
border-bottom: 4px solid $header-bg;
display:block; display:block;
padding: ($baseline/4); padding: 3px 10px;
font-size: 18px; font-size: 18px;
padding-bottom: ($baseline*1.25); line-height: 24px;
font-weight: 600; font-weight: 500;
font-family: $header-sans-serif; font-family: $header-sans-serif;
color: $courseware-navigation-color; color: $courseware-navigation-color;
&:hover, &:focus{ &:hover,
&:focus {
text-decoration: none; text-decoration: none;
color: $courseware-hover-color; color: $courseware-hover-color;
} }
...@@ -594,25 +595,26 @@ header.global-new { ...@@ -594,25 +595,26 @@ header.global-new {
} }
} }
.nav-global {
@extend %default-header-nav;
}
.nav-courseware { .nav-courseware {
@extend .nav-global; @extend %default-header-nav;
float: right; float: right;
div { div {
display: inline-block; display: inline-block;
margin: 0 21px 0 0;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0!important; letter-spacing: 0!important;
position: relative; position: relative;
vertical-align: middle;
&:last-child { &:last-child {
margin-right: 0; margin-right: 10px;
} }
a { a {
&.nav-courseware-button { &.nav-courseware-button {
padding: 5px 45px 5px 45px;
border: 3px solid $courseware-button-border-color; border: 3px solid $courseware-button-border-color;
border-radius: 5px; border-radius: 5px;
margin-top: -22px; margin-top: -22px;
...@@ -628,6 +630,182 @@ header.global-new { ...@@ -628,6 +630,182 @@ header.global-new {
} }
} }
} }
&.rwd {
nav {
max-width: 1180px;
width: 100%;
}
.mobile-menu-button {
@extend %t-action1;
display: inline;
float: left;
text-decoration: none;
color: $m-gray;
margin-top: 9px;
&:hover,
&:active,
&:focus {
text-decoration: none;
}
}
.logo {
position: absolute;
width: 54px;
left: calc( 50% - 90px );
top: 20px;
img {
width: 54px;
}
}
.nav-global,
.nav-courseware {
a {
@extend %t-action3;
&.nav-courseware-button {
width: 86px;
text-align: center;
margin-top: -3px;
}
}
}
.nav-global,
.nav-courseware-01 {
display: none;
}
.nav-global {
position: absolute;
top: 73px;
left: calc( 50% - 160px );
z-index: 1000;
width: 320px;
background: $m-blue-d3;
&.show {
display: inline;
}
a {
color: white;
padding: 10px;
font-weight: 300;
&:hover,
&:focus {
background: $m-blue-d5;
color: white;
border-bottom: none;
}
}
li {
display: block;
border-bottom: 1px solid $m-blue-d5;
}
}
.nav-courseware {
display: inline;
div:last-child {
margin-right: 0;
}
}
@include media( 320px ) {
nav {
width: 320px;
}
}
@include media( $desktop ) {
nav {
width: 100%;
}
.mobile-menu-button {
display: none;
}
.logo {
position: relative;
width: auto;
top: inherit;
left: inherit;
margin-left: 10px;
img {
width: auto;
}
}
.nav-global {
display: inline;
position: relative;
z-index: auto;
width: auto;
top: auto;
left: auto;
background: inherit;
a {
color: $courseware-navigation-color;
padding: 3px 10px;
font-weight: 500;
&:hover,
&:focus {
background: inherit;
color: $courseware-hover-color;
}
}
li {
display: inline-block;
border-bottom: none;
}
}
.nav-courseware {
div:last-child {
margin-right: 10px;
}
}
.nav-courseware-01 {
display: inline-block;
}
.desktop-hide {
display: none!important;
}
}
@include media( $xl-desktop ) {
nav {
padding: 17px 10px;
}
.nav-global,
.nav-courseware {
a {
font-size: 18px;
}
}
.logo {
margin-left: 0;
}
}
}
} }
.view-register header.global-new .cta-register { .view-register header.global-new .cta-register {
......
// lms - views - verification flow // lms - views - verification flow
// ==================== // ====================
@import '../base/grid-settings';
@import 'neat/neat'; // lib - Neat
// MISC: extends - button // MISC: extends - button
%btn-verify-primary { %btn-verify-primary {
...@@ -12,7 +14,6 @@ ...@@ -12,7 +14,6 @@
.is-expandable { .is-expandable {
.title-expand { .title-expand {
} }
.expandable-icon { .expandable-icon {
...@@ -438,7 +439,6 @@ ...@@ -438,7 +439,6 @@
} }
} }
} }
} }
} }
...@@ -989,7 +989,7 @@ ...@@ -989,7 +989,7 @@
@extend %t-weight4; @extend %t-weight4;
position: absolute; position: absolute;
top: -($baseline*1.25); top: -($baseline*1.25);
left: 45%; left: calc( 50% - 46px );
padding: ($baseline/2) ($baseline*1.5); padding: ($baseline/2) ($baseline*1.5);
background: white; background: white;
text-align: center; text-align: center;
...@@ -1129,22 +1129,35 @@ ...@@ -1129,22 +1129,35 @@
} }
.content-supplementary { .content-supplementary {
width: flex-grid(12,12); @include box-sizing(border-box);
@include outer-container;
@include span-columns(12);
.list-help { .list-help {
@include clearfix(); @include clearfix();
.help-item { .help-item {
width: flex-grid(4,12); @include fill-parent;
float: left; float: left;
margin-right: flex-gutter(); margin-right: flex-gutter();
margin-bottom: 25px;
&:last-child { &:last-child {
margin-right: 0; margin: 0;
} }
}
}
&.help-item-technical { @include media( 550px ) {
width: flex-grid(8,12); .list-help {
.help-item {
@include span-columns(4);
margin-bottom: 0;
&.help-item-technical {
@include span-columns(8);
}
} }
} }
} }
...@@ -1154,6 +1167,10 @@ ...@@ -1154,6 +1167,10 @@
// VIEW: select a track // VIEW: select a track
&.step-select-track { &.step-select-track {
.container {
min-width: 0;
max-width: 1200px;
}
.sts-track { .sts-track {
@extend %text-sr; @extend %text-sr;
...@@ -1161,11 +1178,10 @@ ...@@ -1161,11 +1178,10 @@
.form-register-choose { .form-register-choose {
@include clearfix(); @include clearfix();
width: flex-grid(12,12);
margin: ($baseline*2) 0; margin: ($baseline*2) 0;
.deco-divider { .deco-divider {
width: flex-grid(12,12); @include fill-parent;
float: left; float: left;
} }
} }
...@@ -1175,7 +1191,7 @@ ...@@ -1175,7 +1191,7 @@
} }
.register-choice { .register-choice {
width: flex-grid(12,12); @include fill-parent;
margin: 0 flex-gutter() $baseline 0; margin: 0 flex-gutter() $baseline 0;
border-top: ($baseline/4) solid $m-gray-d4; border-top: ($baseline/4) solid $m-gray-d4;
padding: $baseline ($baseline*1.5); padding: $baseline ($baseline*1.5);
...@@ -1190,28 +1206,35 @@ ...@@ -1190,28 +1206,35 @@
vertical-align: middle; vertical-align: middle;
} }
.wrapper-copy {
width: flex-grid(8,8);
}
.list-actions { .list-actions {
width: flex-grid(8,8); @include fill-parent;
text-align: right; text-align: right;
float: right;
margin: ($baseline/4) 0;
border-top: none;
clear: both;
} }
.title { .title {
@extend %t-title5; @extend %t-title5;
@extend %t-weight5; @extend %t-weight5;
margin-bottom: ($baseline/2); margin-bottom: ($baseline/2);
width: calc( 100% - 30px );
} }
.copy { .copy {
@extend %t-copy-base; @extend %t-copy-base;
} }
.action-select input { .action-select {
@extend %t-weight4; @include fill-parent;
padding: ($baseline/2) ($baseline*0.75);
input {
@extend %t-weight4;
padding: ($baseline/2) ($baseline*0.75);
width: 100%;
white-space: normal;
}
} }
} }
...@@ -1226,15 +1249,9 @@ ...@@ -1226,15 +1249,9 @@
display: block; display: block;
width: ($baseline*2.9); width: ($baseline*2.9);
height: ($baseline*4.2); height: ($baseline*4.2);
background: transparent url('../images/honor-ribbon.png') no-repeat 0 0;
}
.wrapper-copy {
width: flex-grid(8,8);
} }
.list-actions { .list-actions {
width: flex-grid(8,8);
margin: ($baseline) 0; margin: ($baseline) 0;
} }
...@@ -1249,19 +1266,12 @@ ...@@ -1249,19 +1266,12 @@
.deco-ribbon { .deco-ribbon {
position: absolute; position: absolute;
top: -($baseline*1.5); top: -10px;
right: $baseline; right: $baseline;
display: block; display: block;
width: ($baseline*3); width: 45px;
height: ($baseline*4); height: 45px;
background: transparent url('../images/vcert-ribbon-s.png') no-repeat 0 0; background: transparent url('../images/verified-ribbon.png') no-repeat 0 0;
}
.list-actions {
margin: ($baseline/4) 0;
border-top: none;
width: flex-grid(4,12);
float: right;
} }
.action-intro, .action-select { .action-intro, .action-select {
...@@ -1270,15 +1280,11 @@ ...@@ -1270,15 +1280,11 @@
} }
.action-intro { .action-intro {
@include fill-parent;
@extend %copy-detail; @extend %copy-detail;
width: flex-grid(3,8);
text-align: left; text-align: left;
} }
.action-select {
width: initial;
}
.action-select input { .action-select input {
@extend %btn-verify-primary; @extend %btn-verify-primary;
} }
...@@ -1301,7 +1307,7 @@ ...@@ -1301,7 +1307,7 @@
} }
.help-register { .help-register {
width: flex-grid(4,12); @include span-columns(4);
.title { .title {
@extend %hd-lv4; @extend %hd-lv4;
...@@ -1333,8 +1339,8 @@ ...@@ -1333,8 +1339,8 @@
.contribution-options { .contribution-options {
@include clearfix(); @include clearfix();
@include fill-parent;
margin: 0; margin: 0;
width: flex-grid(8,12);
&:after{ &:after{
clear: none; clear: none;
...@@ -1342,6 +1348,7 @@ ...@@ -1342,6 +1348,7 @@
} }
.field { .field {
@include fill-parent;
float: left; float: left;
margin: 0 ($baseline/2) ($baseline/2) 0; margin: 0 ($baseline/2) ($baseline/2) 0;
padding: ($baseline/2) ($baseline*0.75); padding: ($baseline/2) ($baseline*0.75);
...@@ -1380,6 +1387,65 @@ ...@@ -1380,6 +1387,65 @@
} }
} }
} }
@include media(min-width 550px max-width 768px) {
.contribution-options {
.field {
@include span-columns(6);
&:nth-of-type(even) {
margin-right: 0;
}
}
}
.register-choice {
.list-actions {
float: left;
width: auto;
}
.action-select {
width: initial;
input {
width: initial;
}
}
}
}
@include media( $desktop ) {
.contribution-options {
.field {
width: auto;
}
}
.register-choice {
.list-actions {
@include span-columns(4);
width: auto;
}
.action-select {
width: initial;
input {
width: initial;
}
}
}
}
@include media( $xl-desktop ) {
.register-choice {
.list-actions {
float: right;
clear: none;
}
}
}
} }
// VIEW: requirements // VIEW: requirements
......
...@@ -4,11 +4,6 @@ ...@@ -4,11 +4,6 @@
from courseware.courses import course_image_url, get_course_about_section from courseware.courses import course_image_url, get_course_about_section
from django.conf import settings from django.conf import settings
from edxmako.shortcuts import marketing_link from edxmako.shortcuts import marketing_link
if settings.FEATURES.get('ENABLE_SHOPPING_CART'):
cart_link = reverse('shoppingcart.views.show_cart')
else:
cart_link = ""
%> %>
<%namespace name='static' file='../static_content.html'/> <%namespace name='static' file='../static_content.html'/>
<%! from microsite_configuration import microsite %> <%! from microsite_configuration import microsite %>
...@@ -42,7 +37,7 @@ ...@@ -42,7 +37,7 @@
event.preventDefault(); event.preventDefault();
}); });
% if settings.FEATURES.get('ENABLE_SHOPPING_CART') and settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION'): % if is_shopping_cart_enabled:
add_course_complete_handler = function(jqXHR, textStatus) { add_course_complete_handler = function(jqXHR, textStatus) {
if (jqXHR.status == 200) { if (jqXHR.status == 200) {
location.href = "${cart_link}"; location.href = "${cart_link}";
...@@ -162,7 +157,7 @@ ...@@ -162,7 +157,7 @@
## so that they can register and become a real user that can enroll. ## so that they can register and become a real user that can enroll.
% elif not is_shib_course and not can_enroll: % elif not is_shib_course and not can_enroll:
<span class="register disabled">${_("Enrollment is Closed")}</span> <span class="register disabled">${_("Enrollment is Closed")}</span>
%elif settings.FEATURES.get('ENABLE_PAID_COURSE_REGISTRATION') and registration_price: %elif is_shopping_cart_enabled and registration_price:
<% <%
if user.is_authenticated(): if user.is_authenticated():
reg_href = "#" reg_href = "#"
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
<head dir="${dir_rtl}"> <head dir="${dir_rtl}">
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
% if responsive:
<meta name="viewport" content="width=device-width, initial-scale=1">
% endif
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%! from microsite_configuration import microsite %> <%! from microsite_configuration import microsite %>
<%! from microsite_configuration import page_title_breadcrumbs %> <%! from microsite_configuration import page_title_breadcrumbs %>
......
...@@ -53,11 +53,15 @@ site_status_msg = get_site_status_msg(course_id) ...@@ -53,11 +53,15 @@ site_status_msg = get_site_status_msg(course_id)
% if user.is_authenticated(): % if user.is_authenticated():
<div class="left nav-global authenticated"> <div class="left nav-global authenticated">
<%block name="navigation_global_links_authenticated"> <%block name="navigation_global_links_authenticated">
% if settings.FEATURES.get('COURSES_ARE_BROWSABLE'): <li class="nav-global-01">
<div class="nav-global-01"> <a href="${marketing_link('HOW_IT_WORKS')}">${_("How it Works")}</a>
<a href="${marketing_link('COURSES')}">${_('Find Courses')}</a> </li>
</div> <li class="nav-global-02">
% endif <a href="${marketing_link('COURSES')}">${_("Find Courses")}</a>
</li>
<li class="nav-global-03">
<a href="${marketing_link('SCHOOLS')}">${_("Schools & Partners")}</a>
</li>
</%block> </%block>
</div> </div>
......
<%! from django.utils.translation import ugettext as _ %> <%! from django.utils.translation import ugettext as _ %>
<%namespace name='static' file='../static_content.html'/>
<header class="page-header"> <header class="page-header">
<h2 class="title"> <h2 class="title">
<span class="wrapper-sts"> <span class="wrapper-sts">
...@@ -66,3 +68,7 @@ ...@@ -66,3 +68,7 @@
% endif % endif
</h2> </h2>
</header> </header>
<%block name="js_extra">
<%static:js group='rwd_header_footer'/>
</%block>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment