Permalink
Browse files

catch extensions or themes unavailable to compiler, before compiling

if you set settings.MEDIA_ROOT to a relative path, it's possible that
the Numbas compiler won't be able to find the file.
The CompileObject view now checks that the paths to extensions and the
selected theme exist before calling the compiler.
Extension and theme paths are made relative to the editor's working directory
(unless MEDIA_ROOT is set to an absolute path, as the documentation
 recommends)

This all works to catch the cases when:
 - an extension file that should exist but doesn't
 - MEDIA_ROOT is set to a path relative to the editor working directory

and throw a sensible error message rather than silently fail.

Thanks to Stuart Simpson for bringing this to my attention.
  • Loading branch information...
1 parent 593c40e commit a4ebdab639fb0700b72c4f306ad832f642f4797c @christianp christianp committed Dec 1, 2016
Showing with 20 additions and 7 deletions.
  1. +2 −2 editor/models.py
  2. +12 −4 editor/templates/compile/error.html
  3. +6 −1 editor/views/editoritem.py
View
@@ -328,7 +328,7 @@ def __unicode__(self):
@property
def extracted_path(self):
- return os.path.join(settings.MEDIA_ROOT,self.zipfile_folder,'extracted',str(self.pk))
+ return os.path.join(settings.GLOBAL_SETTINGS['NUMBAS_PATH'],settings.MEDIA_ROOT,self.zipfile_folder,'extracted',str(self.pk))
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
@@ -1080,7 +1080,7 @@ def theme_path(self):
if self.custom_theme:
return self.custom_theme.extracted_path
else:
- return self.theme
+ return os.path.join(settings.GLOBAL_SETTINGS['NUMBAS_PATH'],'themes',self.theme)
@property
def as_numbasobject(self):
@@ -1,15 +1,23 @@
{% extends "base.html" %}
{% block title %}Compilation Error{% endblock %}
{% block body %}
+<div class="container">
<div class="page-header">
<h1 class="text-warning">Compilation Error</h1>
</div>
+ <p><small>Attempted to compile at {% now "Y-m-d H:i:s" %}</small></p>
{% autoescape on %}
- <p id="message">{{message}} (code {{code}})</p>
+ <p id="message">{{message}}</p>
+ {% if stderr %}
<h3>STDERR</h3>
- <pre id="stderr"><code>{{stderr}}</code></pre>
+ <pre id="stderr"><code>{{stderr}}</code></pre>
+ {% endif %}
+ {% if stdout %}
<h3>STDOUT</h3>
- <pre id="stdout"><code>{{stdout}}</code></pre>
- {% endautoescape %}
+ <pre id="stdout"><code>{{stdout}}</code></pre>
+ {% endif %}
+ {% endautoescape %}
+ <button class="btn btn-primary" onclick="window.location.reload()">Try again</button>
+</div>
{% endblock %}
@@ -400,10 +400,15 @@ def compile(self,numbasobject,switches,location,obj,locale='en-GB'):
Returns the path to the output produced
"""
- numbasobject.data['extensions'] = [e.extracted_path for e in editor.models.Extension.objects.filter(location__in=numbasobject.data.get('extensions',[]))]
+ numbasobject.data['extensions'] = [os.path.join(os.getcwd(),e.extracted_path) for e in editor.models.Extension.objects.filter(location__in=numbasobject.data.get('extensions',[]))]
+ for extracted_path in numbasobject.data['extensions']:
+ if not os.path.exists(extracted_path):
+ raise CompileError("Extension not found at {}. Is MEDIA_ROOT configured correctly? It should be the absolute path to your editor media directory.".format(extracted_path))
source = str(numbasobject)
theme_path = obj.theme_path if hasattr(obj,'theme_path') else 'default'
+ if not os.path.exists(theme_path):
+ raise CompileError("Theme not found at {}. Is MEDIA_ROOT configured correctly? It should be the absolute path to your editor media directory.".format(theme_path))
output_location = os.path.join(settings.GLOBAL_SETTINGS['PREVIEW_PATH'], location)
numbas_command = [

0 comments on commit a4ebdab

Please sign in to comment.