Commit f4660771 by kimth

Merge master

parents 64788a73 5b7ae1a9
...@@ -157,7 +157,7 @@ def edXauth_signup(request, eamap=None): ...@@ -157,7 +157,7 @@ def edXauth_signup(request, eamap=None):
log.debug('ExtAuth: doing signup for %s' % eamap.external_email) 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 # MIT SSL
...@@ -193,7 +193,7 @@ def edXauth_ssl_login(request): ...@@ -193,7 +193,7 @@ def edXauth_ssl_login(request):
The certificate provides user email and fullname; this populates the ExternalAuthMap. The certificate provides user email and fullname; this populates the ExternalAuthMap.
The user is nevertheless still asked to complete the edX signup. 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 certkey = "SSL_CLIENT_S_DN" # specify the request.META field to use
...@@ -207,7 +207,7 @@ def edXauth_ssl_login(request): ...@@ -207,7 +207,7 @@ def edXauth_ssl_login(request):
pass pass
if not cert: if not cert:
# no certificate information - go onward to main index # 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) (user, email, fullname) = ssl_dn_extract_info(cert)
...@@ -217,4 +217,4 @@ def edXauth_ssl_login(request): ...@@ -217,4 +217,4 @@ def edXauth_ssl_login(request):
credentials=cert, credentials=cert,
email=email, email=email,
fullname=fullname, 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 ...@@ -22,7 +22,6 @@ from django.db import IntegrityError
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string from mitxmako.shortcuts import render_to_response, render_to_string
from django.core.urlresolvers import reverse
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from django.core.cache import cache from django.core.cache import cache
...@@ -30,7 +29,6 @@ from django_future.csrf import ensure_csrf_cookie ...@@ -30,7 +29,6 @@ from django_future.csrf import ensure_csrf_cookie
from student.models import (Registration, UserProfile, from student.models import (Registration, UserProfile,
PendingNameChange, PendingEmailChange, PendingNameChange, PendingEmailChange,
CourseEnrollment) CourseEnrollment)
from util.cache import cache_if_anonymous
from xmodule.course_module import CourseDescriptor from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
...@@ -54,23 +52,7 @@ def csrf_token(context): ...@@ -54,23 +52,7 @@ def csrf_token(context):
' name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token)) ' name="csrfmiddlewaretoken" value="%s" /></div>' % (csrf_token))
@ensure_csrf_cookie def index(request, extra_context={}, user=None):
@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):
''' '''
Render the edX main page. Render the edX main page.
......
...@@ -9,6 +9,7 @@ from functools import wraps ...@@ -9,6 +9,7 @@ from functools import wraps
from django.core import cache from django.core import cache
# If we can't find a 'general' CACHE defined in settings.py, we simply fall back # If we can't find a 'general' CACHE defined in settings.py, we simply fall back
# to returning the default cache. This will happen with dev machines. # to returning the default cache. This will happen with dev machines.
try: try:
...@@ -41,7 +42,10 @@ def cache_if_anonymous(view_func): ...@@ -41,7 +42,10 @@ def cache_if_anonymous(view_func):
def _decorated(request, *args, **kwargs): def _decorated(request, *args, **kwargs):
if not request.user.is_authenticated(): if not request.user.is_authenticated():
#Use the cache #Use the cache
cache_key = "cache_if_anonymous." + request.path # same view accessed through different domain names may
# return different things, so include the domain name in the key.
domain = str(request.META.get('HTTP_HOST')) + '.'
cache_key = domain + "cache_if_anonymous." + request.path
response = cache.get(cache_key) response = cache.get(cache_key)
if not response: if not response:
response = view_func(request, *args, **kwargs) response = view_func(request, *args, **kwargs)
......
...@@ -61,6 +61,8 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -61,6 +61,8 @@ class CourseDescriptor(SequenceDescriptor):
def __init__(self, system, definition=None, **kwargs): def __init__(self, system, definition=None, **kwargs):
super(CourseDescriptor, self).__init__(system, definition, **kwargs) super(CourseDescriptor, self).__init__(system, definition, **kwargs)
self.textbooks = self.definition['data']['textbooks'] self.textbooks = self.definition['data']['textbooks']
self.wiki_slug = self.definition['data']['wiki_slug'] or self.location.course
msg = None msg = None
if self.start is None: if self.start is None:
...@@ -99,8 +101,19 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -99,8 +101,19 @@ class CourseDescriptor(SequenceDescriptor):
for textbook in xml_object.findall("textbook"): for textbook in xml_object.findall("textbook"):
textbooks.append(cls.Textbook.from_xml_object(textbook)) textbooks.append(cls.Textbook.from_xml_object(textbook))
xml_object.remove(textbook) xml_object.remove(textbook)
#Load the wiki tag if it exists
wiki_slug = None
wiki_tag = xml_object.find("wiki")
if wiki_tag is not None:
wiki_slug = wiki_tag.attrib.get("slug", default=None)
xml_object.remove(wiki_tag)
definition = super(CourseDescriptor, cls).definition_from_xml(xml_object, system) definition = super(CourseDescriptor, cls).definition_from_xml(xml_object, system)
definition.setdefault('data', {})['textbooks'] = textbooks definition.setdefault('data', {})['textbooks'] = textbooks
definition['data']['wiki_slug'] = wiki_slug
return definition return definition
def has_started(self): def has_started(self):
...@@ -202,6 +215,19 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -202,6 +215,19 @@ class CourseDescriptor(SequenceDescriptor):
def start_date_text(self): def start_date_text(self):
return time.strftime("%b %d, %Y", self.start) return time.strftime("%b %d, %Y", self.start)
# An extra property is used rather than the wiki_slug/number because
# there are courses that change the number for different runs. This allows
# courses to share the same css_class across runs even if they have
# different numbers.
#
# TODO get rid of this as soon as possible or potentially build in a robust
# way to add in course-specific styling. There needs to be a discussion
# about the right way to do this, but arjun will address this ASAP. Also
# note that the courseware template needs to change when this is removed.
@property
def css_class(self):
return self.metadata.get('css_class', '')
@property @property
def title(self): def title(self):
return self.display_name return self.display_name
...@@ -211,10 +237,6 @@ class CourseDescriptor(SequenceDescriptor): ...@@ -211,10 +237,6 @@ class CourseDescriptor(SequenceDescriptor):
return self.location.course return self.location.course
@property @property
def wiki_slug(self):
return self.location.course
@property
def org(self): def org(self):
return self.location.org return self.location.org
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
)
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)
...@@ -5,6 +5,7 @@ from django.http import Http404 ...@@ -5,6 +5,7 @@ from django.http import Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from wiki.models import reverse as wiki_reverse from wiki.models import reverse as wiki_reverse
from courseware.access import has_access
from courseware.courses import get_course_with_access from courseware.courses import get_course_with_access
...@@ -135,7 +136,9 @@ def context_processor(request): ...@@ -135,7 +136,9 @@ def context_processor(request):
try: try:
course = get_course_with_access(request.user, course_id, 'load') course = get_course_with_access(request.user, course_id, 'load')
return {'course' : course} staff_access = has_access(request.user, course, 'staff')
return {'course' : course,
'staff_access': staff_access}
except Http404: except Http404:
# We couldn't access the course for whatever reason. It is too late to change # We couldn't access the course for whatever reason. It is too late to change
# the URL here, so we just leave the course context. The middleware shouldn't # the URL here, so we just leave the course context. The middleware shouldn't
......
...@@ -80,8 +80,8 @@ def course_wiki_redirect(request, course_id): ...@@ -80,8 +80,8 @@ def course_wiki_redirect(request, course_id):
urlpath = URLPath.create_article( urlpath = URLPath.create_article(
root, root,
course_slug, course_slug,
title=course.number, title=course_slug,
content="{0}\n===\nThis is the wiki for **{1}**'s _{2}_.".format(course.number, course.org, course.title), content="This is the wiki for **{0}**'s _{1}_.".format(course.org, course.title),
user_message="Course page automatically created.", user_message="Course page automatically created.",
user=None, user=None,
ip_address=None, ip_address=None,
...@@ -114,7 +114,7 @@ def get_or_create_root(): ...@@ -114,7 +114,7 @@ def get_or_create_root():
"===", "===",
"Visit a course wiki to add an article.")) "Visit a course wiki to add an article."))
root = URLPath.create_root(title="edX Wiki", root = URLPath.create_root(title="Wiki",
content=starting_content) content=starting_content)
article = root.article article = root.article
article.group = None article.group = None
......
...@@ -13,6 +13,7 @@ from xmodule.modulestore.django import modulestore ...@@ -13,6 +13,7 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError from xmodule.modulestore.exceptions import ItemNotFoundError
from static_replace import replace_urls, try_staticfiles_lookup from static_replace import replace_urls, try_staticfiles_lookup
from courseware.access import has_access from courseware.access import has_access
import branding
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
...@@ -141,9 +142,10 @@ def get_course_info_section(course, section_key): ...@@ -141,9 +142,10 @@ def get_course_info_section(course, section_key):
raise KeyError("Invalid about key " + str(section_key)) raise KeyError("Invalid about key " + str(section_key))
# TODO: Fix this such that these are pulled in as extra course-specific tabs. # 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 # 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): def get_course_syllabus_section(course, section_key):
""" """
This returns the snippet of html to be rendered on the syllabus page, 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): ...@@ -178,24 +180,11 @@ def get_courses_by_university(user, domain=None):
''' '''
# TODO: Clean up how 'error' is done. # TODO: Clean up how 'error' is done.
# filter out any courses that errored. # filter out any courses that errored.
courses = [c for c in modulestore().get_courses() visible_courses = branding.get_visible_courses(domain)
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)
universities = defaultdict(list) universities = defaultdict(list)
for course in courses: for course in visible_courses:
if not has_access(user, course, 'see_exists'): if not has_access(user, course, 'see_exists'):
continue continue
if course.id not in visible_courses:
continue
universities[course.org].append(course) universities[course.org].append(course)
return universities return universities
...@@ -55,6 +55,11 @@ MITX_FEATURES = { ...@@ -55,6 +55,11 @@ MITX_FEATURES = {
# course_ids (see dev_int.py for an example) # course_ids (see dev_int.py for an example)
'SUBDOMAIN_COURSE_LISTINGS' : False, '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,
'ENABLE_TEXTBOOK' : True, 'ENABLE_TEXTBOOK' : True,
'ENABLE_DISCUSSION' : False, 'ENABLE_DISCUSSION' : False,
'ENABLE_DISCUSSION_SERVICE': True, 'ENABLE_DISCUSSION_SERVICE': True,
...@@ -62,7 +67,7 @@ MITX_FEATURES = { ...@@ -62,7 +67,7 @@ MITX_FEATURES = {
'ENABLE_SQL_TRACKING_LOGS': False, 'ENABLE_SQL_TRACKING_LOGS': False,
'ENABLE_LMS_MIGRATION': 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 # extrernal access methods
'ACCESS_REQUIRE_STAFF_FOR_COURSE': False, 'ACCESS_REQUIRE_STAFF_FOR_COURSE': False,
...@@ -195,6 +200,11 @@ COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x', ...@@ -195,6 +200,11 @@ COURSE_SETTINGS = {'6.002x_Fall_2012': {'number' : '6.002x',
# TODO (vshnayder): Will probably need to change as we get real access control in. # TODO (vshnayder): Will probably need to change as we get real access control in.
LMS_MIGRATION_ALLOWED_IPS = [] LMS_MIGRATION_ALLOWED_IPS = []
######################## subdomain specific settings ###########################
COURSE_LISTINGS = {}
SUBDOMAIN_BRANDING = {}
############################### XModule Store ################################## ############################### XModule Store ##################################
MODULESTORE = { MODULESTORE = {
'default': { 'default': {
...@@ -314,6 +324,7 @@ WIKI_ACCOUNT_HANDLING = False ...@@ -314,6 +324,7 @@ WIKI_ACCOUNT_HANDLING = False
WIKI_EDITOR = 'course_wiki.editors.CodeMirror' WIKI_EDITOR = 'course_wiki.editors.CodeMirror'
WIKI_SHOW_MAX_CHILDREN = 0 # We don't use the little menu that shows children of an article in the breadcrumb WIKI_SHOW_MAX_CHILDREN = 0 # We don't use the little menu that shows children of an article in the breadcrumb
WIKI_ANONYMOUS = False # Don't allow anonymous access until the styling is figured out WIKI_ANONYMOUS = False # Don't allow anonymous access until the styling is figured out
WIKI_CAN_CHANGE_PERMISSIONS = lambda article, user: user.has_perm('wiki.assign')
################################# Jasmine ################################### ################################# Jasmine ###################################
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee' JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
......
...@@ -15,6 +15,8 @@ TEMPLATE_DEBUG = True ...@@ -15,6 +15,8 @@ TEMPLATE_DEBUG = True
MITX_FEATURES['DISABLE_START_DATES'] = True MITX_FEATURES['DISABLE_START_DATES'] = True
MITX_FEATURES['ENABLE_SQL_TRACKING_LOGS'] = True MITX_FEATURES['ENABLE_SQL_TRACKING_LOGS'] = True
MITX_FEATURES['SUBDOMAIN_COURSE_LISTINGS'] = True
MITX_FEATURES['SUBDOMAIN_BRANDING'] = True
WIKI_ENABLED = True WIKI_ENABLED = True
...@@ -68,6 +70,28 @@ CACHE_TIMEOUT = 0 ...@@ -68,6 +70,28 @@ CACHE_TIMEOUT = 0
# Dummy secret key for dev # Dummy secret key for dev
SECRET_KEY = '85920908f28904ed733fe576320db18cabd7b6cd' 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 ################################# ################################ LMS Migration #################################
MITX_FEATURES['ENABLE_LMS_MIGRATION'] = True 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 MITX_FEATURES['ACCESS_REQUIRE_STAFF_FOR_COURSE'] = False # require that user be in the staff_* group to be able to enroll
......
...@@ -95,13 +95,6 @@ header.global.slim { ...@@ -95,13 +95,6 @@ header.global.slim {
top: -12px; top: -12px;
width: 1px; width: 1px;
} }
a {
width: 48px;
height: 24px;
background: url(../images/small-header-logo.png) no-repeat !important;
}
} }
.find-courses-button { .find-courses-button {
...@@ -138,4 +131,4 @@ header.global.slim { ...@@ -138,4 +131,4 @@ header.global.slim {
font-weight: bold; font-weight: bold;
letter-spacing: 0; letter-spacing: 0;
} }
} }
\ No newline at end of file
...@@ -199,6 +199,17 @@ section.wiki { ...@@ -199,6 +199,17 @@ section.wiki {
font-size: 0.9em; font-size: 0.9em;
font-family: Monaco, monospace; font-family: Monaco, monospace;
} }
.toc {
background-color: $sidebar-color;
padding: 9px;
margin: 10px 0;
@include border-radius(5px);
ul {
margin: 0;
}
}
} }
...@@ -216,7 +227,7 @@ section.wiki { ...@@ -216,7 +227,7 @@ section.wiki {
padding: 40px 40px; padding: 40px 40px;
@include box-sizing(border-box); @include box-sizing(border-box);
.timestamp { .timestamp{
margin-top: 15px; margin-top: 15px;
padding: 15px 0 0 10px; padding: 15px 0 0 10px;
border-top: 1px solid $light-gray; border-top: 1px solid $light-gray;
...@@ -230,6 +241,26 @@ section.wiki { ...@@ -230,6 +241,26 @@ section.wiki {
.date { .date {
font-size: 0.9em; font-size: 0.9em;
} }
}
.see-children {
padding: 15px 0 0;
border-top: 1px solid $light-gray;
margin-top: 15px;
a {
display: block;
padding: 2px 4px 2px 10px;
border-radius: 3px;
font-size: 0.9em;
line-height: 25px;
&:hover {
background-color: #f6f6f6;
text-decoration: none;
}
}
} }
} }
...@@ -659,6 +690,59 @@ section.wiki { ...@@ -659,6 +690,59 @@ section.wiki {
margin-top: 9px; margin-top: 9px;
} }
/*-----------------
Directory
-----------------*/
.directory-toolbar {
background-color: $sidebar-color;
padding: 9px;
margin: 0 -9px 20px;
@include border-radius(5px);
.well-small {
@include clearfix;
a {
@include inline-block;
}
}
+ p {
font-size: 0.9em;
color: #aaa;
}
}
.filter-clear {
margin-right: 10px;
margin-top: 10px;
font-size: .9em;
a {
color: #aaa;
&:hover {
color: #777;
}
}
}
.table.table-striped {
width: 100%;
margin-top: 20px;
th, td {
border-bottom: 1px solid $light-gray;
padding: 8px;
}
tr:nth-child(even) {
background: #F6F6F6;
}
}
...@@ -784,6 +868,39 @@ section.wiki { ...@@ -784,6 +868,39 @@ section.wiki {
text-decoration: none; text-decoration: none;
} }
} }
.missing {
max-width: 400px;
margin: lh(2) auto;
display: block;
overflow: hidden;
background: $pink;
padding: lh();
@include box-shadow(inset 0 0 0 1px lighten($pink, 10%));
border: 1px solid darken($pink, 15%);
p {
color: #fff;
a {
display: block;
background: darken($pink, 8%);
margin: lh() (-(lh())) (-(lh()));
padding: lh();
border-top: 1px solid darken($pink, 15%);
color: #fff;
font-weight: bold;
font-size: em(18);
@include transition;
text-align: center;
-webkit-font-smoothing: antialiased;
&:hover {
background: darken($pink, 12%);
}
}
}
}
} }
.modal-backdrop { .modal-backdrop {
......
...@@ -19,7 +19,7 @@ header.global { ...@@ -19,7 +19,7 @@ header.global {
h1.logo { h1.logo {
float: left; float: left;
margin: 6px 15px 0px 0px; margin: 0px 15px 0px 0px;
padding-right: 20px; padding-right: 20px;
position: relative; position: relative;
...@@ -46,12 +46,7 @@ header.global { ...@@ -46,12 +46,7 @@ header.global {
} }
a { a {
@include background-image(url('/static/images/header-logo.png'));
background-position: 0 0;
background-repeat: no-repeat;
display: block; display: block;
height: 31px;
width: 64px;
} }
} }
......
<%inherit file="/main.html" /> <%inherit file="/main.html" />
<%namespace name='static' file='/static_content.html'/> <%namespace name='static' file='/static_content.html'/>
<%block name="bodyclass">courseware</%block> <%block name="bodyclass">courseware ${course.css_class}</%block>
<%block name="title"><title>${course.number} Courseware</title></%block> <%block name="title"><title>${course.number} Courseware</title></%block>
<%block name="headextra"> <%block name="headextra">
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<nav> <nav>
<section class="top"> <section class="top">
<section class="primary"> <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('courses')}">Find Courses</a>
<a href="${reverse('about_edx')}">About</a> <a href="${reverse('about_edx')}">About</a>
<a href="http://edxonline.tumblr.com/">Blog</a> <a href="http://edxonline.tumblr.com/">Blog</a>
......
<%inherit file="main.html" /> <%inherit file="main.html" />
<%include file="navigation.html" args="active_page=''" />
<script> <script>
function name_confirm(id) { function name_confirm(id) {
postJSON('/accept_name_change',{"id":id}, postJSON('/accept_name_change',{"id":id},
......
...@@ -3,7 +3,12 @@ ...@@ -3,7 +3,12 @@
## one for people who aren't. Assume a Course object is passed to the former, ## one for people who aren't. Assume a Course object is passed to the former,
## instead of using settings.COURSE_TITLE ## instead of using settings.COURSE_TITLE
<%namespace name='static' file='static_content.html'/> <%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: %if course:
<header class="global slim" aria-label="Global Navigation"> <header class="global slim" aria-label="Global Navigation">
...@@ -11,7 +16,7 @@ ...@@ -11,7 +16,7 @@
<header class="global" aria-label="Global Navigation"> <header class="global" aria-label="Global Navigation">
%endif %endif
<nav> <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: %if course:
<h2><span class="provider">${course.org}:</span> ${course.number} ${course.title}</h2> <h2><span class="provider">${course.org}:</span> ${course.number} ${course.title}</h2>
......
<%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>
...@@ -11,18 +11,19 @@ ...@@ -11,18 +11,19 @@
{% block wiki_contents %} {% block wiki_contents %}
<div class="article-wrapper"> <div class="article-wrapper">
<article class="main-article"> <article class="main-article">
{% if selected_tab != "edit" %} {% if selected_tab != "edit" %}
<h1>{{ article.current_revision.title }}</h1> <h1>{{ article.current_revision.title }}</h1>
{% endif %} {% endif %}
{% block wiki_contents_tab %} {% block wiki_contents_tab %}
{% wiki_render article %} {% wiki_render article %}
{% endblock %} {% endblock %}
</article> </article>
<div class="article-functions"> <div class="article-functions">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
{% include "wiki/includes/article_menu.html" %} {% include "wiki/includes/article_menu.html" %}
</ul> </ul>
...@@ -30,6 +31,12 @@ ...@@ -30,6 +31,12 @@
<span class="label">{% trans "Last modified:" %}</span><br /> <span class="label">{% trans "Last modified:" %}</span><br />
<span class="date">{{ article.current_revision.modified }}</span> <span class="date">{{ article.current_revision.modified }}</span>
</div> </div>
{% if urlpath %}
<div class="see-children">
<a href="{% url 'wiki:dir' path=urlpath.path %}">See all children</a>
</div>
{% endif %}
</div> </div>
</div> </div>
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n sekizai_tags %}
{% load url from future %}
{% block pagetitle %}{% trans "Delete article" %}{% endblock %}
{% block wiki_contents %}
<h1 class="page-header">{% trans "Delete" %} "{{ article.current_revision.title }}"</h1>
{% if cannot_delete_root %}
<p class="lead">{% trans "You cannot delete a root article." %}</p>
<p><a href="{% url 'wiki:get' path=urlpath.path article_id=article.id %}">{% trans "Go back" %}</a></p>
{% else %}
{% if cannot_delete_children %}
<p class="alert alert-error"><strong>{% trans "You cannot delete this article because you do not have permission to delete articles with children. Try to remove the children manually one-by-one." %}</strong></p>
{% endif %}
{% if delete_children %}
<p class="lead">{% trans "You are deleting an article. This means that its children will be deleted as well. If you choose to purge, children will also be purged!" %}</p>
<h2>{% trans "Articles that will be deleted" %}</h2>
<ul>
{% for child in delete_children %}
<li><a href="{% url 'wiki:get' article_id=child.article.id %}" target="_blank">{{ child.article }}</a></li>
{% if delete_children_more %}
<li><em>{% trans "...and more!" %}</em></li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% if not cannot_delete_children %}
<p class="lead">{% trans "You are deleting an article. Please confirm." %}</p>
<form method="POST" class="form-horizontal">
{% wiki_form delete_form %}
<script type="text/javascript">
$('#id_revision').val('{{ article.current_revision.id }}');
</script>
<div class="form-actions">
<a href="{% url 'wiki:get' path=urlpath.path article_id=article.id %}" class="btn btn-large">
<span class="icon-circle-arrow-left"></span>
{% trans "Go back" %}
</a>
<button type="submit" name="save_changes" class="btn btn-danger btn-large">
<span class="icon-plus"></span>
{% trans "Delete article" %}
</button>
</div>
</form>
{% endif %}
{% endif %}
{% endblock %}
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
%endif %endif
%endfor %endfor
<%doc>
The settings link has been disabled because the notifications app hasn't been integrated yet and those are the only useful settings.
%if not user.is_anonymous(): %if not user.is_anonymous():
<li class="${"active" if selected_tab == "settings" else ""}"> <li class="${"active" if selected_tab == "settings" else ""}">
<a href="${reverse('wiki:settings', kwargs={'article_id' : article.id, 'path' : urlpath.path})}"> <a href="${reverse('wiki:settings', kwargs={'article_id' : article.id, 'path' : urlpath.path})}">
...@@ -43,4 +47,6 @@ ...@@ -43,4 +47,6 @@
</a> </a>
</li> </li>
%endif %endif
</%doc>
...@@ -115,7 +115,13 @@ ...@@ -115,7 +115,13 @@
{% if attachment.current_revision.user %}{{ attachment.current_revision.user }}{% else %}{% if user|is_moderator %}{{ attachment.current_revision.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %} {% if attachment.current_revision.user %}{{ attachment.current_revision.user }}{% else %}{% if user|is_moderator %}{{ attachment.current_revision.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %}
</td> </td>
<td>{{ attachment.current_revision.get_size|filesizeformat }}</td> <td>{{ attachment.current_revision.get_size|filesizeformat }}</td>
<td>{{ attachment.attachmentrevision_set.all.count }} {% trans "revisions" %}</td>
<td>
<a href="{% url 'wiki:attachments_history' path=urlpath.path article_id=article.id attachment_id=attachment.id %}">
<span class="icon-time"></span>
{% trans "File history" %} ({{ attachment.attachmentrevision_set.all.count }} {% trans "revisions" %})
</a>
</td>
</tr> </tr>
</table> </table>
</div> </div>
......
...@@ -10,22 +10,31 @@ ...@@ -10,22 +10,31 @@
<div class="main-article"> <div class="main-article">
{% if revision %} {% if revision %}
<div class="alert alert-info"> <div class="alert alert-info">
<strong>{% trans "Previewing revision" %}:</strong> {{ revision.created }} (#{{ revision.revision_number }}) by {% if revision.user %}{{ revision.user }}{% else %}{% if user|is_moderator %}{{ revision.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %} <strong>{% trans "Previewing revision" %}:</strong>
{% include "wiki/includes/revision_info.html" %}
</div> </div>
{% endif %} {% endif %}
{% if merge %} {% if merge %}
<div class="alert alert-info"> <div class="alert alert-info">
<strong>{% trans "Previewing merge between" %}:</strong> <strong>{% trans "Previewing merge between" %}:</strong>
{{ merge1.created }} (#{{ merge1.revision_number }}) by {% if merge1.user %}{{ merge1.user }}{% else %}{% if user|is_moderator %}{{ merge1.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %} {% include "wiki/includes/revision_info.html" with revision=merge1 %}
<strong>{% trans "and" %}</strong> <strong>{% trans "and" %}</strong>
{{ merge1.created }} (#{{ merge1.revision_number }}) by {% if merge1.user %}{{ merge1.user }}{% else %}{% if user|is_moderator %}{{ merge1.ip_address|default:"anonymous (IP not logged)" }}{% else %}{% trans "anonymous (IP logged)" %}{% endif %}{% endif %} {% include "wiki/includes/revision_info.html" with revision=merge2 %}
</div> </div>
{% endif %} {% endif %}
<h1 class="page-header">{{ title }}</h1> <h1 class="page-header">{{ title }}</h1>
{% wiki_render article content %} {% if revision and revision.deleted %}
<div class="warning">
<strong>This revision has been deleted.</strong>
<p>Restoring to this revision will mark the article as deleted.</p>
</div>
{% else %}
{% wiki_render article content %}
{% endif %}
</div> </div>
</section> </section>
......
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{% trans "Settings" %}: {{ article.current_revision.title }}{% endblock %}
{% block wiki_breadcrumbs %}
{% include "wiki/includes/breadcrumbs.html" %}
{% endblock %}
{% block wiki_contents %}
<div class="article-wrapper">
<article class="main-article">
{% if selected_tab != "edit" %}
<h1>{{ article.current_revision.title }}</h1>
{% endif %}
{% for form in forms %}
<form method="POST" class="form-horizontal" id="settings_form" action="?f={{form.action}}">
<h2>{{ form.settings_form_headline }}</h2>
<div class="well">
{% wiki_form form %}
</div>
<div class="form-actions">
<button type="submit" name="save" value="1" class="btn btn-large btn-primary">
<span class="icon-ok"></span>
{% trans "Save changes" %}
</button>
</div>
</form>
{% endfor %}
</article>
<div class="article-functions">
<ul class="nav nav-tabs">
{% with "settings" as selected %}
{% include "wiki/includes/article_menu.html" %}
{% endwith %}
</ul>
<div class="timestamp">
<span class="label">{% trans "Last modified:" %}</span><br />
<span class="date">{{ article.current_revision.modified }}</span>
</div>
</div>
</div>
{% endblock %}
{% extends "wiki/base.html" %}
{% load wiki_tags i18n %}
{% load url from future %}
{% block pagetitle %}{{ article.current_revision.title }}{% endblock %}
{% block wiki_breadcrumbs %}
{% include "wiki/includes/breadcrumbs.html" %}
{% endblock %}
{% block wiki_contents %}
<div class="missing-wrapper">
<p>This article was not found, and neither was the parent. <a href="#">Go back to the main wiki article.</a></p>
<button type="submit">Create a new article</button>
</div>
{% endblock %}
...@@ -10,7 +10,7 @@ if settings.DEBUG: ...@@ -10,7 +10,7 @@ if settings.DEBUG:
admin.autodiscover() admin.autodiscover()
urlpatterns = ('', 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'^dashboard$', 'student.views.dashboard', name="dashboard"),
url(r'^admin_dashboard$', 'dashboard.views.dashboard'), url(r'^admin_dashboard$', 'dashboard.views.dashboard'),
...@@ -115,7 +115,7 @@ if settings.COURSEWARE_ENABLED: ...@@ -115,7 +115,7 @@ if settings.COURSEWARE_ENABLED:
# url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'), # url(r'^edit_circuit/(?P<circuit>[^/]*)$', 'circuit.views.edit_circuit'),
# url(r'^save_circuit/(?P<circuit>[^/]*)$', 'circuit.views.save_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$', url(r'^change_enrollment$',
'student.views.change_enrollment_view', name="change_enrollment"), 'student.views.change_enrollment_view', name="change_enrollment"),
......
...@@ -200,6 +200,8 @@ task :package do ...@@ -200,6 +200,8 @@ task :package do
"--exclude=**/.git/**", "--exclude=**/.git/**",
"--exclude=**/*.pyc", "--exclude=**/*.pyc",
"--exclude=**/reports/**", "--exclude=**/reports/**",
"--exclude=**/test_root/**",
"--exclude=**/.coverage/**",
"-C", "#{REPO_ROOT}", "-C", "#{REPO_ROOT}",
"--provides=#{PACKAGE_NAME}", "--provides=#{PACKAGE_NAME}",
"--name=#{NORMALIZED_DEPLOY_NAME}", "--name=#{NORMALIZED_DEPLOY_NAME}",
......
-e git://github.com/MITx/django-staticfiles.git@6d2504e5c8#egg=django-staticfiles -e git://github.com/MITx/django-staticfiles.git@6d2504e5c8#egg=django-staticfiles
-e git://github.com/MITx/django-pipeline.git#egg=django-pipeline -e git://github.com/MITx/django-pipeline.git#egg=django-pipeline
-e git://github.com/benjaoming/django-wiki.git@02275fb4#egg=django-wiki -e git://github.com/benjaoming/django-wiki.git@63003aa#egg=django-wiki
-e git://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev -e git://github.com/dementrock/pystache_custom.git@776973740bdaad83a3b029f96e415a7d1e8bec2f#egg=pystache_custom-dev
-e common/lib/capa -e common/lib/capa
-e common/lib/xmodule -e common/lib/xmodule
...@@ -2,7 +2,7 @@ django>=1.4,<1.5 ...@@ -2,7 +2,7 @@ django>=1.4,<1.5
pip pip
numpy numpy
scipy scipy
markdown Markdown<2.3.0
pygments pygments
lxml lxml
boto boto
...@@ -43,5 +43,7 @@ django-ses ...@@ -43,5 +43,7 @@ django-ses
django-storages django-storages
django-threaded-multihost django-threaded-multihost
django-sekizai<0.7 django-sekizai<0.7
django-mptt>=0.5.3
sorl-thumbnail
networkx networkx
-r repo-requirements.txt -r repo-requirements.txt
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