From 213dc70d1e984bf9326423bd538df41cfa0051bb Mon Sep 17 00:00:00 2001 From: Adam Palay Date: Fri, 29 May 2015 15:03:40 -0400 Subject: [PATCH 01/15] update to course import (TNL-2270) --- .../commands/export_convert_format.py | 5 +-- .../tests/test_export_convert_format.py | 7 ++-- .../views/tests/test_import_export.py | 35 ++++++++++++++++--- cms/envs/test.py | 1 + openedx/core/lib/extract_tar.py | 17 +++++---- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/export_convert_format.py b/cms/djangoapps/contentstore/management/commands/export_convert_format.py index 5b1b1d7cfd..f97ff305fc 100644 --- a/cms/djangoapps/contentstore/management/commands/export_convert_format.py +++ b/cms/djangoapps/contentstore/management/commands/export_convert_format.py @@ -7,6 +7,7 @@ Sample invocation: ./manage.py export_convert_format mycourse.tar.gz ~/newformat import os from path import path from django.core.management.base import BaseCommand, CommandError +from django.conf import settings from tempfile import mkdtemp import tarfile @@ -32,8 +33,8 @@ class Command(BaseCommand): output_path = args[1] # Create temp directories to extract the source and create the target archive. - temp_source_dir = mkdtemp() - temp_target_dir = mkdtemp() + temp_source_dir = mkdtemp(dir=settings.DATA_DIR) + temp_target_dir = mkdtemp(dir=settings.DATA_DIR) try: extract_source(source_archive, temp_source_dir) diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_export_convert_format.py b/cms/djangoapps/contentstore/management/commands/tests/test_export_convert_format.py index fd83d58f89..ddcdb725fb 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_export_convert_format.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_export_convert_format.py @@ -3,6 +3,7 @@ Test for export_convert_format. """ from unittest import TestCase from django.core.management import call_command, CommandError +from django.conf import settings from tempfile import mkdtemp import shutil from path import path @@ -18,7 +19,7 @@ class ConvertExportFormat(TestCase): """ Common setup. """ super(ConvertExportFormat, self).setUp() - self.temp_dir = mkdtemp() + self.temp_dir = mkdtemp(dir=settings.DATA_DIR) self.addCleanup(shutil.rmtree, self.temp_dir) self.data_dir = path(__file__).realpath().parent / 'data' self.version0 = self.data_dir / "Version0_drafts.tar.gz" @@ -52,8 +53,8 @@ class ConvertExportFormat(TestCase): """ Helper function for determining if 2 archives are equal. """ - temp_dir_1 = mkdtemp() - temp_dir_2 = mkdtemp() + temp_dir_1 = mkdtemp(dir=settings.DATA_DIR) + temp_dir_2 = mkdtemp(dir=settings.DATA_DIR) try: extract_source(file1, temp_dir_1) extract_source(file2, temp_dir_2) diff --git a/cms/djangoapps/contentstore/views/tests/test_import_export.py b/cms/djangoapps/contentstore/views/tests/test_import_export.py index 3375a30d09..f251d0a295 100644 --- a/cms/djangoapps/contentstore/views/tests/test_import_export.py +++ b/cms/djangoapps/contentstore/views/tests/test_import_export.py @@ -209,6 +209,19 @@ class ImportTestCase(CourseTestCase): return outside_tar + def _edx_platform_tar(self): + """ + Tarfile with file that extracts to edx-platform directory. + + Extracting this tarfile in directory will also put its contents + directly in (rather than ). + """ + outside_tar = self.unsafe_common_dir / "unsafe_file.tar.gz" + with tarfile.open(outside_tar, "w:gz") as tar: + tar.addfile(tarfile.TarInfo(os.path.join(os.path.abspath("."), "a_file"))) + + return outside_tar + def test_unsafe_tar(self): """ Check that safety measure work. @@ -233,6 +246,12 @@ class ImportTestCase(CourseTestCase): try_tar(self._symlink_tar()) try_tar(self._outside_tar()) try_tar(self._outside_tar2()) + try_tar(self._edx_platform_tar()) + + # test trying to open a tar outside of the normal data directory + with self.settings(DATA_DIR='/not/the/data/dir'): + try_tar(self._edx_platform_tar()) + # Check that `import_status` returns the appropriate stage (i.e., # either 3, indicating all previous steps are completed, or 0, # indicating no upload in progress) @@ -294,13 +313,19 @@ class ImportTestCase(CourseTestCase): self.assertIn(test_block3.url_name, children) self.assertIn(test_block4.url_name, children) - extract_dir = path(tempfile.mkdtemp()) + extract_dir = path(tempfile.mkdtemp(dir=settings.DATA_DIR)) + # the extract_dir needs to be passed as a relative dir to + # import_library_from_xml + extract_dir_relative = path.relpath(extract_dir, settings.DATA_DIR) + try: - tar = tarfile.open(path(TEST_DATA_DIR) / 'imports' / 'library.HhJfPD.tar.gz') - safetar_extractall(tar, extract_dir) + with tarfile.open(path(TEST_DATA_DIR) / 'imports' / 'library.HhJfPD.tar.gz') as tar: + safetar_extractall(tar, extract_dir) library_items = import_library_from_xml( - self.store, self.user.id, - settings.GITHUB_REPO_ROOT, [extract_dir / 'library'], + self.store, + self.user.id, + settings.GITHUB_REPO_ROOT, + [extract_dir_relative / 'library'], load_error_modules=False, static_content_store=contentstore(), target_id=lib_key diff --git a/cms/envs/test.py b/cms/envs/test.py index ba6d9e7df1..289c3c67d3 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -65,6 +65,7 @@ TEST_ROOT = path('test_root') STATIC_ROOT = TEST_ROOT / "staticfiles" GITHUB_REPO_ROOT = TEST_ROOT / "data" +DATA_DIR = TEST_ROOT / "data" COMMON_TEST_DATA_ROOT = COMMON_ROOT / "test" / "data" # For testing "push to lms" diff --git a/openedx/core/lib/extract_tar.py b/openedx/core/lib/extract_tar.py index ea464880ea..1fd6644977 100644 --- a/openedx/core/lib/extract_tar.py +++ b/openedx/core/lib/extract_tar.py @@ -7,6 +7,7 @@ http://stackoverflow.com/questions/10060069/safely-extract-zip-or-tar-using-pyth """ from os.path import abspath, realpath, dirname, join as joinpath from django.core.exceptions import SuspiciousOperation +from django.conf import settings import logging log = logging.getLogger(__name__) @@ -28,19 +29,23 @@ def _is_bad_path(path, base): def _is_bad_link(info, base): """ - Does the file sym- ord hard-link to files outside `base`? + Does the file sym- or hard-link to files outside `base`? """ # Links are interpreted relative to the directory containing the link tip = resolved(joinpath(base, dirname(info.name))) return _is_bad_path(info.linkname, base=tip) -def safemembers(members): +def safemembers(members, base): """ Check that all elements of a tar file are safe. """ - base = resolved(".") + base = resolved(base) + + # check that we're not trying to import outside of the data_dir + if not base.startswith(resolved(settings.DATA_DIR)): + raise SuspiciousOperation("Attempted to import course outside of data dir") for finfo in members: if _is_bad_path(finfo.name, base): @@ -61,8 +66,8 @@ def safemembers(members): return members -def safetar_extractall(tarf, *args, **kwargs): +def safetar_extractall(tar_file, path=".", members=None): """ - Safe version of `tarf.extractall()`. + Safe version of `tar_file.extractall()`. """ - return tarf.extractall(members=safemembers(tarf), *args, **kwargs) + return tar_file.extractall(path, safemembers(tar_file, path)) From 5088ae3091df65099d485ed21096925af6d6be75 Mon Sep 17 00:00:00 2001 From: Adam Palay Date: Wed, 8 Jul 2015 11:48:57 -0400 Subject: [PATCH 02/15] when removing field from _field_data_cache when rebinding a module to a new user, also remove it from _dirty_fields (TNL-2640) --- common/lib/xmodule/xmodule/x_module.py | 6 +++++ .../courseware/tests/test_module_render.py | 25 +++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 0280655965..4943b2610e 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -587,6 +587,12 @@ class XModuleMixin(XModuleFields, XBlock): if field.scope.user == UserScope.ONE: field._del_cached_value(self) # pylint: disable=protected-access + # not the most elegant way of doing this, but if we're removing + # a field from the module's field_data_cache, we should also + # remove it from its _dirty_fields + # pylint: disable=protected-access + if field in self._dirty_fields: + del self._dirty_fields[field] # Set the new xmodule_runtime and field_data (which are user-specific) self.xmodule_runtime = xmodule_runtime diff --git a/lms/djangoapps/courseware/tests/test_module_render.py b/lms/djangoapps/courseware/tests/test_module_render.py index 1f22edee36..f417b37c6e 100644 --- a/lms/djangoapps/courseware/tests/test_module_render.py +++ b/lms/djangoapps/courseware/tests/test_module_render.py @@ -1360,23 +1360,44 @@ class TestRebindModule(TestSubmittingProblems): super(TestRebindModule, self).setUp() self.homework = self.add_graded_section_to_course('homework') self.lti = ItemFactory.create(category='lti', parent=self.homework) + self.problem = ItemFactory.create(category='problem', parent=self.homework) self.user = UserFactory.create() self.anon_user = AnonymousUser() - def get_module_for_user(self, user): + def get_module_for_user(self, user, item=None): """Helper function to get useful module at self.location in self.course_id for user""" mock_request = MagicMock() mock_request.user = user field_data_cache = FieldDataCache.cache_for_descriptor_descendents( self.course.id, user, self.course, depth=2) + if item is None: + item = self.lti + return render.get_module( # pylint: disable=protected-access user, mock_request, - self.lti.location, + item.location, field_data_cache, )._xmodule + def test_rebind_module_to_new_users(self): + module = self.get_module_for_user(self.user, self.problem) + + # Bind the module to another student, which will remove "correct_map" + # from the module's _field_data_cache and _dirty_fields. + user2 = UserFactory.create() + module.descriptor.bind_for_student(module.system, user2.id) + + # XBlock's save method assumes that if a field is in _dirty_fields, + # then it's also in _field_data_cache. If this assumption + # doesn't hold, then we get an error trying to bind this module + # to a third student, since we've removed "correct_map" from + # _field_data cache, but not _dirty_fields, when we bound + # this module to the second student. (TNL-2640) + user3 = UserFactory.create() + module.descriptor.bind_for_student(module.system, user3.id) + def test_rebind_noauth_module_to_user_not_anonymous(self): """ Tests that an exception is thrown when rebind_noauth_module_to_user is run from a From 2c6264077d8b9996f86091f61f0cac2a8697503b Mon Sep 17 00:00:00 2001 From: Adam Palay Date: Mon, 13 Jul 2015 15:09:53 -0400 Subject: [PATCH 03/15] address quality violation --- openedx/core/lib/extract_tar.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openedx/core/lib/extract_tar.py b/openedx/core/lib/extract_tar.py index 1fd6644977..58079ad065 100644 --- a/openedx/core/lib/extract_tar.py +++ b/openedx/core/lib/extract_tar.py @@ -66,7 +66,7 @@ def safemembers(members, base): return members -def safetar_extractall(tar_file, path=".", members=None): +def safetar_extractall(tar_file, path=".", members=None): # pylint: disable=unused-argument """ Safe version of `tar_file.extractall()`. """ From 51deec380ea8ce781dc9139c55c1204a66467443 Mon Sep 17 00:00:00 2001 From: AlasdairSwan Date: Thu, 9 Jul 2015 13:12:32 -0400 Subject: [PATCH 04/15] ECOM-1661 removed nav links for logged out states Add context for navigation states added find course to dashboard sidebar and included check for context that Will adds in PR removed nav_course_search context due to design change so replaced with nav_hidden Removed rwd_header.js and all references as no longer being used. Wrapped Find Courses in dashboard sidebar in if statement --- .../course_modes/tests/test_views.py | 16 ++++ common/djangoapps/course_modes/views.py | 3 +- common/djangoapps/student/tests/tests.py | 13 +++ common/djangoapps/student/views.py | 1 + common/static/js/utils/rwd_header.js | 94 ------------------- common/test/acceptance/pages/lms/dashboard.py | 14 --- common/test/acceptance/tests/lms/test_lms.py | 6 -- lms/djangoapps/commerce/tests/test_views.py | 11 +++ lms/djangoapps/commerce/views.py | 1 + .../verify_student/tests/test_views.py | 11 +++ lms/djangoapps/verify_student/views.py | 1 + lms/envs/common.py | 6 -- lms/static/sass/elements/_controls.scss | 13 +++ lms/static/sass/multicourse/_dashboard.scss | 29 ++++-- lms/static/sass/shared/_header.scss | 12 +-- lms/templates/commerce/checkout_receipt.html | 1 - lms/templates/dashboard.html | 15 +-- lms/templates/navigation-edx.html | 46 ++++----- .../verify_student/incourse_reverify.html | 1 - .../verify_student/pay_and_verify.html | 1 - lms/templates/verify_student/reverify.html | 1 - 21 files changed, 119 insertions(+), 177 deletions(-) delete mode 100644 common/static/js/utils/rwd_header.js diff --git a/common/djangoapps/course_modes/tests/test_views.py b/common/djangoapps/course_modes/tests/test_views.py index 3883a5acd8..11d2afc394 100644 --- a/common/djangoapps/course_modes/tests/test_views.py +++ b/common/djangoapps/course_modes/tests/test_views.py @@ -325,6 +325,22 @@ class CourseModeViewTest(UrlResetMixin, ModuleStoreTestCase): self.assertEquals(course_modes, expected_modes) + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @patch.dict(settings.FEATURES, {"IS_EDX_DOMAIN": True}) + def test_hide_nav(self): + # Create the course modes + for mode in ["honor", "verified"]: + CourseModeFactory(mode_slug=mode, course_id=self.course.id) + + # Load the track selection page + url = reverse('course_modes_choose', args=[unicode(self.course.id)]) + response = self.client.get(url) + + # Verify that the header navigation links are hidden for the edx.org version + self.assertNotContains(response, "How it Works") + self.assertNotContains(response, "Find courses") + self.assertNotContains(response, "Schools & Partners") + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') class TrackSelectionEmbargoTest(UrlResetMixin, ModuleStoreTestCase): diff --git a/common/djangoapps/course_modes/views.py b/common/djangoapps/course_modes/views.py index 290aef9249..0dc790b766 100644 --- a/common/djangoapps/course_modes/views.py +++ b/common/djangoapps/course_modes/views.py @@ -119,7 +119,8 @@ class ChooseModeView(View): "course_num": course.display_number_with_default, "chosen_price": chosen_price, "error": error, - "responsive": True + "responsive": True, + "nav_hidden": True, } if "verified" in modes: context["suggested_prices"] = [ diff --git a/common/djangoapps/student/tests/tests.py b/common/djangoapps/student/tests/tests.py index e1575da5e9..e2e66fb0c9 100644 --- a/common/djangoapps/student/tests/tests.py +++ b/common/djangoapps/student/tests/tests.py @@ -527,6 +527,19 @@ class DashboardTest(ModuleStoreTestCase): response_3 = self.client.get(reverse('dashboard')) self.assertEquals(response_3.status_code, 200) + @unittest.skipUnless(settings.ROOT_URLCONF == 'lms.urls', 'Test only valid in lms') + @patch.dict(settings.FEATURES, {"IS_EDX_DOMAIN": True}) + def test_dashboard_header_nav_has_find_courses(self): + self.client.login(username="jack", password="test") + response = self.client.get(reverse("dashboard")) + + # "Find courses" is shown in the side panel + self.assertContains(response, "Find courses") + + # But other links are hidden in the navigation + self.assertNotContains(response, "How it Works") + self.assertNotContains(response, "Schools & Partners") + class UserSettingsEventTestMixin(EventTestMixin): """ diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index e98ce9473b..53551510fa 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -698,6 +698,7 @@ def dashboard(request): 'order_history_list': order_history_list, 'courses_requirements_not_met': courses_requirements_not_met, 'ccx_membership_triplets': ccx_membership_triplets, + 'nav_hidden': True, } return render_to_response('dashboard.html', context) diff --git a/common/static/js/utils/rwd_header.js b/common/static/js/utils/rwd_header.js deleted file mode 100644 index d2137fd9bc..0000000000 --- a/common/static/js/utils/rwd_header.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * Adds rwd classes and click handlers. - */ - -(function($) { - 'use strict'; - - var rwd = (function() { - - var _fn = { - header: 'header.global-new', - - resultsUrl: 'course-search', - - init: function() { - _fn.$header = $( _fn.header ); - _fn.$footer = $( _fn.footer ); - _fn.$navContainer = _fn.$header.find('.nav-container'); - _fn.$globalNav = _fn.$header.find('.nav-global'); - - _fn.add.elements(); - _fn.add.classes(); - _fn.eventHandlers.init(); - }, - - add: { - classes: function() { - // Add any RWD-specific classes - _fn.$header.addClass('rwd'); - }, - - elements: function() { - _fn.add.burger(); - _fn.add.registerLink(); - }, - - burger: function() { - _fn.$navContainer.prepend([ - '', - '', - '' - ].join('')); - }, - - registerLink: function() { - var $register = _fn.$header.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.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.$header.on( 'click', '.mobile-menu-button', _fn.toggleMenu ); - } - }, - - toggleMenu: function( event ) { - event.preventDefault(); - - _fn.$globalNav.toggleClass('show'); - } - }; - - return { - init: _fn.init - }; - })(); - - rwd.init(); -})(jQuery); diff --git a/common/test/acceptance/pages/lms/dashboard.py b/common/test/acceptance/pages/lms/dashboard.py index 8b83a6bf75..d52f3fe148 100644 --- a/common/test/acceptance/pages/lms/dashboard.py +++ b/common/test/acceptance/pages/lms/dashboard.py @@ -49,20 +49,6 @@ class DashboardPage(PageObject): return self.q(css='h3.course-title > a').map(_get_course_name).results - @property - def sidebar_menu_title(self): - """ - Return the title value for sidebar menu. - """ - return self.q(css='.user-info span.title').text[0] - - @property - def sidebar_menu_description(self): - """ - Return the description text for sidebar menu. - """ - return self.q(css='.user-info span.copy').text[0] - def get_enrollment_mode(self, course_name): """Get the enrollment mode for a given course on the dashboard. diff --git a/common/test/acceptance/tests/lms/test_lms.py b/common/test/acceptance/tests/lms/test_lms.py index 00eb2b33cc..4ab4c5ce79 100644 --- a/common/test/acceptance/tests/lms/test_lms.py +++ b/common/test/acceptance/tests/lms/test_lms.py @@ -268,12 +268,6 @@ class RegisterFromCombinedPageTest(UniqueCourseTest): course_names = self.dashboard_page.wait_for_page().available_courses self.assertIn(self.course_info["display_name"], course_names) - self.assertEqual("want to change your account settings?", self.dashboard_page.sidebar_menu_title.lower()) - self.assertEqual( - "click the arrow next to your username above.", - self.dashboard_page.sidebar_menu_description.lower() - ) - def test_register_failure(self): # Navigate to the registration page self.register_page.visit() diff --git a/lms/djangoapps/commerce/tests/test_views.py b/lms/djangoapps/commerce/tests/test_views.py index 0d91ed44bb..9a1754d50a 100644 --- a/lms/djangoapps/commerce/tests/test_views.py +++ b/lms/djangoapps/commerce/tests/test_views.py @@ -406,3 +406,14 @@ class ReceiptViewTests(UserMixin, TestCase): system_message = "A system error occurred while processing your payment" self.assertRegexpMatches(response.content, user_message if is_user_message_expected else system_message) self.assertNotRegexpMatches(response.content, user_message if not is_user_message_expected else system_message) + + @mock.patch.dict(settings.FEATURES, {"IS_EDX_DOMAIN": True}) + def test_hide_nav_header(self): + self._login() + post_data = {'decision': 'ACCEPT', 'reason_code': '200', 'signed_field_names': 'dummy'} + response = self.post_to_receipt_page(post_data) + + # Verify that the header navigation links are hidden for the edx.org version + self.assertNotContains(response, "How it Works") + self.assertNotContains(response, "Find courses") + self.assertNotContains(response, "Schools & Partners") diff --git a/lms/djangoapps/commerce/views.py b/lms/djangoapps/commerce/views.py index 2c10f33e9c..8b31b6048c 100644 --- a/lms/djangoapps/commerce/views.py +++ b/lms/djangoapps/commerce/views.py @@ -203,6 +203,7 @@ def checkout_receipt(request): 'error_text': error_text, 'for_help_text': for_help_text, 'payment_support_email': payment_support_email, + 'nav_hidden': True, } return render_to_response('commerce/checkout_receipt.html', context) diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py index d188a85e58..068572645b 100644 --- a/lms/djangoapps/verify_student/tests/test_views.py +++ b/lms/djangoapps/verify_student/tests/test_views.py @@ -239,6 +239,17 @@ class TestPayAndVerifyView(UrlResetMixin, ModuleStoreTestCase): ) self._assert_redirects_to_dashboard(response) + @patch.dict(settings.FEATURES, {"IS_EDX_DOMAIN": True}) + def test_pay_and_verify_hides_header_nav(self): + course = self._create_course("verified") + self._enroll(course.id, "verified") + response = self._get_page('verify_student_start_flow', course.id) + + # Verify that the header navigation links are hidden for the edx.org version + self.assertNotContains(response, "How it Works") + self.assertNotContains(response, "Find courses") + self.assertNotContains(response, "Schools & Partners") + def test_verify_now(self): # We've already paid, and now we're trying to verify course = self._create_course("verified") diff --git a/lms/djangoapps/verify_student/views.py b/lms/djangoapps/verify_student/views.py index 288a86710b..74d993ebb2 100644 --- a/lms/djangoapps/verify_student/views.py +++ b/lms/djangoapps/verify_student/views.py @@ -376,6 +376,7 @@ class PayAndVerifyView(View): 'already_verified': already_verified, 'verification_good_until': verification_good_until, 'capture_sound': staticfiles_storage.url("audio/camera_capture.wav"), + 'nav_hidden': True, } return render_to_response("verify_student/pay_and_verify.html", context) diff --git a/lms/envs/common.py b/lms/envs/common.py index 6a13d69c73..bf985c7894 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1254,7 +1254,6 @@ dashboard_js = ( ) dashboard_search_js = ['js/search/dashboard/main.js'] discussion_js = sorted(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/discussion/**/*.js')) -rwd_header_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/utils/rwd_header.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')) notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js')) @@ -1267,7 +1266,6 @@ instructor_dash_js = ( # These are not courseware, so they do not need many of the courseware-specific # JavaScript modules. student_account_js = [ - 'js/utils/rwd_header.js', 'js/utils/edx.utils.validate.js', 'js/form.ext.js', 'js/my_courses_dropdown.js', @@ -1556,10 +1554,6 @@ PIPELINE_JS = { 'source_filenames': dashboard_search_js, 'output_filename': 'js/dashboard-search.js', }, - 'rwd_header': { - 'source_filenames': rwd_header_js, - 'output_filename': 'js/rwd_header.js' - }, 'student_account': { 'source_filenames': student_account_js, 'output_filename': 'js/student_account.js' diff --git a/lms/static/sass/elements/_controls.scss b/lms/static/sass/elements/_controls.scss index ceede5d14f..a38dc4a739 100644 --- a/lms/static/sass/elements/_controls.scss +++ b/lms/static/sass/elements/_controls.scss @@ -352,6 +352,19 @@ } } +%btn-pl-elevated-alt { + @extend %btn-pl-default-base; + box-shadow: 0 3px 0 0 $gray-l4; + border: 1px solid $gray-l4; + + &:hover { + box-shadow: 0 3px 0 0 $action-primary-bg; + border: 1px solid $action-primary-bg; + background-color: lighten($action-primary-bg,20%); + color: $white; + } +} + // ==================== // application: canned actions diff --git a/lms/static/sass/multicourse/_dashboard.scss b/lms/static/sass/multicourse/_dashboard.scss index 13875c1519..fbb203dcf1 100644 --- a/lms/static/sass/multicourse/_dashboard.scss +++ b/lms/static/sass/multicourse/_dashboard.scss @@ -15,14 +15,31 @@ @include clearfix(); padding: ($baseline*2) 0 0 0; + .wrapper-find-courses { + @include float(right); + @include margin-left(flex-gutter()); + width: flex-grid(3); + margin-top: ($baseline*2); + border-top: 3px solid $blue; + padding: $baseline 0; + + .copy { + @extend %t-copy-sub1; + } + + .btn-find-courses { + @extend %btn-pl-elevated-alt; + } + } + .profile-sidebar { background: transparent; @include float(right); - margin-top: ($baseline*2); + @include margin-left(flex-gutter()); width: flex-grid(3); - box-shadow: 0 0 1px $shadow-l1; - border: 1px solid $border-color-2; - border-radius: 3px; + margin-top: ($baseline*2); + border-top: 3px solid $blue; + padding: $baseline 0; .user-info { @include clearfix(); @@ -31,7 +48,7 @@ @include box-sizing(border-box); @include clearfix(); margin: 0; - padding: $baseline; + padding: 0; width: flex-grid(12); li { @@ -59,7 +76,7 @@ } span.title { - @extend %t-copy-sub1; + @extend %t-title6; @extend %t-strong; a { diff --git a/lms/static/sass/shared/_header.scss b/lms/static/sass/shared/_header.scss index 06a811cb7e..ea5ca54d37 100644 --- a/lms/static/sass/shared/_header.scss +++ b/lms/static/sass/shared/_header.scss @@ -627,8 +627,8 @@ header.global-new { a { display:block; padding: 3px 10px; - font-size: 18px; - line-height: 24px; + font-size: 14px; + line-height: 1.5; font-weight: 600; font-family: $header-sans-serif; color: $courseware-navigation-color; @@ -715,7 +715,6 @@ header.global-new { font-size: 14px; &.nav-courseware-button { - width: 86px; text-align: center; margin-top: -3px; } @@ -833,13 +832,6 @@ header.global-new { .wrapper-header { padding: 17px 0; } - - .nav-global, - .nav-courseware { - a { - font-size: 18px; - } - } } } } diff --git a/lms/templates/commerce/checkout_receipt.html b/lms/templates/commerce/checkout_receipt.html index fc5bdf39cc..56627ada05 100644 --- a/lms/templates/commerce/checkout_receipt.html +++ b/lms/templates/commerce/checkout_receipt.html @@ -15,7 +15,6 @@ from django.utils.translation import ugettext as _ <%block name="js_extra"> -<%static:js group='rwd_header'/> diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index 8d3fb0ad43..5d1ffc4c88 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -147,16 +147,19 @@ from django.core.urlresolvers import reverse
    % endif -
    + % if settings.FEATURES.get('IS_EDX_DOMAIN'): +
    +

    Check out our recently launched courses and what's new in your favorite subjects

    +

    ${_("Find New Courses")}

    +
    + % endif + +
    -

    ${_("Username")}:

    +