diff --git a/.gitignore b/.gitignore index 05e76c4caa..69bc47afdd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ .AppleDouble database.sqlite requirements/private.txt +lms/envs/private.py +cms/envs/private.py courseware/static/js/mathjax/* flushdb.sh build @@ -27,6 +29,7 @@ conf/locale/en/LC_MESSAGES/*.po !messages.po lms/static/sass/*.css lms/static/sass/application.scss +lms/static/sass/course.scss cms/static/sass/*.css lms/lib/comment_client/python nosetests.xml diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py index aebfb91126..771871e9bc 100644 --- a/cms/djangoapps/contentstore/tests/test_contentstore.py +++ b/cms/djangoapps/contentstore/tests/test_contentstore.py @@ -486,6 +486,9 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase): # check for custom_tags self.verify_content_existence(module_store, root_dir, location, 'custom_tags', 'custom_tag_template') + # check for about content + self.verify_content_existence(module_store, root_dir, location, 'about', 'about', '.html') + # check for graiding_policy.json filesystem = OSFS(root_dir / 'test_export/policies/6.002_Spring_2012') self.assertTrue(filesystem.exists('grading_policy.json')) diff --git a/cms/envs/aws.py b/cms/envs/aws.py index 63c7d533cd..af5f39631d 100644 --- a/cms/envs/aws.py +++ b/cms/envs/aws.py @@ -95,7 +95,8 @@ SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN') # this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can # happen with some browsers (e.g. Firefox) if ENV_TOKENS.get('SESSION_COOKIE_NAME', None): - SESSION_COOKIE_NAME = ENV_TOKENS.get('SESSION_COOKIE_NAME') + # NOTE, there's a bug in Django (http://bugs.python.org/issue18012) which necessitates this being a str() + SESSION_COOKIE_NAME = str(ENV_TOKENS.get('SESSION_COOKIE_NAME')) #Email overrides DEFAULT_FROM_EMAIL = ENV_TOKENS.get('DEFAULT_FROM_EMAIL', DEFAULT_FROM_EMAIL) diff --git a/cms/envs/dev.py b/cms/envs/dev.py index e63968d338..eea236f0e2 100644 --- a/cms/envs/dev.py +++ b/cms/envs/dev.py @@ -165,3 +165,11 @@ MITX_FEATURES['ENABLE_SERVICE_STATUS'] = True # segment-io key for dev SEGMENT_IO_KEY = 'mty8edrrsg' + + +##################################################################### +# Lastly, see if the developer has any local overrides. +try: + from .private import * +except ImportError: + pass diff --git a/common/djangoapps/mitxmako/shortcuts.py b/common/djangoapps/mitxmako/shortcuts.py index 0766564027..7f7c3f9ebe 100644 --- a/common/djangoapps/mitxmako/shortcuts.py +++ b/common/djangoapps/mitxmako/shortcuts.py @@ -41,7 +41,9 @@ def marketing_link(name): return settings.MKTG_URLS.get('ROOT') + settings.MKTG_URLS.get(name) # only link to the old pages when the marketing site isn't on elif not settings.MITX_FEATURES.get('ENABLE_MKTG_SITE') and name in link_map: - return reverse(link_map[name]) + # don't try to reverse disabled marketing links + if link_map[name] is not None: + return reverse(link_map[name]) else: log.warning("Cannot find corresponding link for name: {name}".format(name=name)) return '#' diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 661b1da26b..87e9f8c804 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -1198,6 +1198,10 @@ def accept_name_change(request): def _get_news(top=None): "Return the n top news items on settings.RSS_URL" + # Don't return anything if we're in a themed site + if settings.MITX_FEATURES["USE_CUSTOM_THEME"]: + return None + feed_data = cache.get("students_index_rss_feed_data") if feed_data is None: if hasattr(settings, 'RSS_URL'): diff --git a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py index 50bdf3a252..9fceb51c51 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml_exporter.py +++ b/common/lib/xmodule/xmodule/modulestore/xml_exporter.py @@ -28,6 +28,9 @@ def export_to_xml(modulestore, contentstore, course_location, root_dir, course_d # export the course updates export_extra_content(export_fs, modulestore, course_location, 'course_info', 'info', '.html') + # export the 'about' data (e.g. overview, etc.) + export_extra_content(export_fs, modulestore, course_location, 'about', 'about', '.html') + # export the grading policy policies_dir = export_fs.makeopendir('policies') course_run_policy_dir = policies_dir.makeopendir(course.location.name) diff --git a/doc/testing.md b/doc/testing.md index 4d286b1bcc..a37cade47e 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -202,9 +202,10 @@ To view test coverage: 2. Generate reports: - rake coverage:html + rake coverage -3. HTML reports are located in the `reports` folder. +3. Reports are located in the `reports` folder. The command +generates HTML and XML (Cobertura format) reports. ## Testing using queue servers diff --git a/jenkins/test.sh b/jenkins/test.sh index 35be3a0121..51566f6fb5 100755 --- a/jenkins/test.sh +++ b/jenkins/test.sh @@ -84,7 +84,8 @@ rake phantomjs_jasmine_cms || TESTS_FAILED=1 rake phantomjs_jasmine_common/lib/xmodule || TESTS_FAILED=1 rake phantomjs_jasmine_common/static/coffee || TESTS_FAILED=1 -rake coverage:xml coverage:html +# Generate coverage reports +rake coverage [ $TESTS_FAILED == '0' ] rake autodeploy_properties diff --git a/lms/envs/aws.py b/lms/envs/aws.py index 588d9034db..788e08a110 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -99,6 +99,8 @@ CELERY_QUEUES = { with open(ENV_ROOT / CONFIG_PREFIX + "env.json") as env_file: ENV_TOKENS = json.load(env_file) +PLATFORM_NAME = ENV_TOKENS.get('PLATFORM_NAME', PLATFORM_NAME) + SITE_NAME = ENV_TOKENS['SITE_NAME'] SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN') @@ -106,7 +108,8 @@ SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN') # this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can # happen with some browsers (e.g. Firefox) if ENV_TOKENS.get('SESSION_COOKIE_NAME', None): - SESSION_COOKIE_NAME = ENV_TOKENS.get('SESSION_COOKIE_NAME') + # NOTE, there's a bug in Django (http://bugs.python.org/issue18012) which necessitates this being a str() + SESSION_COOKIE_NAME = str(ENV_TOKENS.get('SESSION_COOKIE_NAME')) BOOK_URL = ENV_TOKENS['BOOK_URL'] MEDIA_URL = ENV_TOKENS['MEDIA_URL'] @@ -119,11 +122,18 @@ DEFAULT_FROM_EMAIL = ENV_TOKENS.get('DEFAULT_FROM_EMAIL', DEFAULT_FROM_EMAIL) DEFAULT_FEEDBACK_EMAIL = ENV_TOKENS.get('DEFAULT_FEEDBACK_EMAIL', DEFAULT_FEEDBACK_EMAIL) ADMINS = ENV_TOKENS.get('ADMINS', ADMINS) SERVER_EMAIL = ENV_TOKENS.get('SERVER_EMAIL', SERVER_EMAIL) +TECH_SUPPORT_EMAIL = ENV_TOKENS.get('TECH_SUPPORT_EMAIL', TECH_SUPPORT_EMAIL) +CONTACT_EMAIL = ENV_TOKENS.get('CONTACT_EMAIL', CONTACT_EMAIL) +BUGS_EMAIL = ENV_TOKENS.get('BUGS_EMAIL', BUGS_EMAIL) #Theme overrides THEME_NAME = ENV_TOKENS.get('THEME_NAME', None) if not THEME_NAME is None: enable_theme(THEME_NAME) + FAVICON_PATH = 'themes/%s/images/favicon.ico' % THEME_NAME + +# Marketing link overrides +MKTG_URL_LINK_MAP.update(ENV_TOKENS.get('MKTG_URL_LINK_MAP', {})) #Timezone overrides TIME_ZONE = ENV_TOKENS.get('TIME_ZONE', TIME_ZONE) diff --git a/lms/envs/common.py b/lms/envs/common.py index 4102879723..2029715c60 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -31,6 +31,9 @@ from path import path from .discussionsettings import * ################################### FEATURES ################################### +# The display name of the platform to be used in templates/emails/etc. +PLATFORM_NAME = "edX" + COURSEWARE_ENABLED = True ENABLE_JASMINE = False @@ -315,6 +318,9 @@ EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' DEFAULT_FROM_EMAIL = 'registration@edx.org' DEFAULT_FEEDBACK_EMAIL = 'feedback@edx.org' SERVER_EMAIL = 'devops@edx.org' +TECH_SUPPORT_EMAIL = 'technical@edx.org' +CONTACT_EMAIL = 'info@edx.org' +BUGS_EMAIL = 'bugs@edx.org' ADMINS = ( ('edX Admins', 'admin@edx.org'), ) @@ -330,6 +336,8 @@ STATICFILES_DIRS = [ PROJECT_ROOT / "static", ] +FAVICON_PATH = 'images/favicon.ico' + # Locale/Internationalization TIME_ZONE = 'America/New_York' # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name LANGUAGE_CODE = 'en' # http://www.i18nguy.com/unicode/language-identifiers.html diff --git a/lms/envs/dev.py b/lms/envs/dev.py index 9d7c0b3ac2..ac0117ad28 100644 --- a/lms/envs/dev.py +++ b/lms/envs/dev.py @@ -243,3 +243,11 @@ MITX_FEATURES['ENABLE_PEARSON_LOGIN'] = False ANALYTICS_SERVER_URL = "http://127.0.0.1:9000/" ANALYTICS_API_KEY = "" + + +##################################################################### +# Lastly, see if the developer has any local overrides. +try: + from .private import * +except ImportError: + pass diff --git a/lms/static/sass/_shame.scss b/lms/static/sass/_shame.scss index d3cc0b9a80..ac6ac24b41 100644 --- a/lms/static/sass/_shame.scss +++ b/lms/static/sass/_shame.scss @@ -98,3 +98,16 @@ } } } + +//-------------------------------------- +// The Following is to enable themes to +// display H1s on login and register pages +//-------------------------------------- +.view-login .introduction header h1, +.view-register .introduction header h1 { + @include login_register_h1_style; +} + +footer .references { + @include footer_references_style; +} \ No newline at end of file diff --git a/lms/static/sass/application.scss.mako b/lms/static/sass/application.scss.mako index c310347b6f..823587bf04 100644 --- a/lms/static/sass/application.scss.mako +++ b/lms/static/sass/application.scss.mako @@ -4,6 +4,20 @@ @import 'base/font_face'; @import 'base/mixins'; @import 'base/variables'; + +## THEMING +## ------- +## Set up this file to import an edX theme library if the environment +## indicates that a theme should be used. The assumption is that the +## theme resides outside of this main edX repository, in a directory +## called themes//, with its base Sass file in +## themes//static/sass/_.scss. That one entry +## point can be used to @import in as many other things as needed. +% if env.get('THEME_NAME') is not None: + // import theme's Sass overrides + @import '${env.get('THEME_NAME')}'; +% endif + @import 'base/base'; @import 'base/extends'; @import 'base/animations'; @@ -36,16 +50,3 @@ @import 'news'; @import 'shame'; - -## THEMING -## ------- -## Set up this file to import an edX theme library if the environment -## indicates that a theme should be used. The assumption is that the -## theme resides outside of this main edX repository, in a directory -## called themes//, with its base Sass file in -## themes//static/sass/_.scss. That one entry -## point can be used to @import in as many other things as needed. -% if env.get('THEME_NAME') is not None: - // import theme's Sass overrides - @import '${env.get('THEME_NAME')}' -% endif diff --git a/lms/static/sass/base/_mixins.scss b/lms/static/sass/base/_mixins.scss index 97703e8f0f..0b2b82dad8 100644 --- a/lms/static/sass/base/_mixins.scss +++ b/lms/static/sass/base/_mixins.scss @@ -42,3 +42,11 @@ overflow: hidden; display: block; } + + +//----------------- +// Theme Mixin Styles +//----------------- +@mixin login_register_h1_style {} + +@mixin footer_references_style {} \ No newline at end of file diff --git a/lms/static/sass/base/_variables.scss b/lms/static/sass/base/_variables.scss index 2d0021c642..5c8c8d18d9 100644 --- a/lms/static/sass/base/_variables.scss +++ b/lms/static/sass/base/_variables.scss @@ -62,11 +62,12 @@ $lighter-base-font-color: rgb(100,100,100); $text-color: $dark-gray; $body-bg: rgb(250,250,250); +$container-bg: $white; $header-image: linear-gradient(-90deg, rgba(255,255,255, 1), rgba(230,230,230, 0.9)); -$header-bg: transparent; +$header-bg: $white; $courseware-header-image: linear-gradient(top, #fff, #eee); $courseware-header-bg: transparent; -$footer-bg: transparent; +$footer-bg: $white; $courseware-footer-border: none; $courseware-footer-shadow: none; $courseware-footer-margin: 0px; @@ -87,7 +88,7 @@ $dashboard-profile-header-color: transparent; $dashboard-profile-color: rgb(252,252,252); $dot-color: $light-gray; -$content-wrapper-bg: rgb(255,255,255); +$content-wrapper-bg: shade($body-bg, 2%); $course-bg-color: #d6d6d6; $course-bg-image: url(../images/bg-texture.png); @@ -100,6 +101,7 @@ $border-color-3: rgb(100,100,100); $border-color-4: rgb(252,252,252); $link-color: $blue; +$link-color-d1: $m-blue; $link-hover: $pink; $selection-color-1: $pink; $selection-color-2: #444; @@ -118,9 +120,18 @@ $sidebar-active-image: linear-gradient(top, #e6e6e6, #d6d6d6); $form-bg-color: #fff; $modal-bg-color: rgb(245,245,245); +//TOP HEADER IMAGE MARGIN +$header_image_margin: -69px; + +//FOOTER MARGIN +$footer_margin: ($baseline/4) 0 ($baseline*1.5) 0; + //----------------- // CSS BG Images //----------------- $homepage-bg-image: '../images/homepage-bg.jpg'; +$login-banner-image: '../images/bg-banner-login.png'; +$register-banner-image: '../images/bg-banner-register.png'; + $video-thumb-url: '../images/courses/video-thumb.jpg'; diff --git a/lms/static/sass/course.scss b/lms/static/sass/course.scss.mako similarity index 73% rename from lms/static/sass/course.scss rename to lms/static/sass/course.scss.mako index e57865fa9d..9d65505316 100644 --- a/lms/static/sass/course.scss +++ b/lms/static/sass/course.scss.mako @@ -4,6 +4,20 @@ @import 'base/font_face'; @import 'base/mixins'; @import 'base/variables'; + +## THEMING +## ------- +## Set up this file to import an edX theme library if the environment +## indicates that a theme should be used. The assumption is that the +## theme resides outside of this main edX repository, in a directory +## called themes//, with its base Sass file in +## themes//static/sass/_.scss. That one entry +## point can be used to @import in as many other things as needed. +% if env.get('THEME_NAME') is not None: + // import theme's Sass overrides + @import '${env.get('THEME_NAME')}'; +% endif + @import 'base/base'; @import 'base/extends'; @import 'base/animations'; diff --git a/lms/static/sass/course/layout/_courseware_header.scss b/lms/static/sass/course/layout/_courseware_header.scss index 9650dabc95..b1c14f930a 100644 --- a/lms/static/sass/course/layout/_courseware_header.scss +++ b/lms/static/sass/course/layout/_courseware_header.scss @@ -65,7 +65,7 @@ header.global.slim { height: auto; padding: 5px 0 10px 0; border-bottom: 1px solid $outer-border-color; - background: $white; + background: $header-bg; .guest .secondary { margin-right: 0; diff --git a/lms/static/sass/course/layout/_footer.scss b/lms/static/sass/course/layout/_footer.scss index 699846e781..8dc0ae540d 100644 --- a/lms/static/sass/course/layout/_footer.scss +++ b/lms/static/sass/course/layout/_footer.scss @@ -1,5 +1,4 @@ footer { - border: $courseware-footer-border; box-shadow: $courseware-footer-shadow; margin-top: $courseware-footer-margin; } \ No newline at end of file diff --git a/lms/static/sass/multicourse/_account.scss b/lms/static/sass/multicourse/_account.scss index 5147b6a09b..dfd803a22d 100644 --- a/lms/static/sass/multicourse/_account.scss +++ b/lms/static/sass/multicourse/_account.scss @@ -6,7 +6,7 @@ // page-level .view-register, .view-login, .view-passwordreset { - background: $white; + background: $body-bg; @@ -22,14 +22,14 @@ margin: 0 0 $baseline 0; font-weight: 300; text-transform: uppercase; - color: $m-blue; + color: $link-color-d1; } .heading-3 { font-size: 21px; margin: 0 0 $baseline 0; font-weight: 300; - color: $m-gray-d2; + color: $base-font-color; } .heading-4 { @@ -37,7 +37,7 @@ font-weight: 600; text-transform: uppercase; letter-spacing: 0 !important; - color: $m-blue-s1; + color: saturate($link-color-d1,15%); } .heading-5 { @@ -48,7 +48,7 @@ font-size: 18px; margin: 0 0 $baseline 0; font-weight: 300; - color: $m-gray-a1; + color: $base-font-color; font-family: 'Open Sans', sans-serif; line-height: lh(1.1); } @@ -56,18 +56,18 @@ .body-text { font-size: 15px; margin: 0 0 $baseline 0; - color: $m-gray-a1; + color: $base-font-color; line-height: lh(1); } // specific examples - buttons .button-primary { @include border-radius(0); - @include linear-gradient($m-blue-s1 5%, $m-blue-d1 95%); + @include linear-gradient(saturate($link-color-d1,15%) 5%, shade($link-color-d1,15%) 95%); display: inline-block; padding: $baseline/2 $baseline*2.5; text-transform: lowercase; - color: $white; + color: $very-light-text; letter-spacing: 0.1rem; font-weight: 500; cursor: pointer; @@ -80,11 +80,11 @@ } .button-secondary { - @include linear-gradient($m-gray 5%, $m-gray-d1 95%); + @include linear-gradient($outer-border-color 5%, $lighter-base-font-color 95%); display: inline-block; padding: $baseline/2 $baseline*2.5; text-transform: lowercase; - color: $white; + color: $very-light-text; letter-spacing: 0.1rem; font-weight: 600; cursor: pointer; @@ -98,7 +98,7 @@ // layout .content-wrapper { - background: $m-gray-l2; + background: $content-wrapper-bg; padding-bottom: 0; } @@ -107,7 +107,7 @@ @include clearfix; margin: 0 auto; width: 960px; - background: $white; + background: $container-bg; } .container { @@ -142,14 +142,15 @@ @include transition(color 0.15s ease-in-out, border 0.15s ease-in-out); &:link, &:visited, &:hover, &:active { - color: $m-blue; - text-decoration: none !important; + color: $link-color-d1; + font-weight: 400; + text-decoration: none !important; // needed but nasty font-family: $sans-serif; } &:hover, &:active { - border-bottom: 1px dotted $m-blue-l1; - color: $m-blue-l1; + text-decoration: none !important; // needed but nasty + border-bottom: 1px dotted $link-color-d1; } } @@ -254,7 +255,7 @@ font-family: $sans-serif; font-style: normal; font-weight: 500; - color: $m-gray-d2; + color: $base-font-color; } label { @@ -267,7 +268,7 @@ @include transition(color 0.15s ease-in-out); display: block; margin-top: ($baseline/4); - color: tint($m-gray, 50%); + color: tint($outer-border-color, 50%); font-size: em(13); } @@ -330,7 +331,7 @@ } textarea, input { - background: $white; + background: $body-bg; color: rgba(0,0,0,.25); } } @@ -339,11 +340,11 @@ &.is-focused { label { - color: $m-blue-l1; + color: saturate($link-color-d1,15%); } .tip { - color: $m-blue-l1; + color: saturate($link-color-d1,15%); } } @@ -461,7 +462,7 @@ // misc .orn-plus { - color: $white; + color: $very-light-text; padding: 0 $baseline/4; } @@ -492,7 +493,7 @@ header { height: 120px; border-bottom: 1px solid $m-gray; - background: transparent url("../images/bg-banner-login.png") 0 0 no-repeat; + background: transparent url($login-banner-image) 0 0 no-repeat; } } } @@ -506,14 +507,14 @@ header { height: 120px; border-bottom: 1px solid $m-gray; - background: transparent url("../images/bg-banner-register.png") 0 0 no-repeat; + background: transparent url($register-banner-image) 0 0 no-repeat; } } } // password reset .view-passwordreset { - background: $m-gray-l2; + background: $sidebar-color; header.global { @@ -543,7 +544,7 @@ .inner-wrapper { @include border-radius(2px); - background: $white; + background: $body-bg; padding-bottom: 0 !important; } diff --git a/lms/static/sass/multicourse/_course_about.scss b/lms/static/sass/multicourse/_course_about.scss index 0008bf1efe..096ecd6db2 100644 --- a/lms/static/sass/multicourse/_course_about.scss +++ b/lms/static/sass/multicourse/_course_about.scss @@ -11,7 +11,7 @@ border-bottom: 1px solid $border-color-3; @include box-shadow(inset 0 1px 5px 0 rgba(0,0,0, 0.1)); height: 280px; - margin-top: -69px; + margin-top: $header_image_margin; padding-top: 150px; overflow: hidden; position: relative; diff --git a/lms/static/sass/multicourse/_courses.scss b/lms/static/sass/multicourse/_courses.scss index ac31da4d2a..83680c06a0 100644 --- a/lms/static/sass/multicourse/_courses.scss +++ b/lms/static/sass/multicourse/_courses.scss @@ -10,7 +10,7 @@ border-bottom: 1px solid $border-color-3; @include box-shadow(inset 0 -1px 8px 0 rgba(0,0,0, 0.2), inset 0 1px 12px 0 rgba(0,0,0, 0.3)); height: 430px; - margin-top: -69px; + margin-top: $header_image_margin; width: 100%; .inner-wrapper { diff --git a/lms/static/sass/multicourse/_home.scss b/lms/static/sass/multicourse/_home.scss index d4def21f5c..05285262f5 100644 --- a/lms/static/sass/multicourse/_home.scss +++ b/lms/static/sass/multicourse/_home.scss @@ -15,7 +15,7 @@ @include clearfix; height: 460px; overflow: hidden; - margin-top: -69px; + margin-top: $header_image_margin; padding: 0px; width: flex-grid(12); diff --git a/lms/static/sass/shared/_footer.scss b/lms/static/sass/shared/_footer.scss index 864cf57d03..3c89c54faf 100644 --- a/lms/static/sass/shared/_footer.scss +++ b/lms/static/sass/shared/_footer.scss @@ -2,7 +2,7 @@ @include box-shadow(0 -1px 5px 0 rgba(0,0,0, 0.1)); border-top: 1px solid tint($m-gray,50%); padding: 25px ($baseline/2) ($baseline*1.5) ($baseline/2); - background: $white; + background: $footer-bg; footer { @include clearfix(); @@ -16,18 +16,18 @@ } a { - @include transition(color 0.15s ease-in-out, border 0.15s ease-in-out); + @include transition(link-color 0.15s ease-in-out, border 0.15s ease-in-out); &:link, &:visited, &:hover, &:active { border-bottom: none; - color: $m-blue; + color: $link-color; text-decoration: none !important; font-family: $sans-serif; } &:hover, &:active { - border-bottom: 1px dotted $m-blue-s1; - color: $m-blue-s1; + border-bottom: 1px dotted $link-color; + color: $link-color; } } @@ -39,7 +39,7 @@ .nav-colophon { @include clearfix(); - margin: ($baseline/4) 0 ($baseline*1.5) 0; + margin: $footer_margin; li { float: left; @@ -49,7 +49,7 @@ color: tint($black, 20%); &:hover, &:active { - color: $m-blue-s1; + color: $link-color; } } diff --git a/lms/static/sass/shared/_header.scss b/lms/static/sass/shared/_header.scss index e49accf904..0e161b6327 100644 --- a/lms/static/sass/shared/_header.scss +++ b/lms/static/sass/shared/_header.scss @@ -1,7 +1,7 @@ header.global { border-bottom: 1px solid $m-gray; @include box-shadow(0 1px 5px 0 rgba(0,0,0, 0.1)); - background: $white; + background: $header-bg; height: 76px; position: relative; width: 100%; @@ -246,12 +246,12 @@ header.global { a { display:block; padding: ($baseline/4); - color: $m-gray-d1; + color: $lighter-base-font-color; font-weight: 600; &:hover, &:active { text-decoration: none; - color: $m-blue-s1; + color: $link-color; } } @@ -259,7 +259,7 @@ header.global { a { text-decoration: none; - color: $m-blue-s1; + color: $link-color; } } } @@ -280,11 +280,11 @@ header.global { a { @include border-radius(0); - @include linear-gradient($m-blue-s1 5%, $m-blue-d1 95%); + @include linear-gradient(saturate($link-color-d1,15%) 5%, shade($link-color-d1,15%) 95%); display: inline-block; padding: $baseline/2 $baseline*2.5; text-transform: lowercase; - color: $white; + color: $very-light-text; letter-spacing: 0.1rem; font-weight: 300; cursor: pointer; @@ -324,6 +324,6 @@ header.global { a { text-decoration: none; - color: $m-blue-s1 !important; + color: $link-color !important; } } diff --git a/lms/templates/course.html b/lms/templates/course.html index f009955df1..e8c7cd5875 100644 --- a/lms/templates/course.html +++ b/lms/templates/course.html @@ -1,4 +1,5 @@ <%namespace name='static' file='static_content.html'/> +<%namespace file='main.html' import="stanford_theme_enabled"/> <%! from django.core.urlresolvers import reverse from courseware.courses import course_image_url, get_course_about_section @@ -24,7 +25,11 @@

${get_course_about_section(course, 'short_description')}

- ${get_course_about_section(course, 'university')} + % if stanford_theme_enabled(): + ${get_course_about_section(course, 'university')} + % else: + ${get_course_about_section(course, 'university')} + % endif ${course.start_date_text}
diff --git a/lms/templates/courseware/course_about.html b/lms/templates/courseware/course_about.html index 941bf61698..cc4b2ec317 100644 --- a/lms/templates/courseware/course_about.html +++ b/lms/templates/courseware/course_about.html @@ -8,7 +8,11 @@ <%inherit file="../main.html" /> <%block name="headextra"> - <%include file="../google_analytics.html" /> + % if self.theme_enabled(): + <%include file="../theme-google-analytics.html" /> + % else: + <%include file="../google_analytics.html" /> + % endif <%block name="js_extra"> @@ -46,7 +50,12 @@
-

${course.number}: ${get_course_about_section(course, "title")}${get_course_about_section(course, "university")}

+

+ ${course.number}: ${get_course_about_section(course, "title")} + % if not self.theme_enabled(): + ${get_course_about_section(course, "university")} + % endif +

@@ -105,14 +114,26 @@
diff --git a/lms/templates/courseware/courses.html b/lms/templates/courseware/courses.html index a8fe851d19..7f0d596f4b 100644 --- a/lms/templates/courseware/courses.html +++ b/lms/templates/courseware/courses.html @@ -5,13 +5,21 @@ <%block name="title">Courses
-
+ ## `news` should be `None` whenever a non-edX theme is enabled: + ## see common/djangoapps/student/views.py#_get_news %if news:
+ % endif
@@ -45,113 +52,116 @@
-

Explore free courses from edX universities

+ ## Disable university partner logos and sites for non-edX sites + % if not self.theme_enabled(): +

Explore free courses from edX universities

-
-
    -
  1. - - -
    - MITx -
    -
    -
  2. -
  3. - - -
    - HarvardX -
    -
    -
  4. -
  5. - - -
    - BerkeleyX -
    -
    -
  6. -
  7. - - -
    - UTx -
    -
    -
  8. -
  9. - - -
    - McGillX -
    -
    -
  10. -
  11. - - -
    - ANUx -
    -
    -
  12. -
+
+
    +
  1. + + +
    + MITx +
    +
    +
  2. +
  3. + + +
    + HarvardX +
    +
    +
  4. +
  5. + + +
    + BerkeleyX +
    +
    +
  6. +
  7. + + +
    + UTx +
    +
    +
  8. +
  9. + + +
    + McGillX +
    +
    +
  10. +
  11. + + +
    + ANUx +
    +
    +
  12. +
-
+
-
    -
  1. - - -
    - WellesleyX -
    -
    -
  2. -
  3. - - -
    - GeorgetownX -
    -
    -
  4. -
  5. - - -
    - University of TorontoX -
    -
    -
  6. -
  7. - - -
    - EPFLx -
    -
    -
  8. -
  9. - - -
    - DelftX -
    -
    -
  10. -
  11. - - -
    - RiceX -
    -
    -
  12. -
-
+
    +
  1. + + +
    + WellesleyX +
    +
    +
  2. +
  3. + + +
    + GeorgetownX +
    +
    +
  4. +
  5. + + +
    + University of TorontoX +
    +
    +
  6. +
  7. + + +
    + EPFLx +
    +
    +
  8. +
  9. + + +
    + DelftX +
    +
    +
  10. +
  11. + + +
    + RiceX +
    +
    +
  12. +
+
+ % endif
    @@ -165,47 +175,56 @@
-
-
-
-

edX News & Announcements

- edX MEDIA KIT -
-
-
- %for entry in news: -
- %if entry.image: - - %endif -
- ${entry.title} - %if entry.summary: -

${entry.summary}

- %endif - -
-
- %endfor -
- + % endif
diff --git a/lms/templates/invalid_email_key.html b/lms/templates/invalid_email_key.html index 437dfa151d..212f91fa9d 100644 --- a/lms/templates/invalid_email_key.html +++ b/lms/templates/invalid_email_key.html @@ -1,8 +1,16 @@ -

Invalid key

+<%inherit file="main.html" /> -

This e-mail key is not valid. Please check: -

    -
  • Was this key already used? Check whether the e-mail change has already happened. -
  • Did your e-mail client break the URL into two lines? -
  • The keys are valid for a limited amount of time. Has the key expired? -
+
+ +
+

Invalid email change key

+
+

This e-mail key is not valid. Please check:

+
    +
  • Was this key already used? Check whether the e-mail change has already happened. +
  • Did your e-mail client break the URL into two lines? +
  • The keys are valid for a limited amount of time. Has the key expired? +
+

Go back to the home page.

+
+
diff --git a/lms/templates/login.html b/lms/templates/login.html index 91210e7bb7..b185b02c84 100644 --- a/lms/templates/login.html +++ b/lms/templates/login.html @@ -5,7 +5,7 @@ <%! from django.core.urlresolvers import reverse %> <%! from django.utils.translation import ugettext as _ %> -<%block name="title">Log into your edX Account +<%block name="title">Log into your ${settings.PLATFORM_NAME} Account <%block name="js_extra"> - + <%static:css group='application'/> <%static:js group='main_vendor'/> <%block name="headextra"/> + % if theme_enabled(): + <%include file="theme-head-extra.html" /> + % endif @@ -107,7 +107,7 @@

- Please complete the following fields to register for an edX account.
+ Please complete the following fields to register for an account.
Required fields are noted by bold text and an asterisk (*).

@@ -203,7 +203,7 @@
  • - +
  • @@ -221,7 +221,14 @@
    - + <% + ## TODO: provide a better way to override these links + if self.stanford_theme_enabled(): + honor_code_path = marketing_link('TOS') + "#honor" + else: + honor_code_path = marketing_link('HONOR') + %> +
    @@ -252,23 +259,33 @@

    -
    -

    Welcome to edX

    -

    Registering with edX gives you access to all of our current and future free courses. Not ready to take a course just yet? Registering puts you on our mailing list – we will update you as courses are added.

    -
    + ## TODO: Use a %block tag or something to allow themes to + ## override in a more generalizable fashion. + % if not self.stanford_theme_enabled(): +
    +

    Welcome to ${settings.PLATFORM_NAME}

    +

    Registering with ${settings.PLATFORM_NAME} gives you access to all of our current and future free courses. Not ready to take a course just yet? Registering puts you on our mailing list – we will update you as courses are added.

    +
    + % endif

    Next Steps

    -

    As part of joining edX, you will receive an activation email. You must click on the activation link to complete the process. Don’t see the email? Check your spam folder and mark edX emails as ‘not spam’. At edX, we communicate mostly through email.

    + % if self.stanford_theme_enabled(): +

    You will receive an activation email. You must click on the activation link to complete the process. Don’t see the email? Check your spam folder and mark emails from class.stanford.edu as ‘not spam’, since you'll want to be able to receive email from your courses.

    + % else: +

    As part of joining ${settings.PLATFORM_NAME}, you will receive an activation email. You must click on the activation link to complete the process. Don’t see the email? Check your spam folder and mark ${settings.PLATFORM_NAME} emails as ‘not spam’. At ${settings.PLATFORM_NAME}, we communicate mostly through email.

    + % endif
    -
    -

    Need Help?

    -

    Need help in registering with edX? - - View our FAQs for answers to commonly asked questions. - - Once registered, most questions can be answered in the course specific discussion forums or through the FAQs.

    -
    + % if settings.MKTG_URL_LINK_MAP.get('FAQ'): +
    +

    Need Help?

    +

    Need help in registering with ${settings.PLATFORM_NAME}? + + View our FAQs for answers to commonly asked questions. + + Once registered, most questions can be answered in the course specific discussion forums or through the FAQs.

    +
    + % endif
    diff --git a/lms/templates/registration/activation_invalid.html b/lms/templates/registration/activation_invalid.html index 09d373a39d..0a6d6d30c9 100644 --- a/lms/templates/registration/activation_invalid.html +++ b/lms/templates/registration/activation_invalid.html @@ -12,7 +12,7 @@

    Something went wrong. Check to make sure the URL you went to was correct -- e-mail programs will sometimes split it into two lines. If you still have issues, e-mail us to let us know what happened - at bugs@edx.org.

    + at ${settings.BUGS_EMAIL}.

    Or you can go back to the home page.

    diff --git a/lms/templates/static_templates/404.html b/lms/templates/static_templates/404.html index f29968e2f5..c297cec881 100644 --- a/lms/templates/static_templates/404.html +++ b/lms/templates/static_templates/404.html @@ -4,5 +4,5 @@

    Page not found

    -

    The page that you were looking for was not found. Go back to the homepage or let us know about any pages that may have been moved at technical@edx.org.

    +

    The page that you were looking for was not found. Go back to the homepage or let us know about any pages that may have been moved at ${settings.TECH_SUPPORT_EMAIL}.

    diff --git a/lms/templates/static_templates/server-down.html b/lms/templates/static_templates/server-down.html index 7fada34a53..ac847db9ee 100644 --- a/lms/templates/static_templates/server-down.html +++ b/lms/templates/static_templates/server-down.html @@ -1,6 +1,6 @@ <%inherit file="../main.html" />
    -

    Currently the edX servers are down

    -

    Our staff is currently working to get the site back up as soon as possible. Please email us at technical@edx.org to report any problems or downtime.

    +

    Currently the ${settings.PLATFORM_NAME} servers are down

    +

    Our staff is currently working to get the site back up as soon as possible. Please email us at ${settings.TECH_SUPPORT_EMAIL} to report any problems or downtime.

    diff --git a/lms/templates/static_templates/server-error.html b/lms/templates/static_templates/server-error.html index 5564ea082e..04fc11d11a 100644 --- a/lms/templates/static_templates/server-error.html +++ b/lms/templates/static_templates/server-error.html @@ -1,6 +1,6 @@ <%inherit file="../main.html" />
    -

    There has been a 500 error on the edX servers

    -

    Please wait a few seconds and then reload the page. If the problem persists, please email us at technical@edx.org.

    +

    There has been a 500 error on the ${settings.PLATFORM_NAME} servers

    +

    Please wait a few seconds and then reload the page. If the problem persists, please email us at ${settings.TECH_SUPPORT_EMAIL}.

    diff --git a/lms/templates/static_templates/server-overloaded.html b/lms/templates/static_templates/server-overloaded.html index bbf4550ff4..2432f2b481 100644 --- a/lms/templates/static_templates/server-overloaded.html +++ b/lms/templates/static_templates/server-overloaded.html @@ -1,6 +1,6 @@ <%inherit file="../main.html" />
    -

    Currently the edX servers are overloaded

    -

    Our staff is currently working to get the site back up as soon as possible. Please email us at technical@edx.org to report any problems or downtime.

    +

    Currently the ${settings.PLATFORM_NAME} servers are overloaded

    +

    Our staff is currently working to get the site back up as soon as possible. Please email us at ${settings.TECH_SUPPORT_EMAIL} to report any problems or downtime.

    diff --git a/lms/urls.py b/lms/urls.py index 152670adf7..32af67b1ab 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -58,66 +58,92 @@ urlpatterns = ('', # nopep8 name='auth_password_reset_done'), url(r'^heartbeat$', include('heartbeat.urls')), +) - ## - ## Only universities without courses should be included here. If - ## courses exist, the dynamic profile rule below should win. - ## - url(r'^(?i)university_profile/WellesleyX$', 'courseware.views.static_university_profile', - name="static_university_profile", kwargs={'org_id': 'WellesleyX'}), - url(r'^(?i)university_profile/McGillX$', 'courseware.views.static_university_profile', - name="static_university_profile", kwargs={'org_id': 'McGillX'}), - url(r'^(?i)university_profile/TorontoX$', 'courseware.views.static_university_profile', - name="static_university_profile", kwargs={'org_id': 'TorontoX'}), - url(r'^(?i)university_profile/RiceX$', 'courseware.views.static_university_profile', - name="static_university_profile", kwargs={'org_id': 'RiceX'}), - url(r'^(?i)university_profile/ANUx$', 'courseware.views.static_university_profile', - name="static_university_profile", kwargs={'org_id': 'ANUx'}), - url(r'^(?i)university_profile/EPFLx$', 'courseware.views.static_university_profile', - name="static_university_profile", kwargs={'org_id': 'EPFLx'}), +# University profiles only make sense in the default edX context +if not settings.MITX_FEATURES["USE_CUSTOM_THEME"]: + urlpatterns += ( + ## + ## Only universities without courses should be included here. If + ## courses exist, the dynamic profile rule below should win. + ## + url(r'^(?i)university_profile/WellesleyX$', 'courseware.views.static_university_profile', + name="static_university_profile", kwargs={'org_id': 'WellesleyX'}), + url(r'^(?i)university_profile/McGillX$', 'courseware.views.static_university_profile', + name="static_university_profile", kwargs={'org_id': 'McGillX'}), + url(r'^(?i)university_profile/TorontoX$', 'courseware.views.static_university_profile', + name="static_university_profile", kwargs={'org_id': 'TorontoX'}), + url(r'^(?i)university_profile/RiceX$', 'courseware.views.static_university_profile', + name="static_university_profile", kwargs={'org_id': 'RiceX'}), + url(r'^(?i)university_profile/ANUx$', 'courseware.views.static_university_profile', + name="static_university_profile", kwargs={'org_id': 'ANUx'}), + url(r'^(?i)university_profile/EPFLx$', 'courseware.views.static_university_profile', + name="static_university_profile", kwargs={'org_id': 'EPFLx'}), - url(r'^university_profile/(?P[^/]+)$', 'courseware.views.university_profile', - name="university_profile"), + url(r'^university_profile/(?P[^/]+)$', 'courseware.views.university_profile', + name="university_profile"), + ) - #Semi-static views (these need to be rendered and have the login bar, but don't change) +#Semi-static views (these need to be rendered and have the login bar, but don't change) +urlpatterns += ( url(r'^404$', 'static_template_view.views.render', {'template': '404.html'}, name="404"), - url(r'^about$', 'static_template_view.views.render', - {'template': 'about.html'}, name="about_edx"), - url(r'^jobs$', 'static_template_view.views.render', - {'template': 'jobs.html'}, name="jobs"), - url(r'^contact$', 'static_template_view.views.render', - {'template': 'contact.html'}, name="contact"), - url(r'^press$', 'student.views.press', name="press"), - url(r'^media-kit$', 'static_template_view.views.render', - {'template': 'media-kit.html'}, name="media-kit"), - url(r'^faq$', 'static_template_view.views.render', - {'template': 'faq.html'}, name="faq_edx"), - url(r'^help$', 'static_template_view.views.render', - {'template': 'help.html'}, name="help_edx"), - - url(r'^tos$', 'static_template_view.views.render', - {'template': 'tos.html'}, name="tos"), - url(r'^privacy$', 'static_template_view.views.render', - {'template': 'privacy.html'}, name="privacy_edx"), - # TODO: (bridger) The copyright has been removed until it is updated for edX - # url(r'^copyright$', 'static_template_view.views.render', - # {'template': 'copyright.html'}, name="copyright"), - url(r'^honor$', 'static_template_view.views.render', - {'template': 'honor.html'}, name="honor"), - - #Press releases - url(r'^press/([_a-zA-Z0-9-]+)$', 'static_template_view.views.render_press_release', name='press_release'), - - # Favicon - (r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}), - - url(r'^submit_feedback$', 'util.views.submit_feedback_via_zendesk'), - - # TODO: These urls no longer work. They need to be updated before they are re-enabled - # url(r'^reactivate/(?P[^/]*)$', 'student.views.reactivation_email'), ) +# Semi-static views only used by edX, not by themes +if not settings.MITX_FEATURES["USE_CUSTOM_THEME"]: + urlpatterns += ( + url(r'^jobs$', 'static_template_view.views.render', + {'template': 'jobs.html'}, name="jobs"), + url(r'^press$', 'student.views.press', name="press"), + url(r'^media-kit$', 'static_template_view.views.render', + {'template': 'media-kit.html'}, name="media-kit"), + url(r'^help$', 'static_template_view.views.render', + {'template': 'help.html'}, name="help_edx"), + + # TODO: (bridger) The copyright has been removed until it is updated for edX + # url(r'^copyright$', 'static_template_view.views.render', + # {'template': 'copyright.html'}, name="copyright"), + + #Press releases + url(r'^press/([_a-zA-Z0-9-]+)$', 'static_template_view.views.render_press_release', name='press_release'), + + # Favicon + (r'^favicon\.ico$', 'django.views.generic.simple.redirect_to', {'url': '/static/images/favicon.ico'}), + + url(r'^submit_feedback$', 'util.views.submit_feedback_via_zendesk'), + + # TODO: These urls no longer work. They need to be updated before they are re-enabled + # url(r'^reactivate/(?P[^/]*)$', 'student.views.reactivation_email'), + ) + +# Only enable URLs for those marketing links actually enabled in the +# settings. Disable URLs by marking them as None. +for key, value in settings.MKTG_URL_LINK_MAP.items(): + # Skip disabled URLs + if value is None: + continue + + # These urls are enabled separately + if key == "ROOT" or key == "COURSES": + continue + + # Make the assumptions that the templates are all in the same dir + # and that they all match the name of the key (plus extension) + template = "%s.html" % key.lower() + + # To allow theme templates to inherit from default templates, + # prepend a standard prefix + if settings.MITX_FEATURES["USE_CUSTOM_THEME"]: + template = "theme-" + template + + # Make the assumption that the URL we want is the lowercased + # version of the map key + urlpatterns += (url(r'^%s' % key.lower(), + 'static_template_view.views.render', + {'template': template}, name=value),) + + if settings.PERFSTATS: urlpatterns += (url(r'^reprofile$', 'perfstats.views.end_profile'),) diff --git a/rakefiles/tests.rake b/rakefiles/tests.rake index 448a482f04..1c576f2cbb 100644 --- a/rakefiles/tests.rake +++ b/rakefiles/tests.rake @@ -81,12 +81,11 @@ TEST_TASK_DIRS = [] end Dir["common/lib/*"].select{|lib| File.directory?(lib)}.each do |lib| - task_name = "test_#{lib}" report_dir = report_dir_path(lib) desc "Run tests for common lib #{lib}" - task task_name => report_dir do + task "test_#{lib}" => ["clean_test_files", report_dir] do ENV['NOSE_XUNIT_FILE'] = File.join(report_dir, "nosetests.xml") cmd = "nosetests #{lib}" sh(run_under_coverage(cmd, lib)) do |ok, res| @@ -95,10 +94,13 @@ Dir["common/lib/*"].select{|lib| File.directory?(lib)}.each do |lib| end TEST_TASK_DIRS << lib - desc "Run tests for common lib #{lib} (without coverage)" - task "fasttest_#{lib}" do - sh("nosetests #{lib}") - end + # There used to be a fasttest_#{lib} command that ran without coverage. + # However, this is an inconsistent usage of "fast": + # When running tests for lms and cms, "fast" means skipping + # staticfiles collection, but still running under coverage. + # We keep the fasttest_#{lib} command for backwards compatibility, + # but make it an alias to the normal test command. + task "fasttest_#{lib}" => "test_#{lib}" end task :report_dirs @@ -119,30 +121,35 @@ task :test do end end -namespace :coverage do - desc "Build the html coverage reports" - task :html => :report_dirs do - TEST_TASK_DIRS.each do |dir| - report_dir = report_dir_path(dir) +desc "Build the html, xml, and diff coverage reports" +task :coverage => :report_dirs do - if !File.file?("#{report_dir}/.coverage") - next - end + found_coverage_info = false - sh("coverage html --rcfile=#{dir}/.coveragerc") + TEST_TASK_DIRS.each do |dir| + report_dir = report_dir_path(dir) + + if !File.file?("#{report_dir}/.coverage") + next + else + found_coverage_info = true end + + # Generate the coverage.py HTML report + sh("coverage html --rcfile=#{dir}/.coveragerc") + + # Generate the coverage.py XML report + sh("coverage xml -o #{report_dir}/coverage.xml --rcfile=#{dir}/.coveragerc") + + # Generate the diff coverage HTML report, based on the XML report + sh("diff-cover #{report_dir}/coverage.xml --html-report #{report_dir}/diff_cover.html") + + # Print the diff coverage report to the console + sh("diff-cover #{report_dir}/coverage.xml") + puts "\n" end - desc "Build the xml coverage reports" - task :xml => :report_dirs do - TEST_TASK_DIRS.each do |dir| - report_dir = report_dir_path(dir) - - if !File.file?("#{report_dir}/.coverage") - next - end - # Why doesn't the rcfile control the xml output file properly?? - sh("coverage xml -o #{report_dir}/coverage.xml --rcfile=#{dir}/.coveragerc") - end + if not found_coverage_info + puts "No coverage info found. Run `rake test` before running `rake coverage`." end end diff --git a/requirements/edx/github.txt b/requirements/edx/github.txt index b1aef0a108..fc9070bba3 100644 --- a/requirements/edx/github.txt +++ b/requirements/edx/github.txt @@ -10,3 +10,4 @@ # Our libraries: -e git+https://github.com/edx/XBlock.git@2144a25d#egg=XBlock -e git+https://github.com/edx/codejail.git@5fb5fa0#egg=codejail +-e git+https://github.com/edx/diff-cover.git@v0.1.0#egg=diff_cover