Merge pull request #500 from MITx/feature/cale/university-branding
Feature/cale/university branding
This commit is contained in:
@@ -157,7 +157,7 @@ def edXauth_signup(request, eamap=None):
|
||||
|
||||
log.debug('ExtAuth: doing signup for %s' % eamap.external_email)
|
||||
|
||||
return student_views.main_index(request, extra_context=context)
|
||||
return student_views.index(request, extra_context=context)
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# MIT SSL
|
||||
@@ -193,7 +193,7 @@ def edXauth_ssl_login(request):
|
||||
The certificate provides user email and fullname; this populates the ExternalAuthMap.
|
||||
The user is nevertheless still asked to complete the edX signup.
|
||||
|
||||
Else continues on with student.views.main_index, and no authentication.
|
||||
Else continues on with student.views.index, and no authentication.
|
||||
"""
|
||||
certkey = "SSL_CLIENT_S_DN" # specify the request.META field to use
|
||||
|
||||
@@ -207,7 +207,7 @@ def edXauth_ssl_login(request):
|
||||
pass
|
||||
if not cert:
|
||||
# no certificate information - go onward to main index
|
||||
return student_views.main_index(request)
|
||||
return student_views.index(request)
|
||||
|
||||
(user, email, fullname) = ssl_dn_extract_info(cert)
|
||||
|
||||
@@ -217,4 +217,4 @@ def edXauth_ssl_login(request):
|
||||
credentials=cert,
|
||||
email=email,
|
||||
fullname=fullname,
|
||||
retfun = functools.partial(student_views.main_index, request))
|
||||
retfun = functools.partial(student_views.index, request))
|
||||
|
||||
@@ -22,7 +22,6 @@ from django.db import IntegrityError
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.shortcuts import redirect
|
||||
from mitxmako.shortcuts import render_to_response, render_to_string
|
||||
from django.core.urlresolvers import reverse
|
||||
from bs4 import BeautifulSoup
|
||||
from django.core.cache import cache
|
||||
|
||||
@@ -30,7 +29,6 @@ from django_future.csrf import ensure_csrf_cookie
|
||||
from student.models import (Registration, UserProfile,
|
||||
PendingNameChange, PendingEmailChange,
|
||||
CourseEnrollment)
|
||||
from util.cache import cache_if_anonymous
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from xmodule.modulestore.django import modulestore
|
||||
@@ -54,23 +52,7 @@ def csrf_token(context):
|
||||
' name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token))
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@cache_if_anonymous
|
||||
def index(request):
|
||||
|
||||
''' Redirects to main page -- info page if user authenticated, or marketing if not
|
||||
'''
|
||||
|
||||
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
|
||||
return redirect(reverse('dashboard'))
|
||||
|
||||
if settings.MITX_FEATURES.get('AUTH_USE_MIT_CERTIFICATES'):
|
||||
from external_auth.views import edXauth_ssl_login
|
||||
return edXauth_ssl_login(request)
|
||||
|
||||
return main_index(request, user=request.user)
|
||||
|
||||
def main_index(request, extra_context={}, user=None):
|
||||
def index(request, extra_context={}, user=None):
|
||||
'''
|
||||
Render the edX main page.
|
||||
|
||||
|
||||
52
lms/djangoapps/branding/__init__.py
Normal file
52
lms/djangoapps/branding/__init__.py
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def get_subdomain(domain):
|
||||
return domain.split(".")[0]
|
||||
|
||||
|
||||
def get_visible_courses(domain=None):
|
||||
"""
|
||||
Return the set of CourseDescriptors that should be visible in this branded instance
|
||||
"""
|
||||
courses = [c for c in modulestore().get_courses()
|
||||
if isinstance(c, CourseDescriptor)]
|
||||
courses = sorted(courses, key=lambda course: course.number)
|
||||
|
||||
if domain and settings.MITX_FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
|
||||
subdomain = get_subdomain(domain)
|
||||
if subdomain not in settings.COURSE_LISTINGS:
|
||||
subdomain = 'default'
|
||||
visible_ids = frozenset(settings.COURSE_LISTINGS[subdomain])
|
||||
return [course for course in courses if course.id in visible_ids]
|
||||
else:
|
||||
return courses
|
||||
|
||||
|
||||
def get_university(domain=None):
|
||||
"""
|
||||
Return the university name specified for the domain, or None
|
||||
if no university was specified
|
||||
"""
|
||||
if not settings.MITX_FEATURES['SUBDOMAIN_BRANDING'] or domain is None:
|
||||
return None
|
||||
|
||||
subdomain = get_subdomain(domain)
|
||||
return settings.SUBDOMAIN_BRANDING.get(subdomain)
|
||||
|
||||
|
||||
def get_logo_url(domain=None):
|
||||
"""
|
||||
Return the url for the branded logo image to be used
|
||||
"""
|
||||
university = get_university(domain)
|
||||
|
||||
if university is None:
|
||||
return '/static/images/header-logo.png'
|
||||
|
||||
return '/static/images/{uni}-on-edx-logo.png'.format(
|
||||
uni=university
|
||||
)
|
||||
45
lms/djangoapps/branding/views.py
Normal file
45
lms/djangoapps/branding/views.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.shortcuts import redirect
|
||||
from django_future.csrf import ensure_csrf_cookie
|
||||
|
||||
import student.views
|
||||
import branding
|
||||
import courseware.views
|
||||
from util.cache import cache_if_anonymous
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@cache_if_anonymous
|
||||
def index(request):
|
||||
'''
|
||||
Redirects to main page -- info page if user authenticated, or marketing if not
|
||||
'''
|
||||
|
||||
if settings.COURSEWARE_ENABLED and request.user.is_authenticated():
|
||||
return redirect(reverse('dashboard'))
|
||||
|
||||
if settings.MITX_FEATURES.get('AUTH_USE_MIT_CERTIFICATES'):
|
||||
from external_auth.views import edXauth_ssl_login
|
||||
return edXauth_ssl_login(request)
|
||||
|
||||
university = branding.get_university(request.META.get('HTTP_HOST'))
|
||||
if university is None:
|
||||
return student.views.index(request, user=request.user)
|
||||
|
||||
return courseware.views.university_profile(request, university)
|
||||
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@cache_if_anonymous
|
||||
def courses(request):
|
||||
"""
|
||||
Render the "find courses" page. If subdomain branding is on, this is the
|
||||
university profile page, otherwise it's the edX courseware.views.courses page
|
||||
"""
|
||||
|
||||
university = branding.get_university(request.META.get('HTTP_HOST'))
|
||||
if university is None:
|
||||
return courseware.views.courses(request)
|
||||
|
||||
return courseware.views.university_profile(request, university)
|
||||
@@ -13,6 +13,7 @@ from xmodule.modulestore.django import modulestore
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
from static_replace import replace_urls, try_staticfiles_lookup
|
||||
from courseware.access import has_access
|
||||
import branding
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -141,9 +142,10 @@ def get_course_info_section(course, section_key):
|
||||
|
||||
raise KeyError("Invalid about key " + str(section_key))
|
||||
|
||||
|
||||
# TODO: Fix this such that these are pulled in as extra course-specific tabs.
|
||||
# arjun will address this by the end of October if no one does so prior to
|
||||
# then.
|
||||
# then.
|
||||
def get_course_syllabus_section(course, section_key):
|
||||
"""
|
||||
This returns the snippet of html to be rendered on the syllabus page,
|
||||
@@ -178,24 +180,11 @@ def get_courses_by_university(user, domain=None):
|
||||
'''
|
||||
# TODO: Clean up how 'error' is done.
|
||||
# filter out any courses that errored.
|
||||
courses = [c for c in modulestore().get_courses()
|
||||
if isinstance(c, CourseDescriptor)]
|
||||
courses = sorted(courses, key=lambda course: course.number)
|
||||
|
||||
if domain and settings.MITX_FEATURES.get('SUBDOMAIN_COURSE_LISTINGS'):
|
||||
subdomain = domain.split(".")[0]
|
||||
if subdomain not in settings.COURSE_LISTINGS:
|
||||
subdomain = 'default'
|
||||
visible_courses = frozenset(settings.COURSE_LISTINGS[subdomain])
|
||||
else:
|
||||
visible_courses = frozenset(c.id for c in courses)
|
||||
visible_courses = branding.get_visible_courses(domain)
|
||||
|
||||
universities = defaultdict(list)
|
||||
for course in courses:
|
||||
for course in visible_courses:
|
||||
if not has_access(user, course, 'see_exists'):
|
||||
continue
|
||||
if course.id not in visible_courses:
|
||||
continue
|
||||
universities[course.org].append(course)
|
||||
return universities
|
||||
|
||||
|
||||
@@ -55,9 +55,14 @@ MITX_FEATURES = {
|
||||
# course_ids (see dev_int.py for an example)
|
||||
'SUBDOMAIN_COURSE_LISTINGS' : False,
|
||||
|
||||
# When True, will override certain branding with university specific values
|
||||
# Expects a SUBDOMAIN_BRANDING dictionary that maps the subdomain to the
|
||||
# university to use for branding purposes
|
||||
'SUBDOMAIN_BRANDING': False,
|
||||
|
||||
# TODO: This will be removed once course-specific tabs are in place. see
|
||||
# courseware/courses.py
|
||||
'ENABLE_SYLLABUS' : True,
|
||||
'ENABLE_SYLLABUS' : True,
|
||||
|
||||
'ENABLE_TEXTBOOK' : True,
|
||||
'ENABLE_DISCUSSION' : False,
|
||||
@@ -66,7 +71,7 @@ MITX_FEATURES = {
|
||||
'ENABLE_SQL_TRACKING_LOGS': False,
|
||||
'ENABLE_LMS_MIGRATION': False,
|
||||
|
||||
'DISABLE_LOGIN_BUTTON': False, # used in systems where login is automatic, eg MIT SSL
|
||||
'DISABLE_LOGIN_BUTTON': False, # used in systems where login is automatic, eg MIT SSL
|
||||
|
||||
# extrernal access methods
|
||||
'ACCESS_REQUIRE_STAFF_FOR_COURSE': False,
|
||||
@@ -199,6 +204,11 @@ COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x',
|
||||
# TODO (vshnayder): Will probably need to change as we get real access control in.
|
||||
LMS_MIGRATION_ALLOWED_IPS = []
|
||||
|
||||
######################## subdomain specific settings ###########################
|
||||
COURSE_LISTINGS = {}
|
||||
SUBDOMAIN_BRANDING = {}
|
||||
|
||||
|
||||
############################### XModule Store ##################################
|
||||
MODULESTORE = {
|
||||
'default': {
|
||||
|
||||
@@ -15,6 +15,8 @@ TEMPLATE_DEBUG = True
|
||||
|
||||
MITX_FEATURES['DISABLE_START_DATES'] = True
|
||||
MITX_FEATURES['ENABLE_SQL_TRACKING_LOGS'] = True
|
||||
MITX_FEATURES['SUBDOMAIN_COURSE_LISTINGS'] = True
|
||||
MITX_FEATURES['SUBDOMAIN_BRANDING'] = True
|
||||
|
||||
WIKI_ENABLED = True
|
||||
|
||||
@@ -68,6 +70,28 @@ CACHE_TIMEOUT = 0
|
||||
# Dummy secret key for dev
|
||||
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd'
|
||||
|
||||
COURSE_LISTINGS = {
|
||||
'default': ['BerkeleyX/CS169.1x/2012_Fall',
|
||||
'BerkeleyX/CS188.1x/2012_Fall',
|
||||
'HarvardX/CS50x/2012',
|
||||
'HarvardX/PH207x/2012_Fall',
|
||||
'MITx/3.091x/2012_Fall',
|
||||
'MITx/6.002x/2012_Fall',
|
||||
'MITx/6.00x/2012_Fall'],
|
||||
'berkeley': ['BerkeleyX/CS169.1x/Cal_2012_Fall',
|
||||
'BerkeleyX/CS188.1x/Cal_2012_Fall'],
|
||||
'harvard': ['HarvardX/CS50x/2012H'],
|
||||
'mit': [],
|
||||
'sjsu': ['MITx/6.002x-EE98/2012_Fall_SJSU'],
|
||||
}
|
||||
|
||||
SUBDOMAIN_BRANDING = {
|
||||
'sjsu': 'MITx',
|
||||
'mit': 'MITx',
|
||||
'berkeley': 'BerkeleyX',
|
||||
'harvard': 'HarvardX',
|
||||
}
|
||||
|
||||
################################ LMS Migration #################################
|
||||
MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True
|
||||
MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll
|
||||
|
||||
BIN
lms/static/images/BerkeleyX-on-edx-logo.png
Normal file
BIN
lms/static/images/BerkeleyX-on-edx-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
lms/static/images/HarvardX-on-edx-logo.png
Normal file
BIN
lms/static/images/HarvardX-on-edx-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
BIN
lms/static/images/MITx-on-edx-logo.png
Normal file
BIN
lms/static/images/MITx-on-edx-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -95,13 +95,6 @@ header.global.slim {
|
||||
top: -12px;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
a {
|
||||
width: 48px;
|
||||
height: 24px;
|
||||
background: url(../images/small-header-logo.png) no-repeat !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.find-courses-button {
|
||||
@@ -138,4 +131,4 @@ header.global.slim {
|
||||
font-weight: bold;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ header.global {
|
||||
|
||||
h1.logo {
|
||||
float: left;
|
||||
margin: 6px 15px 0px 0px;
|
||||
margin: 0px 15px 0px 0px;
|
||||
padding-right: 20px;
|
||||
position: relative;
|
||||
|
||||
@@ -46,12 +46,7 @@ header.global {
|
||||
}
|
||||
|
||||
a {
|
||||
@include background-image(url('/static/images/header-logo.png'));
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
height: 31px;
|
||||
width: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<nav>
|
||||
<section class="top">
|
||||
<section class="primary">
|
||||
<a href="${reverse('root')}" class="logo"></a>
|
||||
<a href="https://www.edx.org" class="logo"></a>
|
||||
<a href="${reverse('courses')}">Find Courses</a>
|
||||
<a href="${reverse('about_edx')}">About</a>
|
||||
<a href="http://edxonline.tumblr.com/">Blog</a>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<%inherit file="main.html" />
|
||||
<%include file="navigation.html" args="active_page=''" />
|
||||
<script>
|
||||
function name_confirm(id) {
|
||||
postJSON('/accept_name_change',{"id":id},
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
## one for people who aren't. Assume a Course object is passed to the former,
|
||||
## instead of using settings.COURSE_TITLE
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%!
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
# App that handles subdomain specific branding
|
||||
import branding
|
||||
%>
|
||||
|
||||
%if course:
|
||||
<header class="global slim" aria-label="Global Navigation">
|
||||
@@ -11,7 +16,7 @@
|
||||
<header class="global" aria-label="Global Navigation">
|
||||
%endif
|
||||
<nav>
|
||||
<h1 class="logo"><a href="${reverse('root')}"></a></h1>
|
||||
<h1 class="logo"><a href="${reverse('root')}"><img src="${static.url(branding.get_logo_url(request.META.get('HTTP_HOST')))}"/></a></h1>
|
||||
|
||||
%if course:
|
||||
<h2><span class="provider">${course.org}:</span> ${course.number} ${course.title}</h2>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<%inherit file="main.html" />
|
||||
<%block name="title"><title>Textbook – MITx 6.002x</title></%block>
|
||||
|
||||
<div id="bodyContent">
|
||||
<%include file="navigation.html" />
|
||||
|
||||
<div>
|
||||
${ text }
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,7 +10,7 @@ if settings.DEBUG:
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = ('',
|
||||
url(r'^$', 'student.views.index', name="root"), # Main marketing page, or redirect to courseware
|
||||
url(r'^$', 'branding.views.index', name="root"), # Main marketing page, or redirect to courseware
|
||||
url(r'^dashboard$', 'student.views.dashboard', name="dashboard"),
|
||||
|
||||
url(r'^admin_dashboard$', 'dashboard.views.dashboard'),
|
||||
@@ -115,7 +115,7 @@ if settings.COURSEWARE_ENABLED:
|
||||
# url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
|
||||
# url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_circuit'),
|
||||
|
||||
url(r'^courses/?$', 'courseware.views.courses', name="courses"),
|
||||
url(r'^courses/?$', 'branding.views.courses', name="courses"),
|
||||
url(r'^change_enrollment$',
|
||||
'student.views.change_enrollment_view', name="change_enrollment"),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user