22
22
# Provides the AJAX backend for the tutorial application.
23
23
# This allows several actions to be performed on the code the student has
24
# typed into one of the problem boxes.
24
# typed into one of the exercise boxes.
27
27
# Path must be empty.
28
28
# The arguments determine what is to be done on this file.
30
# "problem" - The path to a problem file (including the .xml extension),
30
# "exercise" - The path to a exercise file (including the .xml extension),
31
31
# relative to the subjects base directory.
32
32
# "code" - Full text of the student's code being submitted.
33
33
# "action". May be "test". (More to come).
53
53
# side-effects on the server.
54
54
fields = req.get_fieldstorage()
55
55
act = fields.getfirst('action')
56
problem = fields.getfirst('problem')
56
exercise = fields.getfirst('exercise')
57
57
code = fields.getfirst('code')
59
if problem == None or code == None or act == None:
59
if exercise == None or code == None or act == None:
60
60
req.throw_error(req.HTTP_BAD_REQUEST)
62
problem = problem.value
62
exercise = exercise.value
66
handle_test(req, problem, code, fields)
66
handle_test(req, exercise, code, fields)
68
handle_run(req, problem, code, fields)
68
handle_run(req, exercise, code, fields)
70
70
req.throw_error(req.HTTP_BAD_REQUEST)
72
def handle_test(req, problem, code, fields):
72
def handle_test(req, exercise, code, fields):
73
73
"""Handles a test action."""
75
75
# First normalise the path
76
problem = os.path.normpath(problem)
76
exercise = os.path.normpath(exercise)
77
77
# Now if it begins with ".." or separator, then it's illegal
78
if problem.startswith("..") or problem.startswith(os.sep):
78
if exercise.startswith("..") or exercise.startswith(os.sep):
81
problemfile = os.path.join(conf.problems_base, problem)
81
exercisefile = os.path.join(conf.exercises_base, exercise)
84
problemfile = open(problemfile)
85
except (TypeError, IOError): # TypeError if problemfile == None
84
exercisefile = open(exercisefile)
85
except (TypeError, IOError): # TypeError if exercisefile == None
86
86
req.throw_error(req.HTTP_NOT_FOUND)
88
# Parse the file into a problem object using the test suite
89
problem_obj = test.parse_exercise_file(problemfile)
88
# Parse the file into a exercise object using the test suite
89
exercise_obj = test.parse_exercise_file(exercisefile)
91
91
# Run the test cases. Get the result back as a JSONable object.
93
test_results = problem_obj.run_tests(code)
93
test_results = exercise_obj.run_tests(code)
94
94
req.write(cjson.encode(test_results))
96
def handle_run(req, problem, code, fields):
96
def handle_run(req, exercise, code, fields):
97
97
"""Handles a run action."""
98
98
# Extremely makeshift.
99
99
# For now, just echo the code back