~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/webapp/tutorial/service.py

ivle.webapp.groups: Remove most of the view code; the template now accesses
    the objects directly. Also fix a few double-encodings and typos.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# IVLE - Informatics Virtual Learning Environment
2
 
# Copyright (C) 2007-2009 The University of Melbourne
 
2
# Copyright (C) 2007-2008 The University of Melbourne
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
5
5
# it under the terms of the GNU General Public License as published by
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
17
 
18
 
# Author: Matt Giuca, Nick Chadwick
19
 
 
20
 
'''AJAX backend for the tutorial application.'''
 
18
# Module: TutorialService
 
19
# Author: Matt Giuca
 
20
# Date:   25/1/2008
 
21
 
 
22
# Provides the AJAX backend for the tutorial application.
 
23
# This allows several actions to be performed on the code the student has
 
24
# typed into one of the exercise boxes.
 
25
 
 
26
# Calling syntax
 
27
# Path must be empty.
 
28
# The arguments determine what is to be done on this file.
 
29
 
 
30
# "action". One of the tutorialservice actions.
 
31
# "exercise" - The path to a exercise file (including the .xml extension),
 
32
#              relative to the subjects base directory.
 
33
# action "save" or "test" (POST only):
 
34
#   "code" - Full text of the student's code being submitted.
 
35
# action "getattempts": No arguments. Returns a list of
 
36
#   {'date': 'formatted_date', 'complete': bool} dicts.
 
37
# action "getattempt":
 
38
#   "date" - Formatted date. Gets most recent attempt before (and including)
 
39
#   that date.
 
40
#   Returns JSON string containing code, or null.
 
41
 
 
42
# Returns a JSON response string indicating the results.
21
43
 
22
44
import os
 
45
import time
23
46
import datetime
24
47
 
25
 
import ivle.util
26
 
import ivle.console
 
48
import cjson
 
49
 
 
50
from ivle import util
 
51
from ivle import console
27
52
import ivle.database
28
53
import ivle.worksheet
29
54
import ivle.conf
30
 
import ivle.webapp.tutorial.test
 
55
import test # XXX: Really .test, not real test.
31
56
 
32
 
from ivle.webapp.base.rest import (JSONRESTView, named_operation,
33
 
                                   require_permission)
34
 
from ivle.webapp.errors import NotFound
 
57
from ivle.webapp.base.rest import JSONRESTView
 
58
import ivle.database
 
59
from ivle.webapp.base.rest import named_operation
35
60
 
36
61
# If True, getattempts or getattempt will allow browsing of inactive/disabled
37
62
# attempts. If False, will not allow this.
41
66
 
42
67
 
43
68
class AttemptsRESTView(JSONRESTView):
44
 
    '''REST view of a user's attempts at an exercise.'''
45
 
    def __init__(self, req, subject, worksheet, exercise, username):
46
 
        # TODO: Find exercise within worksheet.
47
 
        self.user = ivle.database.User.get_by_login(req.store, username)
48
 
        if self.user is None:
49
 
            raise NotFound()
50
 
        self.exercise = exercise
51
 
        self.context = self.user # XXX: Not quite right.
52
 
 
53
 
    @require_permission('edit')
 
69
    '''
 
70
    Class to return a list of attempts for a given exercise, or add an Attempt
 
71
    '''
54
72
    def GET(self, req):
55
73
        """Handles a GET Attempts action."""
56
74
        exercise = ivle.database.Exercise.get_by_name(req.store, 
57
75
                                                        self.exercise)
 
76
        user = ivle.database.User.get_by_login(req.store, self.username)
58
77
 
59
 
        attempts = ivle.worksheet.get_exercise_attempts(req.store, self.user,
 
78
        attempts = ivle.worksheet.get_exercise_attempts(req.store, user,
60
79
                            exercise, allow_inactive=HISTORY_ALLOW_INACTIVE)
61
80
        # attempts is a list of ExerciseAttempt objects. Convert to dictionaries
62
81
        time_fmt = lambda dt: datetime.datetime.strftime(dt, TIMESTAMP_FORMAT)
63
82
        attempts = [{'date': time_fmt(a.date), 'complete': a.complete}
64
83
                for a in attempts]
65
 
 
 
84
        attempts.append(self.exercise)
 
85
        
66
86
        return attempts
67
 
 
68
 
 
69
 
    @require_permission('edit')
 
87
        
70
88
    def PUT(self, req, data):
71
 
        ''' Tests the given submission '''
72
 
        exercisefile = ivle.util.open_exercise_file(self.exercise)
 
89
        
 
90
        exercisefile = util.open_exercise_file(self.exercise)
73
91
        if exercisefile is None:
74
 
            raise NotFound()
 
92
            req.throw_error(req.HTTP_NOT_FOUND,
 
93
                "The exercise was not found.")
75
94
 
76
95
        # Start a console to run the tests on
77
96
        jail_path = os.path.join(ivle.conf.jail_base, req.user.login)
78
97
        working_dir = os.path.join("/home", req.user.login)
79
 
        cons = ivle.console.Console(req.user.unixid, jail_path, working_dir)
 
98
        cons = console.Console(req.user.unixid, jail_path, working_dir)
80
99
 
81
100
        # Parse the file into a exercise object using the test suite
82
 
        exercise_obj = ivle.webapp.tutorial.test.parse_exercise_file(
83
 
                                                            exercisefile, cons)
 
101
        exercise_obj = test.parse_exercise_file(exercisefile, cons)
84
102
        exercisefile.close()
85
103
 
86
104
        # Run the test cases. Get the result back as a JSONable object.
87
105
        # Return it.
88
 
        test_results = exercise_obj.run_tests(data['code'])
 
106
        test_results = exercise_obj.run_tests(code)
89
107
 
90
108
        # Close the console
91
109
        cons.close()
92
110
 
93
111
        # Get the Exercise from the database
94
 
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
 
112
        exercise = ivle.database.Exercise.get_by_name(req.store, exercisesrc)
95
113
 
96
114
        attempt = ivle.database.ExerciseAttempt(user=req.user,
97
115
                                                exercise=exercise,
98
116
                                                date=datetime.datetime.now(),
99
117
                                                complete=test_results['passed'],
100
 
                                                # XXX
101
 
                                                text=unicode(data['code']))
 
118
                                                text=unicode(code)) # XXX
102
119
 
103
120
        req.store.add(attempt)
104
 
 
 
121
        req.store.commit()
105
122
        # Query the DB to get an updated score on whether or not this problem
106
123
        # has EVER been completed (may be different from "passed", if it has
107
124
        # been completed before), and the total number of attempts.
111
128
        test_results["attempts"] = attempts
112
129
 
113
130
        return test_results
114
 
 
 
131
        
115
132
 
116
133
class AttemptRESTView(JSONRESTView):
117
 
    '''REST view of an exercise attempt.'''
118
 
 
119
 
    def __init__(self, req, subject, worksheet, exercise, username, date):
120
 
        # TODO: Find exercise within worksheet.
121
 
        user = ivle.database.User.get_by_login(req.store, username)
122
 
        if user is None:
123
 
            raise NotFound()
124
 
 
125
 
        try:
126
 
            date = datetime.datetime.strptime(date, TIMESTAMP_FORMAT)
127
 
        except ValueError:
128
 
            raise NotFound()
129
 
 
130
 
        exercise = ivle.database.Exercise.get_by_name(req.store, exercise)
131
 
        attempt = ivle.worksheet.get_exercise_attempt(req.store, user,
 
134
    '''
 
135
    View used to extract the data of a specified attempt
 
136
    '''
 
137
    
 
138
    def GET(self, req):
 
139
        # Get an actual date object, rather than a string
 
140
        date = datetime.datetime.strptime(self.date, TIMESTAMP_FORMAT)
 
141
        
 
142
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
 
143
        attempt = ivle.worksheet.get_exercise_attempt(req.store, req.user,
132
144
            exercise, as_of=date, allow_inactive=HISTORY_ALLOW_INACTIVE)
133
 
 
134
 
        if attempt is None:
135
 
            raise NotFound()
136
 
 
137
 
        self.context = attempt
138
 
 
139
 
    @require_permission('view')
140
 
    def GET(self, req):
141
 
        return {'code': self.context.text}
142
 
 
143
 
 
 
145
        if attempt is not None:
 
146
            attempt = attempt.text
 
147
        # attempt may be None; will write "null"
 
148
        return {'code': attempt}
 
149
        
144
150
class ExerciseRESTView(JSONRESTView):
145
 
    '''REST view of an exercise.'''
146
 
 
147
 
    def get_permissions(self, user):
148
 
        # XXX: Do it properly.
149
 
        if user is not None:
150
 
            return set(['save'])
151
 
        else:
152
 
            return set()
153
 
 
154
 
    @named_operation('save')
155
 
    def save(self, req, text):
 
151
    '''
 
152
    Handles a save action. This saves the user's code without executing it.
 
153
    '''
 
154
    @named_operation
 
155
    def save(self, req, user, text):    
156
156
        # Need to open JUST so we know this is a real exercise.
157
157
        # (This avoids users submitting code for bogus exercises).
158
 
        exercisefile = ivle.util.open_exercise_file(self.exercise)
 
158
        exercisefile = util.open_exercise_file(self.exercise)
159
159
        if exercisefile is None:
160
 
            raise NotFound()
 
160
            req.throw_error(req.HTTP_NOT_FOUND,
 
161
                "The exercise was not found.")
161
162
        exercisefile.close()
162
163
 
163
164
        exercise = ivle.database.Exercise.get_by_name(req.store, self.exercise)
164
165
        ivle.worksheet.save_exercise(req.store, req.user, exercise,
165
 
                                     unicode(text), datetime.datetime.now())
 
166
                                     unicode(code), datetime.datetime.now())
 
167
        req.store.commit()
166
168
        return {"result": "ok"}