Commit 3632f6a7 by pmitros

Merge pull request #49 from MITx/specific-error-handling

Specific error handling
parents 5c82af3a 9859e854
import logging import logging
import urllib import urllib
import json
from django.conf import settings from django.conf import settings
from django.core.context_processors import csrf from django.core.context_processors import csrf
...@@ -16,6 +17,8 @@ from lxml import etree ...@@ -16,6 +17,8 @@ from lxml import etree
from module_render import render_module, make_track_function, I4xSystem from module_render import render_module, make_track_function, I4xSystem
from models import StudentModule from models import StudentModule
from student.models import UserProfile from student.models import UserProfile
from util.errors import record_exception
from util.views import accepts
from multicourse import multicourse_settings from multicourse import multicourse_settings
import courseware.content_parser as content_parser import courseware.content_parser as content_parser
...@@ -110,12 +113,16 @@ def render_section(request, section): ...@@ -110,12 +113,16 @@ def render_section(request, section):
if 'coursename' in request.session: coursename = request.session['coursename'] if 'coursename' in request.session: coursename = request.session['coursename']
else: coursename = None else: coursename = None
# try: try:
dom = content_parser.section_file(user, section, coursename) dom = content_parser.section_file(user, section, coursename)
#except: except:
# raise Http404 record_exception(log, "Unable to parse courseware xml")
return render_to_response('courseware-error.html', {})
accordion=render_accordion(request, '', '', '') context = {
'csrf': csrf(request)['csrf_token'],
'accordion': render_accordion(request, '', '', '')
}
module_ids = dom.xpath("//@id") module_ids = dom.xpath("//@id")
...@@ -125,15 +132,20 @@ def render_section(request, section): ...@@ -125,15 +132,20 @@ def render_section(request, section):
else: else:
module_object_preload = [] module_object_preload = []
module=render_module(user, request, dom, module_object_preload) try:
module = render_module(user, request, dom, module_object_preload)
if 'init_js' not in module: except:
module['init_js']='' record_exception(log, "Unable to load module")
context.update({
context={'init':module['init_js'], 'init': '',
'accordion':accordion, 'content': render_to_string("module-error.html", {}),
'content':module['content'], })
'csrf':csrf(request)['csrf_token']} return render_to_response('courseware.html', context)
context.update({
'init':module.get('init_js', ''),
'content':module['content'],
})
result = render_to_response('courseware.html', context) result = render_to_response('courseware.html', context)
return result return result
...@@ -167,22 +179,22 @@ def index(request, course=None, chapter="Using the System", section="Hints"): ...@@ -167,22 +179,22 @@ def index(request, course=None, chapter="Using the System", section="Hints"):
if not multicourse_settings.is_valid_course(course): if not multicourse_settings.is_valid_course(course):
return redirect('/') return redirect('/')
#import logging
#log = logging.getLogger("mitx")
#log.info( "DEBUG: "+str(user) )
request.session['coursename'] = course # keep track of current course being viewed in django's request.session request.session['coursename'] = course # keep track of current course being viewed in django's request.session
dom = content_parser.course_file(user,course) # also pass course to it, for course-specific XML path try:
dom = content_parser.course_file(user,course) # also pass course to it, for course-specific XML path
except:
record_exception(log, "Unable to parse courseware xml")
return render_to_response('courseware-error.html', {})
dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]", dom_module = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]/*[1]",
course=course, chapter=chapter, section=section) course=course, chapter=chapter, section=section)
if len(dom_module) == 0: if len(dom_module) == 0:
module = None module = None
else: else:
module = dom_module[0] module = dom_module[0]
accordion=render_accordion(request, course, chapter, section)
module_ids = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]//@id", module_ids = dom.xpath("//course[@name=$course]/chapter[@name=$chapter]//section[@name=$section]//@id",
course=course, chapter=chapter, section=section) course=course, chapter=chapter, section=section)
...@@ -191,18 +203,27 @@ def index(request, course=None, chapter="Using the System", section="Hints"): ...@@ -191,18 +203,27 @@ def index(request, course=None, chapter="Using the System", section="Hints"):
module_id__in=module_ids)) module_id__in=module_ids))
else: else:
module_object_preload = [] module_object_preload = []
module=render_module(user, request, module, module_object_preload)
if 'init_js' not in module: context = {
module['init_js']='' 'csrf': csrf(request)['csrf_token'],
'accordion': render_accordion(request, course, chapter, section),
context={'init':module['init_js'], 'COURSE_TITLE':multicourse_settings.get_course_title(course),
'accordion':accordion, }
'content':module['content'],
'COURSE_TITLE':multicourse_settings.get_course_title(course), try:
'csrf':csrf(request)['csrf_token']} module = render_module(user, request, module, module_object_preload)
except:
record_exception(log, "Unable to load module")
context.update({
'init': '',
'content': render_to_string("module-error.html", {}),
})
return render_to_response('courseware.html', context)
context.update({
'init': module.get('init_js', ''),
'content': module['content'],
})
result = render_to_response('courseware.html', context) result = render_to_response('courseware.html', context)
return result return result
...@@ -234,7 +255,15 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ...@@ -234,7 +255,15 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
else: coursename = None else: coursename = None
# Grab the XML corresponding to the request from course.xml # Grab the XML corresponding to the request from course.xml
xml = content_parser.module_xml(request.user, module, 'id', id, coursename) try:
xml = content_parser.module_xml(request.user, module, 'id', id, coursename)
except:
record_exception(log, "Unable to load module during ajax call")
if accepts(request, 'text/html'):
return render_to_response("module-error.html", {})
else:
response = HttpResponse(json.dumps({'success': "We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible"}))
return response
# Create the module # Create the module
system = I4xSystem(track_function = make_track_function(request), system = I4xSystem(track_function = make_track_function(request),
...@@ -242,10 +271,20 @@ def modx_dispatch(request, module=None, dispatch=None, id=None): ...@@ -242,10 +271,20 @@ def modx_dispatch(request, module=None, dispatch=None, id=None):
ajax_url = ajax_url, ajax_url = ajax_url,
filestore = None filestore = None
) )
instance=courseware.modules.get_module_class(module)(system,
xml, try:
id, instance=courseware.modules.get_module_class(module)(system,
state=oldstate) xml,
id,
state=oldstate)
except:
record_exception(log, "Unable to load module instance during ajax call")
if accepts(request, 'text/html'):
return render_to_response("module-error.html", {})
else:
response = HttpResponse(json.dumps({'success': "We're sorry, this module is temporarily unavailable. Our staff is working to fix it as soon as possible"}))
return response
# Let the module handle the AJAX # Let the module handle the AJAX
ajax_return=instance.handle_ajax(dispatch, request.POST) ajax_return=instance.handle_ajax(dispatch, request.POST)
# Save the state back to the database # Save the state back to the database
......
...@@ -79,6 +79,7 @@ TEMPLATE_DIRS = ( ...@@ -79,6 +79,7 @@ TEMPLATE_DIRS = (
TEMPLATE_CONTEXT_PROCESSORS = ( TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.request', 'django.core.context_processors.request',
'django.core.context_processors.static',
'askbot.context.application_settings', 'askbot.context.application_settings',
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
#'django.core.context_processors.i18n', #'django.core.context_processors.i18n',
...@@ -105,6 +106,20 @@ DEV_CONTENT = True ...@@ -105,6 +106,20 @@ DEV_CONTENT = True
TRACK_MAX_EVENT = 10000 TRACK_MAX_EVENT = 10000
DEBUG_TRACK_LOG = False DEBUG_TRACK_LOG = False
MITX_ROOT_URL = ''
COURSE_NAME = "6.002_Spring_2012"
COURSE_NUMBER = "6.002x"
COURSE_TITLE = "Circuits and Electronics"
ROOT_URLCONF = 'urls'
### Dark code. Should be enabled in local settings for devel.
ENABLE_MULTICOURSE = False # set to False to disable multicourse display (see lib.util.views.mitxhome)
###
############################### DJANGO BUILT-INS ############################### ############################### DJANGO BUILT-INS ###############################
# Change DEBUG/TEMPLATE_DEBUG in your environment settings files, not here # Change DEBUG/TEMPLATE_DEBUG in your environment settings files, not here
DEBUG = False DEBUG = False
...@@ -159,14 +174,22 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage' ...@@ -159,14 +174,22 @@ MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years AWS_QUERYSTRING_EXPIRE = 10 * 365 * 24 * 60 * 60 # 10 years
################################### ASKBOT ##################################### ################################### ASKBOT #####################################
LIVESETTINGS_OPTIONS['MITX_ROOT_URL'] = MITX_ROOT_URL
skin_settings = LIVESETTINGS_OPTIONS[1]['SETTINGS']['GENERAL_SKIN_SETTINGS']
skin_settings['SITE_FAVICON'] = unicode(MITX_ROOT_URL) + skin_settings['SITE_FAVICON']
skin_settings['SITE_LOGO_URL'] = unicode(MITX_ROOT_URL) + skin_settings['SITE_LOGO_URL']
skin_settings['LOCAL_LOGIN_ICON'] = unicode(MITX_ROOT_URL) + skin_settings['LOCAL_LOGIN_ICON']
LIVESETTINGS_OPTIONS[1]['SETTINGS']['LOGIN_PROVIDERS']['WORDPRESS_SITE_ICON'] = unicode(MITX_ROOT_URL) + LIVESETTINGS_OPTIONS[1]['SETTINGS']['LOGIN_PROVIDERS']['WORDPRESS_SITE_ICON']
LIVESETTINGS_OPTIONS[1]['SETTINGS']['LICENSE_SETTINGS']['LICENSE_LOGO_URL'] = unicode(MITX_ROOT_URL) + LIVESETTINGS_OPTIONS[1]['SETTINGS']['LICENSE_SETTINGS']['LICENSE_LOGO_URL']
ASKBOT_EXTRA_SKINS_DIR = ASKBOT_ROOT / "askbot" / "skins" ASKBOT_EXTRA_SKINS_DIR = ASKBOT_ROOT / "askbot" / "skins"
ASKBOT_ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff') ASKBOT_ALLOWED_UPLOAD_FILE_TYPES = ('.jpg', '.jpeg', '.gif', '.bmp', '.png', '.tiff')
ASKBOT_MAX_UPLOAD_FILE_SIZE = 1024 * 1024 # result in bytes ASKBOT_MAX_UPLOAD_FILE_SIZE = 1024 * 1024 # result in bytes
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
ASKBOT_URL = 'discussion/' ASKBOT_URL = 'discussion/'
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = MITX_ROOT_URL + '/'
LOGIN_URL = '/' LOGIN_URL = MITX_ROOT_URL + '/'
ALLOW_UNICODE_SLUGS = False ALLOW_UNICODE_SLUGS = False
ASKBOT_USE_STACKEXCHANGE_URLS = False # mimic url scheme of stackexchange ASKBOT_USE_STACKEXCHANGE_URLS = False # mimic url scheme of stackexchange
...@@ -181,6 +204,9 @@ djcelery.setup_loader() ...@@ -181,6 +204,9 @@ djcelery.setup_loader()
SIMPLE_WIKI_REQUIRE_LOGIN_EDIT = True SIMPLE_WIKI_REQUIRE_LOGIN_EDIT = True
SIMPLE_WIKI_REQUIRE_LOGIN_VIEW = False SIMPLE_WIKI_REQUIRE_LOGIN_VIEW = False
################################# Jasmine ###################################
JASMINE_TEST_DIRECTORY = PROJECT_ROOT + '/templates/coffee'
################################# Middleware ################################### ################################# Middleware ###################################
# List of finder classes that know how to find static files in # List of finder classes that know how to find static files in
# various locations. # various locations.
...@@ -199,6 +225,7 @@ TEMPLATE_LOADERS = ( ...@@ -199,6 +225,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'util.middleware.ExceptionLoggingMiddleware', 'util.middleware.ExceptionLoggingMiddleware',
'util.middleware.AcceptMiddleware',
'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
...@@ -245,6 +272,9 @@ INSTALLED_APPS = ( ...@@ -245,6 +272,9 @@ INSTALLED_APPS = (
'track', 'track',
'util', 'util',
# For testing
'django_jasmine',
# For Askbot # For Askbot
'django.contrib.sitemaps', 'django.contrib.sitemaps',
'django.contrib.admin', 'django.contrib.admin',
......
...@@ -10,8 +10,8 @@ sessions. Assumes structure: ...@@ -10,8 +10,8 @@ sessions. Assumes structure:
from envs.common import * from envs.common import *
from envs.logsettings import get_logger_config from envs.logsettings import get_logger_config
DEBUG = True DEBUG = False
TEMPLATE_DEBUG = True TEMPLATE_DEBUG = False
LOGGING = get_logger_config(ENV_ROOT / "log", LOGGING = get_logger_config(ENV_ROOT / "log",
logging_env="dev", logging_env="dev",
......
import newrelic.agent
import sys
def record_exception(logger, msg, params={}, ignore_errors=[]):
logger.exception(msg)
newrelic.agent.record_exception(*sys.exc_info())
...@@ -13,3 +13,4 @@ class ExceptionLoggingMiddleware(object): ...@@ -13,3 +13,4 @@ class ExceptionLoggingMiddleware(object):
def process_exception(self, request, exception): def process_exception(self, request, exception):
log.exception(exception) log.exception(exception)
return HttpResponseServerError("Server Error - Please try again later.") return HttpResponseServerError("Server Error - Please try again later.")
...@@ -66,3 +66,29 @@ def mitxhome(request): ...@@ -66,3 +66,29 @@ def mitxhome(request):
if settings.ENABLE_MULTICOURSE: if settings.ENABLE_MULTICOURSE:
return render_to_response("mitxhome.html", {}) return render_to_response("mitxhome.html", {})
return info(request) return info(request)
# From http://djangosnippets.org/snippets/1042/
def parse_accept_header(accept):
"""Parse the Accept header *accept*, returning a list with pairs of
(media_type, q_value), ordered by q values.
"""
result = []
for media_range in accept.split(","):
parts = media_range.split(";")
media_type = parts.pop(0)
media_params = []
q = 1.0
for part in parts:
(key, value) = part.lstrip().split("=", 1)
if key == "q":
q = float(value)
else:
media_params.append((key, value))
result.append((media_type, tuple(media_params), q))
result.sort(lambda x, y: -cmp(x[2], y[2]))
return result
def accepts(request, media_type):
"""Return whether this request has an Accept header that matches type"""
accept = parse_accept_header(request.META.get("HTTP_ACCEPT", ""))
return media_type in [t for (t, p, q) in accept]
...@@ -133,6 +133,7 @@ TEMPLATE_LOADERS = ( ...@@ -133,6 +133,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'util.middleware.ExceptionLoggingMiddleware', 'util.middleware.ExceptionLoggingMiddleware',
'util.middleware.AcceptMiddleware',
'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
......
<%inherit file="main.html" />
<%block name="bodyclass">courseware</%block>
<%block name="title"><title>Courseware – MITx 6.002x</title></%block>
<%include file="navigation.html" args="active_page='courseware'" />
<section class="main-content">
<section class="outside-app">
<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>
</section>
</section>
<section class="outside-app">
<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>
</section>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment