Commit 3885e6cf by Don Mitchell

Merge branch 'release'

Conflicts:
	lms/templates/help_modal.html
	lms/templates/index.html
parents 565769b6 95f4acd5
......@@ -54,6 +54,8 @@ from contentstore import utils
from student.roles import CourseInstructorRole, CourseStaffRole, CourseCreatorRole
from student import auth
from microsite_configuration.middleware import MicrositeConfiguration
__all__ = ['course_info_handler', 'course_handler', 'course_info_update_handler',
'settings_handler',
'grading_handler',
......@@ -417,15 +419,21 @@ def settings_handler(request, tag=None, package_id=None, branch=None, version_gu
if 'text/html' in request.META.get('HTTP_ACCEPT', '') and request.method == 'GET':
upload_asset_url = locator.url_reverse('assets/')
# see if the ORG of this course can be attributed to a 'Microsite'. In that case, the
# course about page should be editable in Studio
about_page_editable = not MicrositeConfiguration.get_microsite_configuration_value_for_org(
course_module.location.org,
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)
return render_to_response('settings.html', {
'context_course': course_module,
'course_locator': locator,
'lms_link_for_about_page': utils.get_lms_link_for_about_page(course_module.location),
'course_image_url': utils.course_image_url(course_module),
'details_url': locator.url_reverse('/settings/details/'),
'about_page_editable': not settings.FEATURES.get(
'ENABLE_MKTG_SITE', False
),
'about_page_editable': about_page_editable,
'upload_asset_url': upload_asset_url
})
elif 'application/json' in request.META.get('HTTP_ACCEPT', ''):
......
......@@ -10,6 +10,8 @@ from edxmako.shortcuts import render_to_response
from external_auth.views import ssl_login_shortcut
from microsite_configuration.middleware import MicrositeConfiguration
__all__ = ['signup', 'login_page', 'howitworks']
......@@ -29,10 +31,14 @@ def login_page(request):
Display the login form.
"""
csrf_token = csrf(request)['csrf_token']
return render_to_response('login.html', {
'csrf': csrf_token,
'forgot_password_link': "//{base}/login#forgot-password-modal".format(base=settings.LMS_BASE),
})
return render_to_response(
'login.html',
{
'csrf': csrf_token,
'forgot_password_link': "//{base}/login#forgot-password-modal".format(base=settings.LMS_BASE),
'platform_name': MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME),
}
)
def howitworks(request):
......
......@@ -9,6 +9,7 @@ This is the default template for our main set of AWS servers.
import json
from .common import *
from logsettings import get_logger_config
import os
......@@ -145,7 +146,6 @@ COURSES_WITH_UNSAFE_CODE = ENV_TOKENS.get("COURSES_WITH_UNSAFE_CODE", [])
#Timezone overrides
TIME_ZONE = ENV_TOKENS.get('TIME_ZONE', TIME_ZONE)
ENV_FEATURES = ENV_TOKENS.get('FEATURES', ENV_TOKENS.get('MITX_FEATURES', {}))
for feature, value in ENV_FEATURES.items():
FEATURES[feature] = value
......@@ -213,3 +213,16 @@ BROKER_URL = "{0}://{1}:{2}@{3}/{4}".format(CELERY_BROKER_TRANSPORT,
# Event tracking
TRACKING_BACKENDS.update(AUTH_TOKENS.get("TRACKING_BACKENDS", {}))
SUBDOMAIN_BRANDING = ENV_TOKENS.get('SUBDOMAIN_BRANDING', {})
VIRTUAL_UNIVERSITIES = ENV_TOKENS.get('VIRTUAL_UNIVERSITIES', [])
MICROSITE_CONFIGURATION = ENV_TOKENS.get('MICROSITE_CONFIGURATION', {})
MICROSITE_ROOT_DIR = ENV_TOKENS.get('MICROSITE_ROOT_DIR')
if len(MICROSITE_CONFIGURATION.keys()) > 0:
enable_microsites(
MICROSITE_CONFIGURATION,
SUBDOMAIN_BRANDING,
VIRTUAL_UNIVERSITIES,
microsites_root=path(MICROSITE_ROOT_DIR)
)
......@@ -25,7 +25,7 @@ Longer TODO:
import sys
import lms.envs.common
from lms.envs.common import USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG
from lms.envs.common import USE_TZ, TECH_SUPPORT_EMAIL, PLATFORM_NAME, BUGS_EMAIL, DOC_STORE_CONFIG, enable_microsites
from path import path
from lms.lib.xblock.mixin import LmsBlockMixin
......
"""
This is a localdev test for the Microsite processing pipeline
"""
# We intentionally define lots of variables that aren't used, and
# want to import all variables from base settings files
# pylint: disable=W0401, W0614
from .dev import *
from .dev import SUBDOMAIN_BRANDING, VIRTUAL_UNIVERSITIES
MICROSITE_NAMES = ['openedx']
MICROSITE_CONFIGURATION = {}
if MICROSITE_NAMES and len(MICROSITE_NAMES) > 0:
enable_microsites(MICROSITE_NAMES, MICROSITE_CONFIGURATION, SUBDOMAIN_BRANDING, VIRTUAL_UNIVERSITIES)
......@@ -16,6 +16,8 @@ from django.template import Context
from django.http import HttpResponse
import logging
from microsite_configuration.middleware import MicrositeConfiguration
import edxmako
import edxmako.middleware
from django.conf import settings
......@@ -71,6 +73,10 @@ def marketing_link_context_processor(request):
def render_to_string(template_name, dictionary, context=None, namespace='main'):
# see if there is an override template defined in the microsite
template_name = MicrositeConfiguration.get_microsite_template_path(template_name)
context_instance = Context(dictionary)
# add dictionary to context_instance
context_instance.update(dictionary or {})
......@@ -98,5 +104,9 @@ def render_to_response(template_name, dictionary=None, context_instance=None, na
Returns a HttpResponse whose content is filled with the result of calling
lookup.get_template(args[0]).render with the passed arguments.
"""
# see if there is an override template defined in the microsite
template_name = MicrositeConfiguration.get_microsite_template_path(template_name)
dictionary = dictionary or {}
return HttpResponse(render_to_string(template_name, dictionary, context_instance, namespace), **kwargs)
"""
This file implements the initial Microsite support for the Open edX platform.
A microsite enables the following features:
1) Mapping of sub-domain name to a 'brand', e.g. foo-university.edx.org
2) Present a landing page with a listing of courses that are specific to the 'brand'
3) Ability to swap out some branding elements in the website
"""
import threading
import os.path
from django.conf import settings
_microsite_configuration_threadlocal = threading.local()
_microsite_configuration_threadlocal.data = {}
def has_microsite_configuration_set():
"""
Returns whether the MICROSITE_CONFIGURATION has been set in the configuration files
"""
return getattr(settings, "MICROSITE_CONFIGURATION", False)
class MicrositeConfiguration(object):
"""
Middleware class which will bind configuration information regarding 'microsites' on a per request basis.
The actual configuration information is taken from Django settings information
"""
@classmethod
def is_request_in_microsite(cls):
"""
This will return if current request is a request within a microsite
"""
return cls.get_microsite_configuration()
@classmethod
def get_microsite_configuration(cls):
"""
Returns the current request's microsite configuration
"""
if not hasattr(_microsite_configuration_threadlocal, 'data'):
return {}
return _microsite_configuration_threadlocal.data
@classmethod
def get_microsite_configuration_value(cls, val_name, default=None):
"""
Returns a value associated with the request's microsite, if present
"""
configuration = cls.get_microsite_configuration()
return configuration.get(val_name, default)
@classmethod
def get_microsite_template_path(cls, relative_path):
"""
Returns a path to a Mako template, which can either be in
a microsite directory (as an override) or will just return what is passed in
"""
if not cls.is_request_in_microsite():
return relative_path
microsite_template_path = cls.get_microsite_configuration_value('template_dir')
if microsite_template_path:
search_path = microsite_template_path / relative_path
if os.path.isfile(search_path):
path = '{0}/templates/{1}'.format(
cls.get_microsite_configuration_value('microsite_name'),
relative_path
)
return path
return relative_path
@classmethod
def get_microsite_configuration_value_for_org(cls, org, val_name, default=None):
"""
This returns a configuration value for a microsite which has an org_filter that matches
what is passed in
"""
if not has_microsite_configuration_set():
return default
for key in settings.MICROSITE_CONFIGURATION.keys():
org_filter = settings.MICROSITE_CONFIGURATION[key].get('course_org_filter', None)
if org_filter == org:
return settings.MICROSITE_CONFIGURATION[key].get(val_name, default)
return default
@classmethod
def get_all_microsite_orgs(cls):
"""
This returns a set of orgs that are considered within a Microsite. This can be used,
for example, to do filtering
"""
org_filter_set = []
if not has_microsite_configuration_set():
return org_filter_set
for key in settings.MICROSITE_CONFIGURATION:
org_filter = settings.MICROSITE_CONFIGURATION[key].get('course_org_filter')
if org_filter:
org_filter_set.append(org_filter)
return org_filter_set
def clear_microsite_configuration(self):
"""
Clears out any microsite configuration from the current request/thread
"""
_microsite_configuration_threadlocal.data = {}
def process_request(self, request):
"""
Middleware entry point on every request processing. This will associate a request's domain name
with a 'University' and any corresponding microsite configuration information
"""
self.clear_microsite_configuration()
domain = request.META.get('HTTP_HOST', None)
if domain:
subdomain = MicrositeConfiguration.pick_subdomain(domain, settings.SUBDOMAIN_BRANDING.keys())
university = MicrositeConfiguration.match_university(subdomain)
microsite_configuration = self.get_microsite_configuration_for_university(university)
if microsite_configuration:
microsite_configuration['university'] = university
microsite_configuration['subdomain'] = subdomain
microsite_configuration['site_domain'] = domain
_microsite_configuration_threadlocal.data = microsite_configuration
# also put the configuration on the request itself to make it easier to dereference
request.microsite_configuration = _microsite_configuration_threadlocal.data
return None
def process_response(self, request, response):
"""
Middleware entry point for request completion.
"""
self.clear_microsite_configuration()
return response
def get_microsite_configuration_for_university(self, university):
"""
For a given university, return the microsite configuration which
is in the Django settings
"""
if not university:
return None
if not has_microsite_configuration_set():
return None
configuration = settings.MICROSITE_CONFIGURATION.get(university, None)
return configuration
@classmethod
def match_university(cls, domain):
"""
Return the university name specified for the domain, or None
if no university was specified
"""
if not settings.FEATURES['SUBDOMAIN_BRANDING'] or domain is None:
return None
subdomain = cls.pick_subdomain(domain, settings.SUBDOMAIN_BRANDING.keys())
return settings.SUBDOMAIN_BRANDING.get(subdomain)
@classmethod
def pick_subdomain(cls, domain, options, default='default'):
"""
Attempt to match the incoming request's HOST domain with a configuration map
to see what subdomains are supported in Microsites.
"""
for option in options:
if domain.startswith(option):
return option
return default
......@@ -71,6 +71,7 @@ from pytz import UTC
from util.json_request import JsonResponse
from microsite_configuration.middleware import MicrositeConfiguration
log = logging.getLogger("edx.student")
AUDIT_LOG = logging.getLogger("audit")
......@@ -250,7 +251,11 @@ def signin_user(request):
context = {
'course_id': request.GET.get('course_id'),
'enrollment_action': request.GET.get('enrollment_action')
'enrollment_action': request.GET.get('enrollment_action'),
'platform_name': MicrositeConfiguration.get_microsite_configuration_value(
'platform_name',
settings.PLATFORM_NAME
),
}
return render_to_response('login.html', context)
......@@ -269,7 +274,11 @@ def register_user(request, extra_context=None):
context = {
'course_id': request.GET.get('course_id'),
'enrollment_action': request.GET.get('enrollment_action')
'enrollment_action': request.GET.get('enrollment_action'),
'platform_name': MicrositeConfiguration.get_microsite_configuration_value(
'platform_name',
settings.PLATFORM_NAME
),
}
if extra_context is not None:
context.update(extra_context)
......@@ -311,9 +320,33 @@ def dashboard(request):
# longer exist (because the course IDs have changed). Still, we don't delete those
# enrollments, because it could have been a data push snafu.
course_enrollment_pairs = []
# for microsites, we want to filter and only show enrollments for courses within
# the microsites 'ORG'
course_org_filter = MicrositeConfiguration.get_microsite_configuration_value('course_org_filter')
# Let's filter out any courses in an "org" that has been declared to be
# in a Microsite
org_filter_out_set = MicrositeConfiguration.get_all_microsite_orgs()
# remove our current Microsite from the "filter out" list, if applicable
if course_org_filter:
org_filter_out_set.remove(course_org_filter)
for enrollment in CourseEnrollment.enrollments_for_user(user):
try:
course_enrollment_pairs.append((course_from_id(enrollment.course_id), enrollment))
course = course_from_id(enrollment.course_id)
# if we are in a Microsite, then filter out anything that is not
# attributed (by ORG) to that Microsite
if course_org_filter and course_org_filter != course.location.org:
continue
# Conversely, if we are not in a Microsite, then let's filter out any enrollments
# with courses attributed (by ORG) to Microsites
elif course.location.org in org_filter_out_set:
continue
course_enrollment_pairs.append((course, enrollment))
except ItemNotFoundError:
log.error("User {0} enrolled in non-existent course {1}"
.format(user.username, enrollment.course_id))
......@@ -539,7 +572,11 @@ def accounts_login(request):
course_id = _parse_course_id_from_string(redirect_to)
if course_id and _get_course_enrollment_domain(course_id):
return external_auth.views.course_specific_login(request, course_id)
return render_to_response('login.html')
context = {
'platform_name': settings.PLATFORM_NAME,
}
return render_to_response('login.html', context)
# Need different levels of logging
......@@ -899,26 +936,31 @@ def create_account(request, post_override=None):
return ret
(user, profile, registration) = ret
d = {'name': post_vars['name'],
'key': registration.activation_key,
}
context = {
'name': post_vars['name'],
'key': registration.activation_key,
}
# composes activation email
subject = render_to_string('emails/activation_email_subject.txt', d)
subject = render_to_string('emails/activation_email_subject.txt', context)
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
message = render_to_string('emails/activation_email.txt', d)
message = render_to_string('emails/activation_email.txt', context)
# don't send email if we are doing load testing or random user generation for some reason
if not (settings.FEATURES.get('AUTOMATIC_AUTH_FOR_TESTING')):
from_address = MicrositeConfiguration.get_microsite_configuration_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
try:
if settings.FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
dest_addr = settings.FEATURES['REROUTE_ACTIVATION_EMAIL']
message = ("Activation for %s (%s): %s\n" % (user, user.email, profile.name) +
'-' * 80 + '\n\n' + message)
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
send_mail(subject, message, from_address, [dest_addr], fail_silently=False)
else:
_res = user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
_res = user.email_user(subject, message, from_address)
except:
log.warning('Unable to send activation email to user', exc_info=True)
js['value'] = _('Could not send activation e-mail.')
......@@ -1202,15 +1244,23 @@ def change_email_request(request):
return HttpResponse(json.dumps({'success': False,
'error': _('Old email is the same as the new email.')}))
d = {'key': pec.activation_key,
'old_email': user.email,
'new_email': pec.new_email}
context = {
'key': pec.activation_key,
'old_email': user.email,
'new_email': pec.new_email
}
subject = render_to_string('emails/email_change_subject.txt', d)
subject = render_to_string('emails/email_change_subject.txt', context)
subject = ''.join(subject.splitlines())
message = render_to_string('emails/email_change.txt', d)
_res = send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [pec.new_email])
message = render_to_string('emails/email_change.txt', context)
from_address = MicrositeConfiguration.get_microsite_configuration_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
_res = send_mail(subject, message, from_address, [pec.new_email])
return HttpResponse(json.dumps({'success': True}))
......
""" Utility functions related to HTTP requests """
from django.conf import settings
from microsite_configuration.middleware import MicrositeConfiguration
def safe_get_host(request):
......@@ -14,4 +15,4 @@ def safe_get_host(request):
if isinstance(settings.ALLOWED_HOSTS, (list, tuple)) and '*' not in settings.ALLOWED_HOSTS:
return request.get_host()
else:
return settings.SITE_NAME
return MicrositeConfiguration.get_microsite_configuration_value('site_domain', settings.SITE_NAME)
......@@ -3,11 +3,14 @@ from fs.errors import ResourceNotFoundError
import logging
import os
import sys
from datetime import datetime
from lxml import etree
from path import path
from pytz import UTC
from pkg_resources import resource_string
from xblock.fields import Scope, String, Boolean
from xmodule.fields import Date
from xmodule.editing_module import EditingDescriptor
from xmodule.html_checker import check_html
from xmodule.stringify import stringify_children
......@@ -227,6 +230,12 @@ class AboutFields(object):
default="",
scope=Scope.content
)
# this exists purely to override the default start date
start = Date(
help="placeholder to make sure that About is always active",
default=datetime.fromtimestamp(0, UTC),
scope=Scope.settings,
)
class AboutModule(AboutFields, HtmlModule):
......
......@@ -2,15 +2,10 @@ from xmodule.modulestore.django import modulestore
from xmodule.course_module import CourseDescriptor
from django.conf import settings
from microsite_configuration.middleware import MicrositeConfiguration
def pick_subdomain(domain, options, default='default'):
for option in options:
if domain.startswith(option):
return option
return default
def get_visible_courses(domain=None):
def get_visible_courses():
"""
Return the set of CourseDescriptors that should be visible in this branded instance
"""
......@@ -20,31 +15,52 @@ def get_visible_courses(domain=None):
if isinstance(c, CourseDescriptor)]
courses = sorted(courses, key=lambda course: course.number)
if domain and settings.FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
subdomain = pick_subdomain(domain, settings.COURSE_LISTINGS.keys())
visible_ids = frozenset(settings.COURSE_LISTINGS[subdomain])
return [course for course in courses if course.id in visible_ids]
subdomain = MicrositeConfiguration.get_microsite_configuration_value('subdomain')
# See if we have filtered course listings in this domain
filtered_visible_ids = None
# this is legacy format which is outside of the microsite feature
if hasattr(settings, 'COURSE_LISTINGS') and subdomain in settings.COURSE_LISTINGS:
filtered_visible_ids = frozenset(settings.COURSE_LISTINGS[subdomain])
filtered_by_org = MicrositeConfiguration.get_microsite_configuration_value('course_org_filter')
if filtered_by_org:
return [course for course in courses if course.location.org == filtered_by_org]
if filtered_visible_ids:
return [course for course in courses if course.id in filtered_visible_ids]
else:
return courses
# Let's filter out any courses in an "org" that has been declared to be
# in a Microsite
org_filter_out_set = MicrositeConfiguration.get_all_microsite_orgs()
return [course for course in courses if course.location.org not in org_filter_out_set]
def get_university(domain=None):
def get_university_for_request():
"""
Return the university name specified for the domain, or None
if no university was specified
"""
if not settings.FEATURES['SUBDOMAIN_BRANDING'] or domain is None:
return None
return MicrositeConfiguration.get_microsite_configuration_value('university')
subdomain = pick_subdomain(domain, settings.SUBDOMAIN_BRANDING.keys())
return settings.SUBDOMAIN_BRANDING.get(subdomain)
def get_logo_url(domain=None):
def get_logo_url():
"""
Return the url for the branded logo image to be used
"""
university = get_university(domain)
# if the MicrositeConfiguration has a value for the logo_image_url
# let's use that
image_url = MicrositeConfiguration.get_microsite_configuration_value('logo_image_url')
if image_url:
return '{static_url}{image_url}'.format(
static_url=settings.STATIC_URL,
image_url=image_url
)
# otherwise, use the legacy means to configure this
university = MicrositeConfiguration.get_microsite_configuration_value('university')
if university is None:
return '{static_url}images/header-logo.png'.format(
......
......@@ -6,8 +6,9 @@ from django_future.csrf import ensure_csrf_cookie
from edxmako.shortcuts import render_to_response
import student.views
import branding
import courseware.views
from microsite_configuration.middleware import MicrositeConfiguration
from edxmako.shortcuts import marketing_link
from util.cache import cache_if_anonymous
......@@ -25,10 +26,19 @@ def index(request):
if settings.FEATURES.get('AUTH_USE_MIT_CERTIFICATES'):
from external_auth.views import ssl_login
return ssl_login(request)
if settings.FEATURES.get('ENABLE_MKTG_SITE'):
enable_mktg_site = MicrositeConfiguration.get_microsite_configuration_value(
'ENABLE_MKTG_SITE',
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
)
if enable_mktg_site:
return redirect(settings.MKTG_URLS.get('ROOT'))
university = branding.get_university(request.META.get('HTTP_HOST'))
university = MicrositeConfiguration.match_university(request.META.get('HTTP_HOST'))
# keep specialized logic for Edge until we can migrate over Edge to fully use
# microsite definitions
if university == 'edge':
context = {
'suppress_toplevel_navigation': True
......@@ -49,7 +59,9 @@ def courses(request):
to that. Otherwise, if subdomain branding is on, this is the university
profile page. Otherwise, it's the edX courseware.views.courses page
"""
if settings.FEATURES.get('ENABLE_MKTG_SITE', False):
enable_mktg_site = settings.FEATURES.get('ENABLE_MKTG_SITE') or MicrositeConfiguration.get_microsite_configuration_value('ENABLE_MKTG_SITE', False)
if enable_mktg_site:
return redirect(marketing_link('COURSES'), permanent=True)
if not settings.FEATURES.get('COURSES_ARE_BROWSABLE'):
......
......@@ -294,7 +294,7 @@ def get_courses(user, domain=None):
'''
Returns a list of courses available, sorted by course.number
'''
courses = branding.get_visible_courses(domain)
courses = branding.get_visible_courses()
courses = [c for c in courses if has_access(user, c, 'see_exists')]
courses = sorted(courses, key=lambda course: course.number)
......
"""
Tests related to the Microsites feature
"""
from django.core.urlresolvers import reverse
from django.test.utils import override_settings
from unittest import skip
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from helpers import LoginEnrollmentTestCase
from courseware.tests.modulestore_config import TEST_DATA_MIXED_MODULESTORE
MICROSITE_TEST_HOSTNAME = 'testmicrosite.testserver'
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
class TestMicrosites(ModuleStoreTestCase, LoginEnrollmentTestCase):
"""
This is testing of the Microsite feature
"""
STUDENT_INFO = [('view@test.com', 'foo'), ('view2@test.com', 'foo')]
def setUp(self):
# use a different hostname to test Microsites since they are
# triggered on subdomain mappings
#
# NOTE: The Microsite Configuration is in lms/envs/test.py. The content for the Test Microsite is in
# test_microsites/test_microsite.
#
# IMPORTANT: For these tests to work, this domain must be defined via
# DNS configuration (either local or published)
self.course = CourseFactory.create(display_name='Robot_Super_Course', org='TestMicrositeX')
self.chapter0 = ItemFactory.create(parent_location=self.course.location,
display_name='Overview')
self.chapter9 = ItemFactory.create(parent_location=self.course.location,
display_name='factory_chapter')
self.section0 = ItemFactory.create(parent_location=self.chapter0.location,
display_name='Welcome')
self.section9 = ItemFactory.create(parent_location=self.chapter9.location,
display_name='factory_section')
self.course_outside_microsite = CourseFactory.create(display_name='Robot_Course_Outside_Microsite', org='FooX')
def create_test_accounts(self):
"""
Build out the test accounts we'll use in these tests
"""
# Create student accounts and activate them.
for i in range(len(self.STUDENT_INFO)):
email, password = self.STUDENT_INFO[i]
username = 'u{0}'.format(i)
self.create_account(username, email, password)
self.activate_user(email)
@skip # skipping - runs fine on localdev, not jenkins environment
def test_microsite_anonymous_homepage_content(self):
"""
Verify that the homepage, when accessed via a Microsite domain, returns
HTML that reflects the Microsite branding elements
"""
resp = self.client.get('/', HTTP_HOST=MICROSITE_TEST_HOSTNAME)
self.assertEqual(resp.status_code, 200)
# assert various branding definitions on this Microsite
# as per the configuration and Microsite overrides
self.assertContains(resp, 'This is a Test Microsite Overlay') # Overlay test message
self.assertContains(resp, 'test_microsite/images/header-logo.png') # logo swap
self.assertContains(resp, 'test_microsite/css/test_microsite.css') # css override
self.assertContains(resp, '<title>Test Microsite</title>') # page title
# assert that test course display name is visible
self.assertContains(resp, 'Robot_Super_Course')
# assert that test course that is outside microsite is not visible
self.assertNotContains(resp, 'Robot_Course_Outside_Microsite')
# assert that footer template has been properly overriden on homepage
self.assertContains(resp, 'This is a Test Microsite footer')
# assert that the edX partners section is not in the HTML
self.assertNotContains(resp, '<section class="university-partners university-partners2x6">')
# assert that the edX partners tag line is not in the HTML
self.assertNotContains(resp, 'Explore free courses from')
@skip # skipping - runs fine on localdev, not jenkins environment
def test_not_microsite_anonymous_homepage_content(self):
"""
Make sure we see the right content on the homepage if we are not in a microsite
"""
resp = self.client.get('/')
self.assertEqual(resp.status_code, 200)
# assert various branding definitions on this Microsite ARE NOT VISIBLE
self.assertNotContains(resp, 'This is a Test Microsite Overlay') # Overlay test message
self.assertNotContains(resp, 'test_microsite/images/header-logo.png') # logo swap
self.assertNotContains(resp, 'test_microsite/css/test_microsite.css') # css override
self.assertNotContains(resp, '<title>Test Microsite</title>') # page title
# assert that test course display name IS NOT VISIBLE, since that is a Microsite only course
self.assertNotContains(resp, 'Robot_Super_Course')
# assert that test course that is outside microsite IS VISIBLE
self.assertContains(resp, 'Robot_Course_Outside_Microsite')
# assert that footer template has been properly overriden on homepage
self.assertNotContains(resp, 'This is a Test Microsite footer')
# assert that the edX partners section is not in the HTML
self.assertContains(resp, '<section class="university-partners university-partners2x6">')
# assert that the edX partners tag line is not in the HTML
self.assertContains(resp, 'Explore free courses from')
@skip # skipping - runs fine on localdev, not jenkins environment
def test_microsite_course_enrollment(self):
"""
Enroll user in a course scoped in a Microsite and one course outside of a Microsite
and make sure that they are only visible in the right Dashboards
"""
self.create_test_accounts()
email, password = self.STUDENT_INFO[0]
self.login(email, password)
self.enroll(self.course, True)
self.enroll(self.course_outside_microsite, True)
# Access the microsite dashboard and make sure the right courses appear
resp = self.client.get(reverse('dashboard'), HTTP_HOST=MICROSITE_TEST_HOSTNAME)
self.assertContains(resp, 'Robot_Super_Course')
self.assertNotContains(resp, 'Robot_Course_Outside_Microsite')
# Now access the non-microsite dashboard and make sure the right courses appear
resp = self.client.get(reverse('dashboard'))
self.assertNotContains(resp, 'Robot_Super_Course')
self.assertContains(resp, 'Robot_Course_Outside_Microsite')
......@@ -14,6 +14,8 @@ from student.models import CourseEnrollment, CourseEnrollmentAllowed
from courseware.models import StudentModule
from edxmako.shortcuts import render_to_string
from microsite_configuration.middleware import MicrositeConfiguration
# For determining if a shibboleth course
SHIBBOLETH_DOMAIN_PREFIX = 'shib:'
......@@ -223,22 +225,58 @@ def send_mail_to_student(student, param_dict):
Returns a boolean indicating whether the email was sent successfully.
"""
email_template_dict = {'allowed_enroll': ('emails/enroll_email_allowedsubject.txt', 'emails/enroll_email_allowedmessage.txt'),
'enrolled_enroll': ('emails/enroll_email_enrolledsubject.txt', 'emails/enroll_email_enrolledmessage.txt'),
'allowed_unenroll': ('emails/unenroll_email_subject.txt', 'emails/unenroll_email_allowedmessage.txt'),
'enrolled_unenroll': ('emails/unenroll_email_subject.txt', 'emails/unenroll_email_enrolledmessage.txt')}
# add some helpers and microconfig subsitutions
if 'course' in param_dict:
param_dict['course_name'] = param_dict['course'].display_name_with_default
param_dict['site_name'] = MicrositeConfiguration.get_microsite_configuration_value(
'SITE_NAME',
param_dict['site_name']
)
subject = None
message = None
# see if we are running in a microsite and that there is an
# activation email template definition available as configuration, if so, then render that
message_type = param_dict['message']
email_template_dict = {
'allowed_enroll': (
'emails/enroll_email_allowedsubject.txt',
'emails/enroll_email_allowedmessage.txt'
),
'enrolled_enroll': (
'emails/enroll_email_enrolledsubject.txt',
'emails/enroll_email_enrolledmessage.txt'
),
'allowed_unenroll': (
'emails/unenroll_email_subject.txt',
'emails/unenroll_email_allowedmessage.txt'
),
'enrolled_unenroll': (
'emails/unenroll_email_subject.txt',
'emails/unenroll_email_enrolledmessage.txt'
)
}
subject_template, message_template = email_template_dict.get(param_dict['message'], (None, None))
subject_template, message_template = email_template_dict.get(message_type, (None, None))
if subject_template is not None and message_template is not None:
subject = render_to_string(subject_template, param_dict)
message = render_to_string(message_template, param_dict)
if subject and message:
# Remove leading and trailing whitespace from body
message = message.strip()
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [student], fail_silently=False)
from_address = MicrositeConfiguration.get_microsite_configuration_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
send_mail(subject, message, from_address, [student], fail_silently=False)
def uses_shib(course):
......
......@@ -19,7 +19,7 @@ class Command(BaseCommand):
Command to manually re-post open ended submissions to the grader.
"""
help = ("Usage: openended_post <course_id> <problem_location> <student_ids.txt> --dry-run --task-number=<task_number>\n"
help = ("Usage: openended_post <course_id> <problem_location> <student_ids.txt> <hostname> --dry-run --task-number=<task_number>\n"
"The text file should contain a User.id in each line.")
option_list = BaseCommand.option_list + (
......@@ -36,10 +36,11 @@ class Command(BaseCommand):
dry_run = options['dry_run']
task_number = options['task_number']
if len(args) == 3:
if len(args) == 4:
course_id = args[0]
location = args[1]
students_ids = [line.strip() for line in open(args[2])]
hostname = args[3]
else:
print self.help
return
......@@ -62,15 +63,20 @@ class Command(BaseCommand):
print "Number of students: {0}".format(students.count())
for student in students:
post_submission_for_student(student, course, location, task_number, dry_run=dry_run)
post_submission_for_student(student, course, location, task_number, dry_run=dry_run, hostname=hostname)
def post_submission_for_student(student, course, location, task_number, dry_run=True):
def post_submission_for_student(student, course, location, task_number, dry_run=True, hostname=None):
"""If the student's task child_state is ASSESSING post submission to grader."""
print "{0}:{1}".format(student.id, student.username)
request = DummyRequest()
request.user = student
request.host = hostname
try:
module = get_module_for_student(student, course, location)
module = get_module_for_student(student, course, location, request=request)
if module is None:
print " WARNING: No state found."
return False
......@@ -104,3 +110,22 @@ def post_submission_for_student(student, course, location, task_number, dry_run=
print err
return False
class DummyRequest(object):
"""Dummy request"""
META = {}
def __init__(self):
self.session = {}
self.user = None
self.host = None
self.secure = True
def get_host(self):
"""Return a default host."""
return self.host
def is_secure(self):
"""Always secure."""
return self.secure
......@@ -27,10 +27,11 @@ class DummyRequest(object):
return False
def get_module_for_student(student, course, location):
def get_module_for_student(student, course, location, request=None):
"""Return the module for the (student, location) using a DummyRequest."""
request = DummyRequest()
request.user = student
if request is None:
request = DummyRequest()
request.user = student
descriptor = modulestore().get_instance(course.id, location, depth=0)
field_data_cache = FieldDataCache([descriptor], course.id, student)
......
......@@ -63,6 +63,8 @@ from xblock.fields import ScopeIds
from django.utils.translation import ugettext as _u
from lms.lib.xblock.runtime import handler_prefix
from microsite_configuration.middleware import MicrositeConfiguration
log = logging.getLogger(__name__)
# internal commands for managing forum roles:
......@@ -1282,7 +1284,10 @@ def _do_enroll_students(course, course_id, students, overload=False, auto_enroll
ceaset.delete()
if email_students:
stripped_site_name = settings.SITE_NAME
stripped_site_name = MicrositeConfiguration.get_microsite_configuration_value(
'SITE_NAME',
settings.SITE_NAME
)
registration_url = 'https://' + stripped_site_name + reverse('student.views.register_user')
#Composition of email
d = {'site_name': stripped_site_name,
......@@ -1291,7 +1296,7 @@ def _do_enroll_students(course, course_id, students, overload=False, auto_enroll
'auto_enroll': auto_enroll,
'course_url': 'https://' + stripped_site_name + '/courses/' + course_id,
'course_about_url': 'https://' + stripped_site_name + '/courses/' + course_id + '/about',
'is_shib_course': is_shib_course,
'is_shib_course': is_shib_course
}
for student in new_students:
......@@ -1373,7 +1378,10 @@ def _do_unenroll_students(course_id, students, email_students=False):
old_students, _ = get_and_clean_student_list(students)
status = dict([x, 'unprocessed'] for x in old_students)
stripped_site_name = settings.SITE_NAME
stripped_site_name = MicrositeConfiguration.get_microsite_configuration_value(
'SITE_NAME',
settings.SITE_NAME
)
if email_students:
course = course_from_id(course_id)
#Composition of email
......@@ -1447,22 +1455,43 @@ def send_mail_to_student(student, param_dict):
Returns a boolean indicating whether the email was sent successfully.
"""
EMAIL_TEMPLATE_DICT = {'allowed_enroll': ('emails/enroll_email_allowedsubject.txt', 'emails/enroll_email_allowedmessage.txt'),
'enrolled_enroll': ('emails/enroll_email_enrolledsubject.txt', 'emails/enroll_email_enrolledmessage.txt'),
'allowed_unenroll': ('emails/unenroll_email_subject.txt', 'emails/unenroll_email_allowedmessage.txt'),
'enrolled_unenroll': ('emails/unenroll_email_subject.txt', 'emails/unenroll_email_enrolledmessage.txt')}
# add some helpers and microconfig subsitutions
if 'course' in param_dict:
param_dict['course_name'] = param_dict['course'].display_name_with_default
param_dict['site_name'] = MicrositeConfiguration.get_microsite_configuration_value(
'SITE_NAME',
param_dict.get('site_name', '')
)
subject = None
message = None
message_type = param_dict['message']
subject_template, message_template = EMAIL_TEMPLATE_DICT.get(param_dict['message'], (None, None))
email_template_dict = {
'allowed_enroll': ('emails/enroll_email_allowedsubject.txt', 'emails/enroll_email_allowedmessage.txt'),
'enrolled_enroll': ('emails/enroll_email_enrolledsubject.txt', 'emails/enroll_email_enrolledmessage.txt'),
'allowed_unenroll': ('emails/unenroll_email_subject.txt', 'emails/unenroll_email_allowedmessage.txt'),
'enrolled_unenroll': ('emails/unenroll_email_subject.txt', 'emails/unenroll_email_enrolledmessage.txt'),
}
subject_template, message_template = email_template_dict.get(message_type, (None, None))
if subject_template is not None and message_template is not None:
subject = render_to_string(subject_template, param_dict)
message = render_to_string(message_template, param_dict)
if subject and message:
# Remove leading and trailing whitespace from body
message = message.strip()
# Email subject *must not* contain newlines
subject = ''.join(subject.splitlines())
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [student], fail_silently=False)
from_address = MicrositeConfiguration.get_microsite_configuration_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
send_mail(subject, message, from_address, [student], fail_silently=False)
return True
else:
......
......@@ -36,6 +36,8 @@ from verify_student.models import SoftwareSecurePhotoVerification
from .exceptions import (InvalidCartItem, PurchasedCallbackException, ItemAlreadyInCartException,
AlreadyEnrolledInCourseException, CourseDoesNotExistException, ReportException)
from microsite_configuration.middleware import MicrositeConfiguration
log = logging.getLogger("shoppingcart")
ORDER_STATUSES = (
......@@ -165,14 +167,22 @@ class Order(models.Model):
# send confirmation e-mail
subject = _("Order Payment Confirmation")
message = render_to_string('emails/order_confirmation_email.txt', {
'order': self,
'order_items': orderitems,
'has_billing_info': settings.FEATURES['STORE_BILLING_INFO']
})
message = render_to_string(
'emails/order_confirmation_email.txt',
{
'order': self,
'order_items': orderitems,
'has_billing_info': settings.FEATURES['STORE_BILLING_INFO']
}
)
try:
from_address = MicrositeConfiguration.get_microsite_configuration_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
send_mail(subject, message,
settings.DEFAULT_FROM_EMAIL, [self.user.email]) # pylint: disable=E1101
from_address, [self.user.email]) # pylint: disable=E1101
except (smtplib.SMTPException, BotoServerError): # sadly need to handle diff. mail backends individually
log.error('Failed sending confirmation e-mail for order %d', self.id) # pylint: disable=E1101
......@@ -468,7 +478,10 @@ class CertificateItem(OrderItem):
user_email=course_enrollment.user.email,
order_number=order_number)
to_email = [settings.PAYMENT_SUPPORT_EMAIL]
from_email = [settings.PAYMENT_SUPPORT_EMAIL]
from_email = [MicrositeConfiguration.get_microsite_configuration_value(
'payment_support_email',
settings.PAYMENT_SUPPORT_EMAIL
)]
try:
send_mail(subject, message, from_email, to_email, fail_silently=False)
except (smtplib.SMTPException, BotoServerError):
......
......@@ -338,3 +338,13 @@ VERIFY_STUDENT = AUTH_TOKENS.get("VERIFY_STUDENT", VERIFY_STUDENT)
GRADES_DOWNLOAD_ROUTING_KEY = HIGH_MEM_QUEUE
GRADES_DOWNLOAD = ENV_TOKENS.get("GRADES_DOWNLOAD", GRADES_DOWNLOAD)
MICROSITE_CONFIGURATION = ENV_TOKENS.get('MICROSITE_CONFIGURATION', {})
MICROSITE_ROOT_DIR = ENV_TOKENS.get('MICROSITE_ROOT_DIR')
if MICROSITE_CONFIGURATION:
enable_microsites(
MICROSITE_CONFIGURATION,
SUBDOMAIN_BRANDING,
VIRTUAL_UNIVERSITIES,
microsites_root=path(MICROSITE_ROOT_DIR)
)
"""
This is a localdev test for the Microsite processing pipeline
"""
# We intentionally define lots of variables that aren't used, and
# want to import all variables from base settings files
# pylint: disable=W0401, W0614
from .dev import *
from .dev import SUBDOMAIN_BRANDING, VIRTUAL_UNIVERSITIES
MICROSITE_CONFIGURATION = {
"openedx": {
"domain_prefix": "openedx",
"university": "openedx",
"platform_name": "Open edX",
"logo_image_url": "openedx/images/header-logo.png",
"email_from_address": "openedx@edx.org",
"payment_support_email": "openedx@edx.org",
"ENABLE_MKTG_SITE": False,
"SITE_NAME": "openedx.localhost",
"course_org_filter": "CDX",
"course_about_show_social_links": False,
"css_overrides_file": "openedx/css/openedx.css",
"show_partners": False,
"show_homepage_promo_video": False,
"course_index_overlay_text": "Explore free courses from leading universities.",
"course_index_overlay_logo_file": "openedx/images/header-logo.png",
"homepage_overlay_html": "<h1>Take an Open edX Course</h1>"
},
}
if len(MICROSITE_CONFIGURATION.keys()) > 0:
enable_microsites(
MICROSITE_CONFIGURATION,
SUBDOMAIN_BRANDING,
VIRTUAL_UNIVERSITIES
)
......@@ -25,6 +25,7 @@ Longer TODO:
import sys
import os
import json
from path import path
......@@ -382,7 +383,7 @@ TRACKING_ENABLED = True
######################## subdomain specific settings ###########################
COURSE_LISTINGS = {}
SUBDOMAIN_BRANDING = {}
VIRTUAL_UNIVERSITIES = []
############################### XModule Store ##################################
MODULESTORE = {
......@@ -620,6 +621,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = (
'request_cache.middleware.RequestCache',
'microsite_configuration.middleware.MicrositeConfiguration',
'django_comment_client.middleware.AjaxExceptionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
......@@ -1051,6 +1053,64 @@ MKTG_URL_LINK_MAP = {
}
############################### MICROSITES ################################
def enable_microsites(microsite_config_dict, subdomain_branding, virtual_universities, microsites_root=ENV_ROOT / "microsites"):
"""
Enable the use of microsites, which are websites that allow
for subdomains for the edX platform, e.g. foo.edx.org
"""
if not microsite_config_dict:
return
FEATURES['USE_MICROSITES'] = True
for microsite_name in microsite_config_dict.keys():
# Calculate the location of the microsite's files
microsite_root = microsites_root / microsite_name
microsite_config = microsite_config_dict[microsite_name]
# pull in configuration information from each
# microsite root
if os.path.isdir(microsite_root):
# store the path on disk for later use
microsite_config['microsite_root'] = microsite_root
# get the domain that this should reside
domain = microsite_config['domain_prefix']
# get the virtual university that this should use
university = microsite_config['university']
# add to the existing maps in our settings
subdomain_branding[domain] = university
virtual_universities.append(university)
template_dir = microsite_root / 'templates'
microsite_config['template_dir'] = template_dir
microsite_config['microsite_name'] = microsite_name
else:
# not sure if we have application logging at this stage of
# startup
print '**** Error loading microsite {0}. Directory does not exist'.format(microsite_root)
# remove from our configuration as it is not valid
del microsite_config_dict[microsite_name]
# if we have microsites, then let's turn on SUBDOMAIN_BRANDING
# Note check size of the dict because some microsites might not be found on disk and
# we could be left with none
if microsite_config_dict:
FEATURES['SUBDOMAIN_BRANDING'] = True
TEMPLATE_DIRS.append(microsites_root)
MAKO_TEMPLATES['main'].append(microsites_root)
STATICFILES_DIRS.append(microsites_root)
################# Student Verification #################
VERIFY_STUDENT = {
"DAYS_GOOD_FOR": 365, # How many days is a verficiation good for?
......
......@@ -131,6 +131,8 @@ SUBDOMAIN_BRANDING = {
'mit': 'MITx',
'berkeley': 'BerkeleyX',
'harvard': 'HarvardX',
'openedx': 'openedx',
'edge': 'edge',
}
# List of `university` landing pages to display, even though they may not
......
......@@ -277,3 +277,33 @@ PASSWORD_HASHERS = (
import openid.oidutil
openid.oidutil.log = lambda message, level = 0: None
# set up some testing for microsites
MICROSITE_CONFIGURATION = {
"test_microsite": {
"domain_prefix": "testmicrosite",
"university": "test_microsite",
"platform_name": "Test Microsite",
"logo_image_url": "test_microsite/images/header-logo.png",
"email_from_address": "test_microsite@edx.org",
"payment_support_email": "test_microsite@edx.org",
"ENABLE_MKTG_SITE": False,
"SITE_NAME": "test_microsite.localhost",
"course_org_filter": "TestMicrositeX",
"course_about_show_social_links": False,
"css_overrides_file": "test_microsite/css/test_microsite.css",
"show_partners": False,
"show_homepage_promo_video": False,
"course_index_overlay_text": "This is a Test Microsite Overlay Text.",
"course_index_overlay_logo_file": "test_microsite/images/header-logo.png",
"homepage_overlay_html": "<h1>This is a Test Microsite Overlay HTML</h1>"
}
}
if len(MICROSITE_CONFIGURATION.keys()) > 0:
enable_microsites(
MICROSITE_CONFIGURATION,
SUBDOMAIN_BRANDING,
VIRTUAL_UNIVERSITIES,
microsites_root=ENV_ROOT / 'edx-platform' / 'test_microsites'
)
......@@ -12,15 +12,20 @@
cart_link = ""
%>
<%namespace name='static' file='../static_content.html'/>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%inherit file="../main.html" />
<%block name="headextra">
% if self.theme_enabled():
<%include file="../theme-google-analytics.html" />
% else:
<%include file="../google_analytics.html" />
% endif
<%
if self.theme_enabled():
google_analytics_file = u'../' + MicrositeConfiguration.get_microsite_configuration_value('google_analytics_file', 'theme-google-analytics.html')
else:
google_analytics_file = '../google_analytics.html'
%>
<%include file="${google_analytics_file}" />
</%block>
<%block name="js_extra">
......@@ -203,6 +208,7 @@
<section class="course-sidebar">
<section class="course-summary">
<header>
% if MicrositeConfiguration.get_microsite_configuration_value('course_about_show_social_links', True):
<div class="social-sharing">
<div class="sharing-message">${_("Share with friends and family!")}</div>
## TODO: this should probably be an overrideable block,
......@@ -216,17 +222,28 @@
<img src="${static.url('images/social/email-sharing.png')}" alt="Email someone to say you've registered for this course">
</a>
% else:
<a href="http://twitter.com/intent/tweet?text=I+just+registered+for+${course.number}+${get_course_about_section(course, 'title')}+through+@edxonline:+http://www.edx.org${reverse('about_course', args=[course.id])}" class="share">
<%
site_domain = MicrositeConfiguration.get_microsite_configuration_value('site_domain', 'www.edx.org')
platform_name = MicrositeConfiguration.get_microsite_configuration_value('platform_name', 'edX')
tweet_action = "http://twitter.com/intent/tweet?text=I+just+registered+for+"+course.number+"+"+get_course_about_section(course, 'title')+"+through+"+MicrositeConfiguration.get_microsite_configuration_value('course_about_twitter_account', '@edxonline')+":+http://"+site_domain+reverse('about_course', args=[course.id])
facebook_link = MicrositeConfiguration.get_microsite_configuration_value('course_about_facebook_link', 'http://www.facebook.com/EdxOnline')
email_subject = "mailto:?subject=Take%20a%20course%20with%20"+platform_name+"%20online&body=I%20just%20registered%20for%20"+course.number+"%20"+get_course_about_section(course, 'title')+"%20through%20"+platform_name+"%20http://"+site_domain+reverse('about_course', args=[course.id])
%>
<a href="${tweet_action}" class="share">
<img src="${static.url('images/social/twitter-sharing.png')}" alt="Tweet that you've registered for this course">
</a>
<a href="http://www.facebook.com/EdxOnline" class="share">
<a href="${facebook_link}" class="share">
<img src="${static.url('images/social/facebook-sharing.png')}" alt="Post a Facebook message to say you've registered for this course">
</a>
<a href="mailto:?subject=Take%20a%20course%20with%20edX%20online&body=I%20just%20registered%20for%20${course.number}%20${get_course_about_section(course, 'title')}%20through%20edX:+http://edx.org/${reverse('about_course', args=[course.id])}" class="share">
<a href="${email_subject}" class="share">
<img src="${static.url('images/social/email-sharing.png')}" alt="Email someone to say you've registered for this course">
</a>
% endif
</div>
% endif
</header>
<ol class="important-dates">
......
......@@ -4,8 +4,20 @@
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>${_("Courses")}</title></%block>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<section class="find-courses">
<%
course_index_overlay_text = MicrositeConfiguration.get_microsite_configuration_value('course_index_overlay_text', _("Explore free courses from leading universities."))
# not sure why this is, but if I use static.url('images/edx_bw.png') then the HTML rendering
# of this template goes wonky
logo_file = MicrositeConfiguration.get_microsite_configuration_value(
'course_index_overlay_logo_file', settings.STATIC_URL + 'images/edx_bw.png')
%>
<header class="search">
<div class="inner-wrapper main-search">
<hgroup>
......@@ -13,13 +25,13 @@
% if self.stanford_theme_enabled():
<img src="${static.url('themes/stanford/images/seal.png')}" alt="Stanford Seal Logo" />
% else:
<img src="${static.url('images/edx_bw.png')}" alt="Black and White edX Logo" />
<img src='${logo_file}' alt="${MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME)} Logo" />
% endif
</div>
% if self.stanford_theme_enabled():
<h2>${_("Explore free courses from {university_name}.").format(university_name="Stanford University")}</h2>
% else:
<h2>${_("Explore free courses from leading universities.")}</h2>
<h2>${course_index_overlay_text}</h2>
% endif
</hgroup>
</div>
......
<%! from django.utils.translation import ugettext as _ %>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%! from django.core.urlresolvers import reverse %>
<section id="forgot-password-modal" class="modal" role="dialog" aria-label="${_('Password Reset')}">
......@@ -22,7 +23,7 @@
<li class="field required text" id="forgot-password-modal-field-email">
<label for="pwd_reset_email">${_("Your E-mail Address")}</label>
<input class="" id="pwd_reset_email" type="email" name="email" value="" placeholder="example: username@domain.com" aria-describedby="pwd_reset_email-tip" aria-required="true" />
<span class="tip tip-input" id="pwd_reset_email-tip">${_("This is the e-mail address you used to register with {platform}").format(platform=settings.PLATFORM_NAME)}</span>
<span class="tip tip-input" id="pwd_reset_email-tip">${_("This is the e-mail address you used to register with {platform}").format(platform=MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME))}</span>
</li>
</ol>
</fieldset>
......
......@@ -5,6 +5,7 @@
<%! import pytz %>
<%! from django.conf import settings %>
<%! from courseware.tabs import get_discussion_link %>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
% if settings.FEATURES.get('ENABLE_FEEDBACK_SUBMISSION', False):
......@@ -12,13 +13,13 @@
<a href="#help-modal" rel="leanModal" role="button">${_("Help")}</a>
</div>
<section id="help-modal" class="modal" aria-hidden="true" role="dialog" aria-label="${_("{platform_name} Help").format(platform_name=settings.PLATFORM_NAME)}">
<section id="help-modal" class="modal" aria-hidden="true" role="dialog" aria-label="${_("{platform_name} Help").format(platform_name=MicrositeConfiguration.get_microsite_configuration_value("platform_name", settings.PLATFORM_NAME))}">
<div class="inner-wrapper" id="help_wrapper">
## TODO: find a way to refactor this
<button class="close-modal "tabindex="0">&#10005; <span class="sr">${_('Close Modal')}</span></button>
<header>
<h2>${_('{span_start}{platform_name}{span_end} Help').format(span_start='<span class="edx">', span_end='</span>', platform_name=settings.PLATFORM_NAME)}</h2>
<h2>${_('{span_start}{platform_name}{span_end} Help').format(span_start='<span class="edx">', span_end='</span>', platform_name=MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME))}</h2>
<hr>
</header>
......@@ -39,10 +40,10 @@ discussion_link = get_discussion_link(course) if course else None
url=marketing_link('FAQ')
),
link_end='</a>',
platform_name=settings.PLATFORM_NAME)}
platform_name=MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME))}
</p>
<p>${_('Have a <strong>question about something specific</strong>? You can contact the {platform_name} general support team directly:').format(platform_name=settings.PLATFORM_NAME)}</p>
<p>${_('Have a <strong>question about something specific</strong>? You can contact the {platform_name} general support team directly:').format(platform_name=MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME))}</p>
<hr>
<div class="help-buttons">
......
......@@ -5,17 +5,33 @@
<%inherit file="main.html" />
<%namespace name='static' file='static_content.html'/>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%
homepage_overlay_html = MicrositeConfiguration.get_microsite_configuration_value('homepage_overlay_html')
show_homepage_promo_video = MicrositeConfiguration.get_microsite_configuration_value('show_homepage_promo_video', True)
homepage_promo_video_youtube_id = MicrositeConfiguration.get_microsite_configuration_value('homepage_promo_video_youtube_id', "XNaiOGxWeto")
show_partners = MicrositeConfiguration.get_microsite_configuration_value('show_partners', True)
%>
<section class="home">
<header>
<div class="outer-wrapper">
<div class="title">
<hgroup>
% if self.stanford_theme_enabled():
<h1>${_("Free courses from <strong>{university_name}</strong>").format(university_name="Stanford")}</h1>
% if homepage_overlay_html:
${homepage_overlay_html}
% else:
<h1>${_("The Future of Online Education")}</h1>
% if self.stanford_theme_enabled():
<h1>${_("Free courses from <strong>{university_name}</strong>").format(university_name="Stanford")}</h1>
% else:
<h1>${_("The Future of Online Education")}</h1>
% endif
<h2>${_("For anyone, anywhere, anytime")}</h2>
% endif
<h2>${_("For anyone, anywhere, anytime")}</h2>
</hgroup>
## Disable social buttons for non-edX sites
......@@ -40,21 +56,130 @@
</div>
</div>
</section>
% endif
% endif
</div>
% if show_homepage_promo_video:
<a href="#video-modal" class="media" rel="leanModal">
<div class="hero">
<div class="play-intro"></div>
</div>
</a>
% endif
</div>
</header>
<section class="container">
<section class="container">
<section class="highlighted-courses">
## NOTE: To put a title here surround in <h2> tags
## Disable university partner logos and sites for non-edX sites
% if not self.theme_enabled() and show_partners:
<h2>${_('Explore free courses from {span_start}{platform_name}{span_end} universities').format(platform_name="edX", span_start='<span class="edx">', span_end='</span>')}</h2>
<section class="university-partners university-partners2x6">
<ol class="partners">
<li class="partner mit">
<a href="#">
<img src="${static.url('images/university/mit/mit.png')}" />
<div class="name">
<span>MITx</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/harvard/harvard.png')}" />
<div class="name">
<span>HarvardX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/berkeley/berkeley.png')}" />
<div class="name">
<span>BerkeleyX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/ut/ut-rollover_350x150.png')}" />
<div class="name">
<span>UTx</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/mcgill/mcgill.png')}" />
<div class="name">
<span>McGillX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/anu/anu.png')}" />
<div class="name">
<span>ANUx</span>
</div>
</a>
</li>
</ol>
<hr />
<ol class="partners">
<li class="partner">
<a href="#">
<img src="${static.url('images/university/wellesley/wellesley-rollover_350x150.png')}" />
<div class="name">
<span>WellesleyX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/georgetown/georgetown-rollover_350x150.png')}" />
<div class="name">
<span>GeorgetownX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/toronto/toronto.png')}" />
<div class="name">
<span>University of TorontoX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/epfl/epfl.png')}" />
<div class="name">
<span>EPFLx</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/delft/delft.png')}" />
<div class="name">
<span>DelftX</span>
</div>
</a>
</li>
<li class="partner">
<a href="#">
<img src="${static.url('images/university/rice/rice.png')}" />
<div class="name">
<span>RiceX</span>
</div>
</a>
</li>
</ol>
</section>
% endif
% if settings.FEATURES.get('COURSES_ARE_BROWSABLE'):
<section class="courses">
......@@ -74,10 +199,9 @@
<section id="video-modal" class="modal home-page-video-modal video-modal">
<div class="inner-wrapper">
<%
youtube_video_id = homepage_promo_video_youtube_id
if self.stanford_theme_enabled():
youtube_video_id = "2gmreZObCY4"
else:
youtube_video_id = "XNaiOGxWeto"
%>
<iframe width="640" height="360" src="//www.youtube.com/embed/${youtube_video_id}?showinfo=0" frameborder="0" allowfullscreen></iframe>
</div>
......
<%!
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
%>
<header>
<h2 class="sr">${_("Helpful Information")}</h2>
</header>
% if settings.FEATURES.get('AUTH_USE_OPENID'):
<!-- <div class="cta cta-login-options-openid">
<h3>${_("Login via OpenID")}</h3>
<p>${_('You can now start learning with {platform_name} by logging in with your <a rel="external" href="http://openid.net/">OpenID account</a>.').format(platform_name=platform_name)}</p>
<a class="action action-login-openid" href="#">${_("Login via OpenID")}</a>
</div> -->
% endif
<div class="cta cta-help">
<h3>${_("Not Enrolled?")}</h3>
<p><a href="${reverse('register_user')}">${_("Sign up for {platform_name} today!").format(platform_name=platform_name)}</a></p>
## Disable help unless the FAQ marketing link is enabled
% if settings.MKTG_URL_LINK_MAP.get('FAQ'):
<h3>${_("Need Help?")}</h3>
<p>${_("Looking for help in logging in or with your {platform_name} account?").format(platform_name=platform_name)}
<a href="${marketing_link('FAQ')}">
${_("View our help section for answers to commonly asked questions.")}
</a></p>
% endif
</div>
\ No newline at end of file
<%inherit file="main.html" />
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%namespace name='static' file='static_content.html'/>
<%! from django.core.urlresolvers import reverse %>
<%! from django.utils.translation import ugettext as _ %>
<%block name="title"><title>${_("Log into your {platform_name} Account").format(platform_name=settings.PLATFORM_NAME)}</title></%block>
<%block name="title"><title>${_("Log into your {platform_name} Account").format(platform_name=platform_name)}</title></%block>
<%block name="js_extra">
<script type="text/javascript">
......@@ -83,7 +83,7 @@
$submitButton.
removeClass('is-disabled').
removeProp('disabled').
html("${_('Log into My {platform_name} Account').format(platform_name=settings.PLATFORM_NAME)} <span class='orn-plus'>+</span> ${_('Access My Courses')}");
html("${_('Log into My {platform_name} Account').format(platform_name=platform_name)} <span class='orn-plus'>+</span> ${_('Access My Courses')}");
}
else {
$submitButton.
......@@ -110,7 +110,7 @@
<!-- status messages -->
<div role="alert" class="status message">
<h3 class="message-title">${_("We're Sorry, {platform_name} accounts are unavailable currently").format(platform_name=settings.PLATFORM_NAME)}</h3>
<h3 class="message-title">${_("We're Sorry, {platform_name} accounts are unavailable currently").format(platform_name=platform_name)}</h3>
</div>
<div role="alert" class="status message submission-error" tabindex="-1">
......@@ -121,7 +121,7 @@
</div>
<p class="instructions sr">
${_('Please provide the following information to log into your {platform_name} account. Required fields are noted by <strong class="indicator">bold text and an asterisk (*)</strong>.').format(platform_name=settings.PLATFORM_NAME)}
${_('Please provide the following information to log into your {platform_name} account. Required fields are noted by <strong class="indicator">bold text and an asterisk (*)</strong>.').format(platform_name=platform_name)}
</p>
<div class="group group-form group-form-requiredinformation">
......@@ -131,7 +131,7 @@
<li class="field required text" id="field-email">
<label for="email">${_('E-mail')}</label>
<input class="" id="email" type="email" name="email" value="" placeholder="example: username@domain.com" required aria-required="true" aria-described-by="email-tip" />
<span class="tip tip-input" id="email-tip">${_("This is the e-mail address you used to register with {platform}").format(platform=settings.PLATFORM_NAME)}</span>
<span class="tip tip-input" id="email-tip">${_("This is the e-mail address you used to register with {platform}").format(platform=platform_name)}</span>
</li>
<li class="field required password" id="field-password">
<label for="password">${_('Password')}</label>
......@@ -166,31 +166,14 @@
</section>
<aside role="complementary">
<header>
<h2 class="sr">${_("Helpful Information")}</h2>
</header>
% if settings.FEATURES.get('AUTH_USE_OPENID'):
<!-- <div class="cta cta-login-options-openid">
<h3>${_("Login via OpenID")}</h3>
<p>${_('You can now start learning with {platform_name} by logging in with your <a rel="external" href="http://openid.net/">OpenID account</a>.').format(platform_name=settings.PLATFORM_NAME)}</p>
<a class="action action-login-openid" href="#">${_("Login via OpenID")}</a>
</div> -->
% endif
<div class="cta cta-help">
<h3>${_("Not Enrolled?")}</h3>
<p><a href="${reverse('register_user')}">${_("Sign up for {platform_name} today!").format(platform_name=settings.PLATFORM_NAME)}</a></p>
## Disable help unless the FAQ marketing link is enabled
% if settings.MKTG_URL_LINK_MAP.get('FAQ'):
<h3>${_("Need Help?")}</h3>
<p>${_("Looking for help in logging in or with your {platform_name} account?").format(platform_name=settings.PLATFORM_NAME)}
<a href="${marketing_link('FAQ')}">
${_("View our help section for answers to commonly asked questions.")}
</a></p>
% endif
</div>
<%
# allow for microsite overrides on the registration sidebars, otherwise default to pre-existing ones
sidebar_file = MicrositeConfiguration.get_microsite_template_path('login-sidebar.html')
%>
<%include file="${sidebar_file}" />
</aside>
</section>
<%! from django.utils.translation import ugettext as _ %>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%namespace name='static' file='static_content.html'/>
<%! from django.utils import html %>
......@@ -12,7 +13,12 @@
</%def>
<%def name="stanford_theme_enabled()">
<% return theme_enabled() and getattr(settings, "THEME_NAME") == "stanford" %>
<%
if not theme_enabled():
return False
return getattr(settings, "THEME_NAME", None) == "stanford"
%>
</%def>
<!DOCTYPE html>
......@@ -26,10 +32,9 @@
<title>${_("Home")} | class.stanford.edu</title>
% else:
## "edX" should not be translated
<title>edX</title>
<title>${MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME)}</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
/* immediately break out of an iframe if coming from the marketing website */
......@@ -44,7 +49,7 @@
<script type="text/javascript" src="/jsi18n/"></script>
<link rel="icon" type="image/x-icon" href="${static.url(settings.FAVICON_PATH)}" />
<link rel="icon" type="image/x-icon" href="${static.url(MicrositeConfiguration.get_microsite_configuration_value('favicon_path', settings.FAVICON_PATH))}" />
<%static:css group='style-vendor'/>
<%static:css group='style-app'/>
......@@ -54,8 +59,27 @@
<%static:js group='main_vendor'/>
<%block name="headextra"/>
% if theme_enabled():
<%include file="theme-head-extra.html" />
<%
if theme_enabled():
header_extra_file = 'theme-head-extra.html'
header_file = 'theme-header.html'
google_analytics_file = 'theme-google-analytics.html'
footer_file = 'theme-footer.html'
style_overrides_file = None
else:
header_extra_file = None
header_file = MicrositeConfiguration.get_microsite_template_path('navigation.html')
google_analytics_file = MicrositeConfiguration.get_microsite_template_path('google_analytics.html')
footer_file = MicrositeConfiguration.get_microsite_template_path('footer.html')
style_overrides_file = MicrositeConfiguration.get_microsite_configuration_value('css_overrides_file')
%>
% if header_extra_file:
<%include file="${header_extra_file}" />
% endif
<!--[if lt IE 9]>
......@@ -66,15 +90,16 @@
<meta name="google-site-verification" content="_mipQ4AtZQDNmbtOkwehQDOgCxUUV2fb_C0b6wbiRHY" />
% if not course:
% if theme_enabled():
<%include file="theme-google-analytics.html" />
% else:
<%include file="google_analytics.html" />
% endif
<%include file="${google_analytics_file}" />
% endif
<%include file="widgets/segment-io.html" />
% if style_overrides_file:
<link rel="stylesheet" type="text/css" href="${static.url(style_overrides_file)}" />
% endif
</head>
<body class="<%block name='bodyclass'/>">
......@@ -82,21 +107,17 @@
<%include file="mathjax_accessible.html" />
% if theme_enabled():
<%include file="theme-header.html" />
% elif not suppress_toplevel_navigation:
<%include file="navigation.html" />
% endif
% if not suppress_toplevel_navigation:
<%include file="${header_file}" />
%endif
<section class="content-wrapper" id="content">
${self.body()}
<%block name="bodyextra"/>
</section>
% if theme_enabled():
<%include file="theme-footer.html" />
% elif not suppress_toplevel_navigation:
<%include file="footer.html" />
% if not suppress_toplevel_navigation:
<%include file="${footer_file}" />
% endif
<script>window.baseUrl = "${settings.STATIC_URL}";</script>
......@@ -113,3 +134,5 @@
html.escape(enrollment_action)
) if course_id and enrollment_action else ""
}</%def>
......@@ -11,6 +11,8 @@ import branding
from status.status import get_site_status_msg
%>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
## Provide a hook for themes to inject branding on top.
<%block name="navigation_top" />
......@@ -44,7 +46,7 @@ site_status_msg = get_site_status_msg(course_id)
<h1 class="logo">
<a href="${marketing_link('ROOT')}">
<%block name="navigation_logo">
<img src="${static.url(branding.get_logo_url(request.META.get('HTTP_HOST')))}" alt="${settings.PLATFORM_NAME} ${_('Home')}" />
<img src="${static.url(branding.get_logo_url())}" alt="${MicrositeConfiguration.get_microsite_configuration_value('platform_name', settings.PLATFORM_NAME)} ${_('Home')}" />
</%block>
</a>
</h1>
......
<%!
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
%>
<%namespace file='main.html' import="login_query, stanford_theme_enabled"/>
<%namespace name='static' file='static_content.html'/>
<header>
<h3 class="sr">${_("Registration Help")}</h3>
</header>
% if has_extauth_info is UNDEFINED:
<div class="cta">
<h3>${_("Already registered?")}</h3>
<p class="instructions">
<a href="${reverse('signin_user')}${login_query()}">
${_("Click here to log in.")}
</a>
</p>
</div>
% endif
## TODO: Use a %block tag or something to allow themes to
## override in a more generalizable fashion.
% if not stanford_theme_enabled():
<div class="cta cta-welcome">
<h3>${_("Welcome to {platform_name}").format(platform_name=platform_name)}</h3>
<p>${_("Registering with {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.").format(platform_name=platform_name)}</p>
</div>
% endif
<div class="cta cta-nextsteps">
<h3>${_("Next Steps")}</h3>
% if stanford_theme_enabled():
<p>${_("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.")}</p>
% else:
<p>${_("As part of joining {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 {platform_name} emails as 'not spam'. At {platform_name}, we communicate mostly through email.").format(platform_name=platform_name)}</p>
% endif
</div>
% if settings.MKTG_URL_LINK_MAP.get('FAQ'):
<div class="cta cta-help">
<h3>${_("Need Help?")}</h3>
<p>${_("Need help in registering with {platform_name}?").format(platform_name=platform_name)}
<a href="${marketing_link('FAQ')}">
${_("View our FAQs for answers to commonly asked questions.")}
</a>
${_("Once registered, most questions can be answered in the course specific discussion forums or through the FAQs.")}</p>
</div>
% endif
<%! from django.utils.translation import ugettext as _ %>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%inherit file="main.html" />
......@@ -13,7 +14,7 @@
<%! from datetime import date %>
<%! import calendar %>
<%block name="title"><title>${_("Register for {platform_name}").format(platform_name=settings.PLATFORM_NAME)}</title></%block>
<%block name="title"><title>${_("Register for {platform_name}").format(platform_name=platform_name)}</title></%block>
<%block name="js_extra">
<script type="text/javascript">
......@@ -76,7 +77,7 @@
$submitButton.
removeClass('is-disabled').
removeProp('disabled').
text("${_('Create My {platform_name} Account').format(platform_name=settings.PLATFORM_NAME)}");
html("${_('Create My {platform_name} Account').format(platform_name=platform_name)}");
}
else {
$submitButton.
......@@ -92,7 +93,7 @@
<header>
<h1 class="title">
<span class="title-super">${_("Welcome!")}</span>
<span class="title-sub">${_("Register below to create your {platform_name} account").format(platform_name=settings.PLATFORM_NAME)}</span>
<span class="title-sub">${_("Register below to create your {platform_name} account").format(platform_name=platform_name)}</span>
</h1>
</header>
</section>
......@@ -104,7 +105,7 @@
<!-- status messages -->
<div role="alert" class="status message">
<h3 class="message-title">${_("We're sorry, {platform_name} enrollment is not available in your region").format(platform_name=settings.PLATFORM_NAME)}</h3>
<h3 class="message-title">${_("We're sorry, {platform_name} enrollment is not available in your region").format(platform_name=platform_name)}</h3>
</div>
<div role="alert" class="status message submission-error" tabindex="-1">
......@@ -241,7 +242,7 @@
% if 'goals' in settings.REGISTRATION_OPTIONAL_FIELDS:
<li class="field text" id="field-goals">
<label for="goals">${_("Please share with us your reasons for registering with {platform_name}").format(platform_name=settings.PLATFORM_NAME)}</label>
<label for="goals">${_("Please share with us your reasons for registering with {platform_name}").format(platform_name=platform_name)}</label>
<textarea id="goals" name="goals" value=""></textarea>
</li>
% endif
......@@ -294,50 +295,13 @@
</section>
<aside role="complementary">
<header>
<h3 class="sr">${_("Registration Help")}</h3>
</header>
% if has_extauth_info is UNDEFINED:
<%
# allow for microsite overrides on the registration sidebars, otherwise default to pre-existing ones
sidebar_file = MicrositeConfiguration.get_microsite_template_path('register-sidebar.html')
%>
<div class="cta">
<h3>${_("Already registered?")}</h3>
<p class="instructions">
<a href="${reverse('signin_user')}${login_query()}">
${_("Click here to log in.")}
</a>
</p>
</div>
% endif
<%include file="${sidebar_file}" />
## TODO: Use a %block tag or something to allow themes to
## override in a more generalizable fashion.
% if not self.stanford_theme_enabled():
<div class="cta cta-welcome">
<h3>${_("Welcome to {platform_name}").format(platform_name=settings.PLATFORM_NAME)}</h3>
<p>${_("Registering with {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.").format(platform_name=settings.PLATFORM_NAME)}</p>
</div>
% endif
<div class="cta cta-nextsteps">
<h3>${_("Next Steps")}</h3>
% if self.stanford_theme_enabled():
<p>${_("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.")}</p>
% else:
<p>${_("As part of joining {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 {platform_name} emails as 'not spam'. At {platform_name}, we communicate mostly through email.").format(platform_name=settings.PLATFORM_NAME)}</p>
% endif
</div>
% if settings.MKTG_URL_LINK_MAP.get('FAQ'):
<div class="cta cta-help">
<h3>${_("Need Help?")}</h3>
<p>${_("Need help in registering with {platform_name}?").format(platform_name=settings.PLATFORM_NAME)}
<a href="${marketing_link('FAQ')}">
${_("View our FAQs for answers to commonly asked questions.")}
</a>
${_("Once registered, most questions can be answered in the course specific discussion forums or through the FAQs.")}</p>
</div>
% endif
</aside>
</section>
.find-courses header.search, .university-profile header.search {
background-image: url("../images/background-image.jpg");
}
.course-info header.course-profile {
background: url("../images/background-image.jpg") repeat scroll 0 0 / cover #F5F5F5;
}
.view-login .introduction header {
background-image: url("../images/login-and-register-banner.png");
}
.view-register .introduction header {
background-image: url("../images/login-and-register-banner.png");
}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("Thank you for signing up for Open edX! To activate "
"your account, please copy and paste this address into your web "
"browser's address bar:")}
% if is_secure:
https://${ site }/activate/${ key }
% else:
http://${ site }/activate/${ key }
% endif
${_("If you didn't request this, you don't need to do anything; you won't "
"receive any more email from us. Please do not reply to this e-mail; "
"if you require assistance, check the help section of the "
"Open edX web site.")}
<%! from django.utils.translation import ugettext as _ %>
${_("Your account for Open edX")}
<%! from django.core.urlresolvers import reverse %>
This is to confirm that you changed the e-mail associated with
Open edX from ${old_email} to ${new_email}. If you
did not make this request, please contact us immediately. Contact
information is listed at:
% if is_secure:
https://${ site }${reverse('contact')}
% else:
http://${ site }${reverse('contact')}
% endif
We keep a log of old e-mails, so if this request was unintentional, we
can investigate.
We received a request to change the e-mail associated with your
Open edX account from ${old_email} to ${new_email}.
If this is correct, please confirm your new e-mail address by
visiting:
% if is_secure:
https://${ site }/email_confirm/${ key }
% else:
http://${ site }/email_confirm/${ key }
% endif
If you didn't request this, you don't need to do anything; you won't
receive any more email from us. Please do not reply to this e-mail;
if you require assistance, check the help section of the
Open edX web site.
<%! from django.utils.translation import ugettext as _ %>
${_("Dear student,")}
${_("You have been invited to join {course_name} at {site_name} by a "
"member of the course staff.").format(
course_name=course.display_name_with_default,
site_name=site_name
)}
${_("To finish your registration, please visit {registration_url} and fill "
"out the registration form making sure to use {email_address} in the E-mail field.").format(
registration_url=registration_url,
email_address=email_address
)}
% if auto_enroll:
${_("Once you have registered and activated your account, you will see "
"{course_name} listed on your dashboard.").format(
course_name=course.display_name_with_default
)}
% else:
${_("Once you have registered and activated your account, visit {course_about_url} "
"to join the course.").format(course_about_url=course_about_url)}
% endif
----
${_("This email was automatically sent from {site_name} to "
"{email_address}").format(
site_name=site_name, email_address=email_address
)}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("You have been invited to register for {course_name}").format(
course_name=course.display_name_with_default
)}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("Dear {full_name}").format(full_name=full_name)}
${_("You have been enrolled in {course_name} at {site_name} by a member "
"of the course staff. The course should now appear on your {site_name} "
"dashboard.").format(
course_name=course.display_name_with_default,
site_name=site_name
)}
${_("To start accessing course materials, please visit {course_url}").format(
course_url=course_url
)}
----
${_("This email was automatically sent from {site_name} to "
"{full_name}").format(
site_name=site_name, full_name=full_name
)}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("You have been enrolled in {course_name}").format(
course_name=course.display_name_with_default
)}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("Dear Student,")}
${_("You have been un-enrolled from course {course_name} by a member "
"of the course staff. Please disregard the invitation "
"previously sent.").format(course_name=course.display_name_with_default)}
----
${_("This email was automatically sent from {site_name} "
"to {email_address}").format(
site_name=site_name, email_address=email_address
)}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("Dear {full_name}").format(full_name=full_name)}
${_("You have been un-enrolled in {course_name} at {site_name} by a member "
"of the course staff. The course will no longer appear on your "
"{site_name} dashboard.").format(
course_name=course.display_name_with_default, site_name=site_name
)}
${_("Your other courses have not been affected.")}
----
${_("This email was automatically sent from {site_name} to "
"{full_name}").format(
full_name=full_name, site_name=site_name
)}
\ No newline at end of file
<%! from django.utils.translation import ugettext as _ %>
${_("You have been un-enrolled from {course_name}").format(
course_name=course.display_name_with_default
)}
\ No newline at end of file
## mako
<%! from django.core.urlresolvers import reverse %>
<%! from django.utils.translation import ugettext as _ %>
<%! from microsite_configuration.middleware import MicrositeConfiguration %>
<%namespace name='static' file='static_content.html'/>
<div class="wrapper wrapper-footer">
<footer>
<div class="colophon">
<div class="colophon-about">
<p>This is a Test Microsite footer</p>
</div>
</div>
</footer>
</div>
<%!
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
%>
<header>
<h2 class="sr">${_("Helpful Information")}</h2>
</header>
<div class="cta cta-help">
<h3>${_("Not Enrolled?")}</h3>
<p><a href="${reverse('register_user')}">${_("Sign up for {platform_name} today!").format(platform_name=platform_name)}</a></p>
<h3>${_("Need Help?")}</h3>
<p>
Custom text
</p>
</div>
\ No newline at end of file
<%!
from django.utils.translation import ugettext as _
from django.core.urlresolvers import reverse
%>
<%namespace file='../../main.html' import="login_query"/>
<%namespace name='static' file='../../static_content.html'/>
<header>
<h3 class="sr">${_("Registration Help")}</h3>
</header>
<div class="cta">
<h3>${_("Already registered?")}</h3>
<p class="instructions">
<a href="${reverse('signin_user')}${login_query()}">
${_("Click here to log in.")}
</a>
</p>
</div>
<div class="cta cta-welcome">
<h3>${_("Welcome to {platform_name}").format(platform_name=platform_name)}</h3>
<p>${_("Registering with {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.").format(platform_name=platform_name)}</p>
</div>
<div class="cta cta-nextsteps">
<h3>${_("Next Steps")}</h3>
<p>${_("As part of joining {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 {platform_name} emails as 'not spam'. At {platform_name}, we communicate mostly through email.").format(platform_name=platform_name)}</p>
</div>
<div class="cta cta-help">
<h3>${_("Need Help?")}</h3>
<p>
This is custom area
</p>
</div>
<%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %>
<%namespace name='static' file='../../../static_content.html'/>
<%inherit file="../../../main.html" />
<%block name="title"><title>${_("About {edX}").format(edX="edX")}</title></%block>
<section class="container about">
<nav>
<a href="${reverse('about_edx')}" class="active">${_("Vision")}</a>
<a href="${reverse('faq_edx')}">${_("Faq")}</a>
<a href="${reverse('press')}">${_("Press")}</a>
<a href="${reverse('contact')}">${_("Contact")}</a>
</nav>
<section class="vision">
## <div class="our-mission">
## <div class="logo">
## <img src="${static.url('images/edx-logo-large-bw.png')}">
## </div>
## <h2 class="mission-quote">&ldquo;${_('The mission of <span class="edx">{edX}</span> is to enhance human fulfillment worldwide through online ## learning, transforming education in quality, efficiency and scale through technology and research, for the benefit of campus-based ## students and the worldwide community of online learners.').format(edX="edX")}&rdquo;</h2>
## </div>
<section class="message left">
<div class="photo">
<img src="${static.url('images/about_1.jpg')}">
</div>
<article>
<h2>${_('About {span_start}{edX}{span_end}'.format(span_start='<span class="edx">', span_end='</span>', edX="edX"))}</h2>
<p>${_("Open edX is a not-for-profit enterprise of its founding partners {harvard_university} and the {massachusetts_institute_of_technology} that features learning designed specifically for interactive study via the web. Based on a long history of collaboration and their shared educational missions, the founders are creating a new online-learning experience with online courses that reflect their disciplinary breadth. Along with offering online courses, the institutions will use {edX} to research how students learn and how technology can transform learning&ndash;both on-campus and worldwide. Anant Agarwal, former Director of {MIT}'s Computer Science and Artificial Intelligence Laboratory, serves as the first president of {edX}. {EdX}'s goals combine the desire to reach out to students of all ages, means, and nations, and to deliver these teachings from a faculty who reflect the diversity of its audience. {EdX} is based in Cambridge, Massachusetts and is governed by {MIT} and {Harvard}.").format(edX="edX", EdX="EdX", harvard_university="Harvard University", Harvard="Harvard", MIT="MIT", massachusetts_institute_of_technology="Massachusetts Institute of Technology")}</p>
</article>
<hr class="fade-right-hr-divider">
</section>
<section class="message left">
<div class="photo">
<img src="${static.url('images/university/harvard/about-harvard.jpg')}">
</div>
<article>
<h2>${_("{harvard_university}").format(harvard_university="Harvard University")}</h2>
<p>${_("{harvard_university} is devoted to excellence in teaching, learning, and research, and to developing leaders in many disciplines who make a difference globally. {Harvard} faculty are engaged with teaching and research to push the boundaries of human knowledge. The University has twelve degree-granting Schools in addition to the {radcliffe_institute_for_advanced_study}.").format(harvard_university="Harvard University", Harvard="Harvard", radcliffe_institute_for_advanced_study="Radcliffe Institute for Advanced Study")}</p>
<p>${_("Established in 1636, {Harvard} is the oldest institution of higher education in the United States. The University, which is based in Cambridge and Boston, Massachusetts, has an enrollment of over 20,000 degree candidates, including undergraduate, graduate, and professional students. {Harvard} has more than 360,000 alumni around the world.").format(Harvard="Harvard")}</p>
</article>
<hr class="fade-left-hr-divider">
</section>
<section class="message left">
<div class="photo">
<img src="${static.url('images/university/mit/about-mit.jpg')}">
</div>
<article>
<h2>${_("{massachusetts_institute_of_technology}").format(massachusetts_institute_of_technology="Massachusetts Institute of Technology")}</h2>
<p>${_("The {massachusetts_institute_of_technology} &mdash; a coeducational, privately endowed research university founded in 1861 &mdash; is dedicated to advancing knowledge and educating students in science, technology, and other areas of scholarship that will best serve the nation and the world in the 21st century. The Institute has close to 1,000 faculty and 10,000 undergraduate and graduate students. It is organized into five Schools: Architecture and Urban Planning; Engineering; Humanities, Arts, and Social Sciences; {Sloan} School of Management; and Science.").format(massachusetts_institute_of_technology="Massachusetts Institute of Technology", Sloan="Sloan")}</p>
<p>${_("{MIT}'s commitment to innovation has led to a host of scientific breakthroughs and technological advances. Achievements of the Institute's faculty and graduates have included the first chemical synthesis of penicillin and vitamin A, the development of inertial guidance systems, modern technologies for artificial limbs, and the magnetic core memory that made possible the development of digital computers. 78 alumni, faculty, researchers and staff have won Nobel Prizes.").format(MIT="MIT")}</p>
<p>${_("Current areas of research and education include neuroscience and the study of the brain and mind, bioengineering, cancer, energy, the environment and sustainable development, information sciences and technology, new media, financial technology, and entrepreneurship.")}</p>
</article>
</section>
<section class="partners">
</section>
</section>
</section>
<%! from django.utils.translation import ugettext as _ %>
<%! from django.core.urlresolvers import reverse %>
<%namespace name='static' file='../static_content.html'/>
<%inherit file="../main.html" />
<%block name="title"><title>${_("Contact {platform_name}").format(platform_name=settings.PLATFORM_NAME)}</title></%block>
<section class="container about">
<nav>
<a href="${reverse('about_edx')}">${_("Vision")}</a>
<a href="${reverse('faq_edx')}">${_("Faq")}</a>
<a href="${reverse('press')}">${_("Press")}</a>
<a href="${reverse('contact')}" class="active">${_("Contact")}</a>
</nav>
<section class="contact">
<div class="photo">
<img src="${static.url('images/contact-page.jpg')}">
</div>
<div class="contacts">
<h2>${_("Class Feedback")}</h2>
<p>${_("We are always seeking feedback to improve our courses. If you are an enrolled student and have any questions, feedback, suggestions, or any other issues specific to a particular class, please post on the discussion forums of that&nbsp;class.")}</p>
<h2>${_("General Inquiries and Feedback")}</h2>
<p>${_('If you have a general question about {platform_name} please email {email}. To see if your question has already been answered, visit our {faq_link_start}FAQ page{faq_link_end}. You can also join the discussion on our {fb_link_start}facebook page{fb_link_end}. Though we may not have a chance to respond to every email, we take all feedback into consideration.').format(
platform_name=settings.PLATFORM_NAME,
email='<a href="mailto:{contact_email}">{contact_email}</a>'.format(contact_email=settings.CONTACT_EMAIL),
faq_link_start='<a href="{url}">'.format(url=reverse('faq_edx')),
faq_link_end='</a>',
fb_link_start='<a href="http://www.facebook.com/EdxOnline">',
fb_link_end='</a>'
)}</p>
<h2>${_("Technical Inquiries and Feedback")}</h2>
<p>${_('If you have suggestions/feedback about the overall {platform_name} platform, or are facing general technical issues with the platform (e.g., issues with email addresses and passwords), you can reach us at {tech_email}. For technical questions, please make sure you are using a current version of Firefox or Chrome, and include browser and version in your e-mail, as well as screenshots or other pertinent details. If you find a bug or other issues, you can reach us at the following: {bug_email}.').format(
platform_name=settings.PLATFORM_NAME,
tech_email='<a href="mailto:{tech_support_email}">{tech_support_email}</a>'.format(tech_support_email=settings.TECH_SUPPORT_EMAIL),
bug_email='<a href="mailto:{bugs_email}">{bugs_email}</a>'.format(bugs_email=settings.BUGS_EMAIL)
)}</p>
<h2>${_("Media")}</h2>
<p>${_('Please visit our {link_start}media/press page{link_end} for more information. For any media or press inquiries, please email {email}.').format(
link_start='<a href="{url}">'.format(url=reverse('faq_edx')),
link_end='</a>',
email='<a href="mailto:{email}">{email}</a>'.format(email="press@edx.org"),
)}</p>
<h2>${_("Universities")}</h2>
<p>${_('If you are a university wishing to collaborate or you have questions about {platform_name}, please email {email}.'.format(
platform_name="edX",
email='<a href="mailto:{email}">{email}</a>'.format(
email="university@edx.org"
)
))}</p>
<h2>${_("Accessibility")}</h2>
<p>${_('{platform_name} strives to create an innovative online-learning platform that promotes accessibility for everyone, including students with disabilities. We are dedicated to improving the accessibility of the platform and welcome your comments or questions at {email}.'.format(platform_name="EdX", email='<a href="mailto:{email}">{email}</a>'.format(email="accessibility@edx.org")))}</p>
</div>
</section>
</section>
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