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

« back to all changes in this revision

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

  • Committer: Nick Chadwick
  • Date: 2009-03-03 01:48:48 UTC
  • mto: (1099.1.227 exercise-ui)
  • mto: This revision was merged to the branch mainline in revision 1162.
  • Revision ID: chadnickbok@gmail.com-20090303014848-dyurvmtmbneohd7f
Modified the setup script to include '.txt' files.

This allows the automatic inclusion of definitions.txt from the rst
code, as it is needed by all worksheets.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
import os
23
23
import datetime
24
 
 
25
24
import genshi
26
 
from storm.locals import Store
27
25
 
 
26
import ivle.util
28
27
import ivle.console
29
28
import ivle.database
30
29
from ivle.database import Exercise, ExerciseAttempt, ExerciseSave, Worksheet, \
31
 
                          Offering, Subject, Semester, User, WorksheetExercise
 
30
                          Offering, Subject, Semester, WorksheetExercise
32
31
import ivle.worksheet.utils
 
32
import ivle.conf
33
33
import ivle.webapp.tutorial.test
34
34
from ivle.webapp.base.rest import (JSONRESTView, named_operation,
35
35
                                   require_permission)
36
36
from ivle.webapp.errors import NotFound
37
37
 
 
38
# If True, getattempts or getattempt will allow browsing of inactive/disabled
 
39
# attempts. If False, will not allow this.
 
40
HISTORY_ALLOW_INACTIVE = False
38
41
 
39
42
TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S'
40
43
 
41
44
class AttemptsRESTView(JSONRESTView):
42
45
    '''REST view of a user's attempts at an exercise.'''
 
46
    
 
47
    def __init__(self, req, subject, year, semester, worksheet, 
 
48
                                                exercise, username):
 
49
        self.user = ivle.database.User.get_by_login(req.store, username)
 
50
        if self.user is None:
 
51
            raise NotFound()
 
52
        
 
53
        self.worksheet_exercise = req.store.find(WorksheetExercise,
 
54
            WorksheetExercise.exercise_id == unicode(exercise),
 
55
            WorksheetExercise.worksheet_id == Worksheet.id,
 
56
            Worksheet.offering_id == Offering.id,
 
57
            Worksheet.identifier == unicode(worksheet),
 
58
            Offering.subject_id == Subject.id,
 
59
            Subject.code == subject,
 
60
            Offering.semester_id == Semester.id,
 
61
            Semester.year == year,
 
62
            Semester.semester == semester).one()
 
63
        
 
64
        self.context = self.user # XXX: Not quite right.
43
65
 
44
66
    @require_permission('edit')
45
67
    def GET(self, req):
46
68
        """Handles a GET Attempts action."""
47
69
        attempts = req.store.find(ExerciseAttempt, 
48
 
                ExerciseAttempt.ws_ex_id == self.context.worksheet_exercise.id,
49
 
                ExerciseAttempt.user_id == self.context.user.id)
 
70
                ExerciseAttempt.ws_ex_id == self.worksheet_exercise.id,
 
71
                ExerciseAttempt.user_id == self.user.id)
50
72
        # attempts is a list of ExerciseAttempt objects. Convert to dictionaries
51
73
        time_fmt = lambda dt: datetime.datetime.strftime(dt, TIMESTAMP_FORMAT)
52
74
        attempts = [{'date': time_fmt(a.date), 'complete': a.complete}
58
80
    @require_permission('edit')
59
81
    def PUT(self, req, data):
60
82
        """ Tests the given submission """
 
83
        exercise = req.store.find(Exercise, 
 
84
            Exercise.id == self.worksheet_exercise.exercise_id).one()
 
85
        if exercise is None:
 
86
            raise NotFound()
 
87
 
61
88
        # Start a console to run the tests on
62
 
        jail_path = os.path.join(req.config['paths']['jails']['mounts'],
63
 
                                 req.user.login)
 
89
        jail_path = os.path.join(ivle.conf.jail_base, req.user.login)
64
90
        working_dir = os.path.join("/home", req.user.login)
65
 
        cons = ivle.console.Console(req.config, req.user.unixid, jail_path,
66
 
                                    working_dir)
 
91
        cons = ivle.console.Console(req.user.unixid, jail_path, working_dir)
67
92
 
68
93
        # Parse the file into a exercise object using the test suite
69
94
        exercise_obj = ivle.webapp.tutorial.test.parse_exercise_file(
70
 
                            self.context.worksheet_exercise.exercise, cons)
 
95
                                                            exercise, cons)
71
96
 
72
97
        # Run the test cases. Get the result back as a JSONable object.
73
98
        # Return it.
77
102
        cons.close()
78
103
 
79
104
        attempt = ivle.database.ExerciseAttempt(user=req.user,
80
 
            worksheet_exercise = self.context.worksheet_exercise,
 
105
            worksheet_exercise = self.worksheet_exercise,
81
106
            date = datetime.datetime.now(),
82
107
            complete = test_results['passed'],
83
108
            text = unicode(data['code'])
89
114
        # has EVER been completed (may be different from "passed", if it has
90
115
        # been completed before), and the total number of attempts.
91
116
        completed, attempts = ivle.worksheet.utils.get_exercise_status(
92
 
                req.store, req.user, self.context.worksheet_exercise)
 
117
                req.store, req.user, self.worksheet_exercise)
93
118
        test_results["completed"] = completed
94
119
        test_results["attempts"] = attempts
95
120
 
99
124
class AttemptRESTView(JSONRESTView):
100
125
    '''REST view of an exercise attempt.'''
101
126
 
 
127
    def __init__(self, req, subject, year, semester, worksheet, exercise, 
 
128
                 username, date):
 
129
        # TODO: Find exercise within worksheet.
 
130
        user = ivle.database.User.get_by_login(req.store, username)
 
131
        if user is None:
 
132
            raise NotFound()
 
133
 
 
134
        try:
 
135
            date = datetime.datetime.strptime(date, TIMESTAMP_FORMAT)
 
136
        except ValueError:
 
137
            raise NotFound()
 
138
 
 
139
        # XXX Hack around Google Code issue #87
 
140
        # Query from the given date +1 secnod.
 
141
        # Date is in seconds (eg. 3:47:12), while the data is in finer time
 
142
        # (eg. 3:47:12.3625). The query "date <= 3:47:12" will fail because
 
143
        # 3:47:12.3625 is greater. Hence we do the query from +1 second,
 
144
        # "date <= 3:47:13", and it finds the correct submission, UNLESS there
 
145
        # are multiple submissions inside the same second.
 
146
        date += datetime.timedelta(seconds=1)
 
147
 
 
148
        worksheet_exercise = req.store.find(WorksheetExercise,
 
149
            WorksheetExercise.exercise_id == exercise,
 
150
            WorksheetExercise.worksheet_id == Worksheet.id,
 
151
            Worksheet.identifier == worksheet,
 
152
            Worksheet.offering_id == Offering.id,
 
153
            Offering.subject_id == Subject.id,
 
154
            Subject.code == subject,
 
155
            Offering.semester_id == Semester.id,
 
156
            Semester.year == year,
 
157
            Semester.semester == semester).one()
 
158
            
 
159
        attempt = ivle.worksheet.utils.get_exercise_attempt(req.store, user,
 
160
                        worksheet_exercise, as_of=date,
 
161
                        allow_inactive=HISTORY_ALLOW_INACTIVE) 
 
162
 
 
163
        if attempt is None:
 
164
            raise NotFound()
 
165
 
 
166
        self.context = attempt
 
167
 
102
168
    @require_permission('view')
103
169
    def GET(self, req):
104
170
        return {'code': self.context.text}
105
171
 
106
172
 
107
173
class WorksheetExerciseRESTView(JSONRESTView):
108
 
    '''REST view of a worksheet exercise.'''
109
 
 
110
 
    @named_operation('view')
 
174
    '''REST view of an exercise.'''
 
175
 
 
176
    def get_permissions(self, user):
 
177
        # XXX: Do it properly.
 
178
        # XXX: Does any user have the ability to save as themselves?
 
179
        # XXX: Does a user EVER have permission to save as another user?
 
180
        if user is not None:
 
181
            return set(['save'])
 
182
        else:
 
183
            return set()
 
184
 
 
185
    @named_operation('save')
111
186
    def save(self, req, text):
112
187
        # Find the appropriate WorksheetExercise to save to. If its not found,
113
188
        # the user is submitting against a non-existant worksheet/exercise
 
189
        worksheet_exercise = req.store.find(WorksheetExercise,
 
190
            WorksheetExercise.exercise_id == self.exercise,
 
191
            WorksheetExercise.worksheet_id == Worksheet.id,
 
192
            Worksheet.offering_id == Offering.id,
 
193
            Offering.subject_id == Subject.id,
 
194
            Subject.code == self.subject,
 
195
            Offering.semester_id == Semester.id,
 
196
            Semester.year == self.year,
 
197
            Semester.semester == self.semester).one()
 
198
        
 
199
        if worksheet_exercise is None:
 
200
            raise NotFound()
114
201
 
115
202
        old_save = req.store.find(ExerciseSave,
116
 
            ExerciseSave.ws_ex_id == self.context.id,
 
203
            ExerciseSave.ws_ex_id == worksheet_exercise.id,
117
204
            ExerciseSave.user == req.user).one()
118
205
        
119
206
        #Overwrite the old, or create a new if there isn't one
123
210
        else:
124
211
            new_save = old_save
125
212
        
126
 
        new_save.worksheet_exercise = self.context
 
213
        new_save.worksheet_exercise = worksheet_exercise
127
214
        new_save.user = req.user
128
215
        new_save.text = unicode(text)
129
216
        new_save.date = datetime.datetime.now()
131
218
        return {"result": "ok"}
132
219
 
133
220
 
 
221
 
134
222
# Note that this is the view of an existing worksheet. Creation is handled
135
223
# by OfferingRESTView (as offerings have worksheets)
136
224
class WorksheetRESTView(JSONRESTView):
137
225
    """View used to update a worksheet."""
138
226
 
139
 
    @named_operation('edit')
 
227
    def get_permissions(self, user):
 
228
        # XXX: Do it properly.
 
229
        # XXX: Lecturers should be allowed to add worksheets Only to subjects
 
230
        #      under their control
 
231
        if user is not None:
 
232
            if user.admin:
 
233
                return set(['save'])
 
234
            else:
 
235
                return set()
 
236
        else:
 
237
            return set()    
 
238
 
 
239
    def __init__(self, req, **kwargs):
 
240
    
 
241
        self.worksheet = kwargs['worksheet']
 
242
        self.subject = kwargs['subject']
 
243
        self.year = kwargs['year']
 
244
        self.semester = kwargs['semester']
 
245
    
 
246
        self.context = req.store.find(Worksheet,
 
247
            Worksheet.identifier == self.worksheet,
 
248
            Worksheet.offering_id == Offering.id,
 
249
            Offering.subject_id == Subject.id,
 
250
            Subject.code == self.subject,
 
251
            Offering.semester_id == Semester.id,
 
252
            Semester.year == self.year,
 
253
            Semester.semester == self.semester).one()
 
254
        
 
255
        if self.context is None:
 
256
            raise NotFound()
 
257
    
 
258
    @named_operation('save')
140
259
    def save(self, req, name, assessable, data, format):
141
260
        """Takes worksheet data and saves it."""
142
261
        self.context.name = unicode(name)
149
268
 
150
269
class WorksheetsRESTView(JSONRESTView):
151
270
    """View used to update and create Worksheets."""
 
271
    
 
272
    def get_permissions(self, user):
 
273
        # XXX: Do it properly.
 
274
        # XXX: Lecturers should be allowed to add worksheets Only to subjects
 
275
        #      under their control
 
276
        if user is not None:
 
277
            if user.admin:
 
278
                return set(['edit'])
 
279
            else:
 
280
                return set()
 
281
        else:
 
282
            return set()
 
283
 
 
284
    def __init__(self, req, **kwargs):
 
285
    
 
286
        self.subject = kwargs['subject']
 
287
        self.year = kwargs['year']
 
288
        self.semester = kwargs['semester']
 
289
    
 
290
        self.context = req.store.find(Offering,
 
291
            Offering.subject_id == Subject.id,
 
292
            Subject.code == self.subject,
 
293
            Offering.semester_id == Semester.id,
 
294
            Semester.year == self.year,
 
295
            Semester.semester == self.semester).one()
 
296
        
 
297
        if self.context is None:
 
298
            raise NotFound()
152
299
 
153
300
    @named_operation('edit')
154
301
    def add_worksheet(self, req, identifier, name, assessable, data, format):