Merge branch 'master' into feature/tomg/fall-design
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.
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ from functools import wraps
|
||||
|
||||
from django.core import cache
|
||||
|
||||
|
||||
# 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.
|
||||
try:
|
||||
@@ -41,7 +42,10 @@ def cache_if_anonymous(view_func):
|
||||
def _decorated(request, *args, **kwargs):
|
||||
if not request.user.is_authenticated():
|
||||
#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)
|
||||
if not response:
|
||||
response = view_func(request, *args, **kwargs)
|
||||
|
||||
@@ -112,11 +112,14 @@ def add_histogram(get_html, module, user):
|
||||
edit_link = "%s/%s/tree/master/%s" % (giturl,data_dir,filepath)
|
||||
else:
|
||||
edit_link = False
|
||||
source_file = module.metadata.get('source_file','') # source used to generate the problem XML, eg latex or word
|
||||
|
||||
staff_context = {'definition': module.definition.get('data'),
|
||||
'metadata': json.dumps(module.metadata, indent=4),
|
||||
'location': module.location,
|
||||
'xqa_key': module.metadata.get('xqa_key',''),
|
||||
'source_file' : source_file,
|
||||
'source_url': '%s/%s/tree/master/%s' % (giturl,data_dir,source_file),
|
||||
'category': str(module.__class__.__name__),
|
||||
'element_id': module.location.html_id().replace('-','_'),
|
||||
'edit_link': edit_link,
|
||||
|
||||
@@ -557,7 +557,7 @@ class ChoiceResponse(LoncapaResponse):
|
||||
return CorrectMap(self.answer_id, 'incorrect')
|
||||
|
||||
def get_answers(self):
|
||||
return {self.answer_id: self.correct_choices}
|
||||
return {self.answer_id: list(self.correct_choices)}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -390,9 +390,19 @@ class CapaModule(XModule):
|
||||
raise NotFoundError('Answer is not available')
|
||||
else:
|
||||
answers = self.lcp.get_question_answers()
|
||||
|
||||
# answers (eg <solution>) may have embedded images
|
||||
answers = dict( (k,self.system.replace_urls(answers[k], self.metadata['data_dir'])) for k in answers )
|
||||
return {'answers': answers}
|
||||
# but be careful, some problems are using non-string answer dicts
|
||||
new_answers = dict()
|
||||
for answer_id in answers:
|
||||
try:
|
||||
new_answer = {answer_id: self.system.replace_urls(answers[answer_id], self.metadata['data_dir'])}
|
||||
except TypeError:
|
||||
log.debug('Unable to perform URL substitution on answers[%s]: %s' % (answer_id, answers[answer_id]))
|
||||
new_answer = {answer_id: answers[answer_id]}
|
||||
new_answers.update(new_answer)
|
||||
|
||||
return {'answers': new_answers}
|
||||
|
||||
# Figure out if we should move these to capa_problem?
|
||||
def get_problem(self, get):
|
||||
|
||||
@@ -60,6 +60,8 @@ class CourseDescriptor(SequenceDescriptor):
|
||||
def __init__(self, system, definition=None, **kwargs):
|
||||
super(CourseDescriptor, self).__init__(system, definition, **kwargs)
|
||||
self.textbooks = self.definition['data']['textbooks']
|
||||
|
||||
self.wiki_slug = self.definition['data']['wiki_slug'] or self.location.course
|
||||
|
||||
msg = None
|
||||
if self.start is None:
|
||||
@@ -94,8 +96,19 @@ class CourseDescriptor(SequenceDescriptor):
|
||||
for textbook in xml_object.findall("textbook"):
|
||||
textbooks.append(cls.Textbook.from_xml_object(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.setdefault('data', {})['textbooks'] = textbooks
|
||||
definition['data']['wiki_slug'] = wiki_slug
|
||||
|
||||
return definition
|
||||
|
||||
def has_started(self):
|
||||
@@ -197,6 +210,19 @@ class CourseDescriptor(SequenceDescriptor):
|
||||
def start_date_text(self):
|
||||
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
|
||||
def title(self):
|
||||
return self.display_name
|
||||
@@ -205,10 +231,6 @@ class CourseDescriptor(SequenceDescriptor):
|
||||
def number(self):
|
||||
return self.location.course
|
||||
|
||||
@property
|
||||
def wiki_slug(self):
|
||||
return self.location.course
|
||||
|
||||
@property
|
||||
def org(self):
|
||||
return self.location.org
|
||||
|
||||
@@ -15,18 +15,39 @@ from xmodule.errortracker import exc_info_to_str
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# NOTE: This is not the most beautiful design in the world, but there's no good
|
||||
# way to tell if the module is being used in a staff context or not. Errors that get discovered
|
||||
# at course load time are turned into ErrorDescriptor objects, and automatically hidden from students.
|
||||
# Unfortunately, we can also have errors when loading modules mid-request, and then we need to decide
|
||||
# what to show, and the logic for that belongs in the LMS (e.g. in get_module), so the error handler
|
||||
# decides whether to create a staff or not-staff module.
|
||||
|
||||
class ErrorModule(XModule):
|
||||
def get_html(self):
|
||||
'''Show an error.
|
||||
'''Show an error to staff.
|
||||
TODO (vshnayder): proper style, divs, etc.
|
||||
'''
|
||||
# staff get to see all the details
|
||||
return self.system.render_template('module-error.html', {
|
||||
'staff_access' : True,
|
||||
'data' : self.definition['data']['contents'],
|
||||
'error' : self.definition['data']['error_msg'],
|
||||
})
|
||||
|
||||
|
||||
class NonStaffErrorModule(XModule):
|
||||
def get_html(self):
|
||||
'''Show an error to a student.
|
||||
TODO (vshnayder): proper style, divs, etc.
|
||||
'''
|
||||
# staff get to see all the details
|
||||
return self.system.render_template('module-error.html', {
|
||||
'staff_access' : False,
|
||||
'data' : "",
|
||||
'error' : "",
|
||||
})
|
||||
|
||||
|
||||
class ErrorDescriptor(EditingDescriptor):
|
||||
"""
|
||||
Module that provides a raw editing view of broken xml.
|
||||
@@ -99,3 +120,9 @@ class ErrorDescriptor(EditingDescriptor):
|
||||
err_node = etree.SubElement(root, 'error_msg')
|
||||
err_node.text = self.definition['data']['error_msg']
|
||||
return etree.tostring(root)
|
||||
|
||||
class NonStaffErrorDescriptor(ErrorDescriptor):
|
||||
"""
|
||||
Module that provides non-staff error messages.
|
||||
"""
|
||||
module_class = NonStaffErrorModule
|
||||
|
||||
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)
|
||||
@@ -5,6 +5,7 @@ from django.http import Http404
|
||||
from django.shortcuts import redirect
|
||||
|
||||
from wiki.models import reverse as wiki_reverse
|
||||
from courseware.access import has_access
|
||||
from courseware.courses import get_course_with_access
|
||||
|
||||
|
||||
@@ -135,7 +136,9 @@ def context_processor(request):
|
||||
|
||||
try:
|
||||
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:
|
||||
# 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
|
||||
|
||||
@@ -80,8 +80,8 @@ def course_wiki_redirect(request, course_id):
|
||||
urlpath = URLPath.create_article(
|
||||
root,
|
||||
course_slug,
|
||||
title=course.number,
|
||||
content="{0}\n===\nThis is the wiki for **{1}**'s _{2}_.".format(course.number, course.org, course.title),
|
||||
title=course_slug,
|
||||
content="This is the wiki for **{0}**'s _{1}_.".format(course.org, course.title),
|
||||
user_message="Course page automatically created.",
|
||||
user=None,
|
||||
ip_address=None,
|
||||
@@ -114,7 +114,7 @@ def get_or_create_root():
|
||||
"===",
|
||||
"Visit a course wiki to add an article."))
|
||||
|
||||
root = URLPath.create_root(title="edX Wiki",
|
||||
root = URLPath.create_root(title="Wiki",
|
||||
content=starting_content)
|
||||
article = root.article
|
||||
article.group = None
|
||||
|
||||
@@ -13,7 +13,6 @@ from xmodule.modulestore import Location
|
||||
from xmodule.timeparse import parse_time
|
||||
from xmodule.x_module import XModule, XModuleDescriptor
|
||||
|
||||
|
||||
DEBUG_ACCESS = False
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
@@ -15,10 +16,12 @@ from courseware.access import has_access
|
||||
from mitxmako.shortcuts import render_to_string
|
||||
from models import StudentModule, StudentModuleCache
|
||||
from static_replace import replace_urls
|
||||
from xmodule.errortracker import exc_info_to_str
|
||||
from xmodule.exceptions import NotFoundError
|
||||
from xmodule.modulestore import Location
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.x_module import ModuleSystem
|
||||
from xmodule.error_module import ErrorDescriptor, NonStaffErrorDescriptor
|
||||
from xmodule_modifiers import replace_course_urls, replace_static_urls, add_histogram, wrap_xmodule
|
||||
|
||||
log = logging.getLogger("mitx.courseware")
|
||||
@@ -73,6 +76,8 @@ def toc_for_course(user, request, course, active_chapter, active_section, course
|
||||
student_module_cache = StudentModuleCache.cache_for_descriptor_descendents(
|
||||
course_id, user, course, depth=2)
|
||||
course = get_module(user, request, course.location, student_module_cache, course_id)
|
||||
if course is None:
|
||||
return None
|
||||
|
||||
chapters = list()
|
||||
for chapter in course.get_display_items():
|
||||
@@ -131,9 +136,9 @@ def get_section(course_module, chapter, section):
|
||||
|
||||
return section_module
|
||||
|
||||
|
||||
def get_module(user, request, location, student_module_cache, course_id, position=None):
|
||||
''' Get an instance of the xmodule class identified by location,
|
||||
"""
|
||||
Get an instance of the xmodule class identified by location,
|
||||
setting the state based on an existing StudentModule, or creating one if none
|
||||
exists.
|
||||
|
||||
@@ -146,9 +151,22 @@ def get_module(user, request, location, student_module_cache, course_id, positio
|
||||
- position : extra information from URL for user-specified
|
||||
position within module
|
||||
|
||||
Returns: xmodule instance
|
||||
Returns: xmodule instance, or None if the user does not have access to the
|
||||
module. If there's an error, will try to return an instance of ErrorModule
|
||||
if possible. If not possible, return None.
|
||||
"""
|
||||
try:
|
||||
return _get_module(user, request, location, student_module_cache, course_id, position)
|
||||
except:
|
||||
# Something has gone terribly wrong, but still not letting it turn into a 500.
|
||||
log.exception("Error in get_module")
|
||||
return None
|
||||
|
||||
'''
|
||||
def _get_module(user, request, location, student_module_cache, course_id, position=None):
|
||||
"""
|
||||
Actually implement get_module. See docstring there for details.
|
||||
"""
|
||||
location = Location(location)
|
||||
descriptor = modulestore().get_instance(course_id, location)
|
||||
|
||||
# Short circuit--if the user shouldn't have access, bail without doing any work
|
||||
@@ -198,7 +216,7 @@ def get_module(user, request, location, student_module_cache, course_id, positio
|
||||
'callback_url': xqueue_callback_url,
|
||||
'default_queuename': xqueue_default_queuename.replace(' ', '_')}
|
||||
|
||||
def _get_module(location):
|
||||
def inner_get_module(location):
|
||||
"""
|
||||
Delegate to get_module. It does an access check, so may return None
|
||||
"""
|
||||
@@ -214,7 +232,7 @@ def get_module(user, request, location, student_module_cache, course_id, positio
|
||||
xqueue=xqueue,
|
||||
# TODO (cpennington): Figure out how to share info between systems
|
||||
filestore=descriptor.system.resources_fs,
|
||||
get_module=_get_module,
|
||||
get_module=inner_get_module,
|
||||
user=user,
|
||||
# TODO (cpennington): This should be removed when all html from
|
||||
# a module is coming through get_html and is therefore covered
|
||||
@@ -226,7 +244,22 @@ def get_module(user, request, location, student_module_cache, course_id, positio
|
||||
system.set('position', position)
|
||||
system.set('DEBUG', settings.DEBUG)
|
||||
|
||||
module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
|
||||
try:
|
||||
module = descriptor.xmodule_constructor(system)(instance_state, shared_state)
|
||||
except:
|
||||
log.exception("Error creating module from descriptor {0}".format(descriptor))
|
||||
|
||||
# make an ErrorDescriptor -- assuming that the descriptor's system is ok
|
||||
import_system = descriptor.system
|
||||
if has_access(user, location, 'staff'):
|
||||
err_descriptor = ErrorDescriptor.from_xml(str(descriptor), import_system,
|
||||
error_msg=exc_info_to_str(sys.exc_info()))
|
||||
else:
|
||||
err_descriptor = NonStaffErrorDescriptor.from_xml(str(descriptor), import_system,
|
||||
error_msg=exc_info_to_str(sys.exc_info()))
|
||||
|
||||
# Make an error module
|
||||
return err_descriptor.xmodule_constructor(system)(None, None)
|
||||
|
||||
module.get_html = replace_static_urls(
|
||||
wrap_xmodule(module.get_html, module, 'xmodule_display.html'),
|
||||
|
||||
@@ -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': {
|
||||
@@ -318,6 +328,7 @@ WIKI_ACCOUNT_HANDLING = False
|
||||
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_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_TEST_DIRECTORY = PROJECT_ROOT + '/static/coffee'
|
||||
|
||||
@@ -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 |
@@ -100,13 +100,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 {
|
||||
@@ -143,4 +136,4 @@ header.global.slim {
|
||||
font-weight: bold;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,17 @@ section.wiki {
|
||||
font-size: 0.9em;
|
||||
font-family: Monaco, monospace;
|
||||
}
|
||||
|
||||
.toc {
|
||||
background-color: $sidebar-color;
|
||||
padding: 9px;
|
||||
margin: 10px 0;
|
||||
@include border-radius(5px);
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +231,7 @@ section.wiki {
|
||||
padding: 40px 40px;
|
||||
@include box-sizing(border-box);
|
||||
|
||||
.timestamp {
|
||||
.timestamp{
|
||||
margin-top: 15px;
|
||||
padding: 15px 0 0 10px;
|
||||
border-top: 1px solid $light-gray;
|
||||
@@ -234,6 +245,26 @@ section.wiki {
|
||||
.date {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,6 +694,59 @@ section.wiki {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -788,6 +872,39 @@ section.wiki {
|
||||
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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%inherit file="/main.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="headextra">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -2,10 +2,19 @@
|
||||
<h1>There has been an error on the <em>MITx</em> servers</h1>
|
||||
<p>We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible. Please email us at <a href="mailto:technical@mitx.mit.edu">technical@mitx.mit.edu</a> to report any problems or downtime.</p>
|
||||
|
||||
<h1>Details below:</h1>
|
||||
% if staff_access:
|
||||
<h1>Details</h1>
|
||||
|
||||
<p>Error: ${error | h}</p>
|
||||
<p>Error:
|
||||
<pre>
|
||||
${error | h}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<p>Raw data: ${data | h}</p>
|
||||
<p>Raw data:
|
||||
|
||||
<pre>${data | h}</pre>
|
||||
</p>
|
||||
|
||||
% endif
|
||||
</section>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -31,9 +31,12 @@ ${module_content}
|
||||
<header>
|
||||
<h2>Staff Debug</h2>
|
||||
</header>
|
||||
<div class="staff_info">
|
||||
<div class="staff_info" style="display:block">
|
||||
location = ${location | h}
|
||||
github = <a href="${edit_link}">${edit_link | h}</a>
|
||||
%if source_file:
|
||||
source_url = <a href="${source_url}">${source_file | h}</a>
|
||||
%endif
|
||||
definition = <pre>${definition | h}</pre>
|
||||
metadata = ${metadata | h}
|
||||
category = ${category | h}
|
||||
|
||||
@@ -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>
|
||||
@@ -11,18 +11,19 @@
|
||||
{% block wiki_contents %}
|
||||
|
||||
<div class="article-wrapper">
|
||||
|
||||
|
||||
<article class="main-article">
|
||||
{% if selected_tab != "edit" %}
|
||||
<h1>{{ article.current_revision.title }}</h1>
|
||||
<h1>{{ article.current_revision.title }}</h1>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% block wiki_contents_tab %}
|
||||
{% wiki_render article %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
</article>
|
||||
|
||||
<div class="article-functions">
|
||||
<div class="article-functions">
|
||||
<ul class="nav nav-tabs">
|
||||
{% include "wiki/includes/article_menu.html" %}
|
||||
</ul>
|
||||
@@ -30,6 +31,12 @@
|
||||
<span class="label">{% trans "Last modified:" %}</span><br />
|
||||
<span class="date">{{ article.current_revision.modified }}</span>
|
||||
</div>
|
||||
|
||||
{% if urlpath %}
|
||||
<div class="see-children">
|
||||
<a href="{% url 'wiki:dir' path=urlpath.path %}">See all children</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
{% 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 @@
|
||||
%endif
|
||||
%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():
|
||||
<li class="${"active" if selected_tab == "settings" else ""}">
|
||||
<a href="${reverse('wiki:settings', kwargs={'article_id' : article.id, 'path' : urlpath.path})}">
|
||||
@@ -43,4 +47,6 @@
|
||||
</a>
|
||||
</li>
|
||||
%endif
|
||||
</%doc>
|
||||
|
||||
|
||||
|
||||
@@ -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 %}
|
||||
</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>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -10,22 +10,31 @@
|
||||
<div class="main-article">
|
||||
{% if revision %}
|
||||
<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>
|
||||
{% endif %}
|
||||
|
||||
{% if merge %}
|
||||
<div class="alert alert-info">
|
||||
<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>
|
||||
{{ 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>
|
||||
{% endif %}
|
||||
|
||||
<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>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
{% 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 %}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{% 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:
|
||||
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"),
|
||||
|
||||
|
||||
2
rakefile
2
rakefile
@@ -200,6 +200,8 @@ task :package do
|
||||
"--exclude=**/.git/**",
|
||||
"--exclude=**/*.pyc",
|
||||
"--exclude=**/reports/**",
|
||||
"--exclude=**/test_root/**",
|
||||
"--exclude=**/.coverage/**",
|
||||
"-C", "#{REPO_ROOT}",
|
||||
"--provides=#{PACKAGE_NAME}",
|
||||
"--name=#{NORMALIZED_DEPLOY_NAME}",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-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/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 common/lib/capa
|
||||
-e common/lib/xmodule
|
||||
|
||||
@@ -2,7 +2,7 @@ django>=1.4,<1.5
|
||||
pip
|
||||
numpy
|
||||
scipy
|
||||
markdown
|
||||
Markdown<2.3.0
|
||||
pygments
|
||||
lxml
|
||||
boto
|
||||
@@ -43,5 +43,7 @@ django-ses
|
||||
django-storages
|
||||
django-threaded-multihost
|
||||
django-sekizai<0.7
|
||||
django-mptt>=0.5.3
|
||||
sorl-thumbnail
|
||||
networkx
|
||||
-r repo-requirements.txt
|
||||
|
||||
Reference in New Issue
Block a user