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

« back to all changes in this revision

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

Remove Request.title.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 
22
22
import os
23
23
import datetime
24
 
import genshi
25
24
 
 
25
import ivle.util
26
26
import ivle.console
27
27
import ivle.database
28
 
from ivle.database import Exercise, ExerciseAttempt, ExerciseSave, Worksheet, \
29
 
                          Offering, Subject, Semester, WorksheetExercise
30
 
import ivle.worksheet.utils
 
28
from ivle.database import Exercise, ExerciseAttempt, ExerciseSave, Worksheet, Offering, Subject, Semester
 
29
import ivle.worksheet
 
30
import ivle.conf
31
31
import ivle.webapp.tutorial.test
 
32
 
32
33
from ivle.webapp.base.rest import (JSONRESTView, named_operation,
33
34
                                   require_permission)
34
35
from ivle.webapp.errors import NotFound
39
40
 
40
41
TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S'
41
42
 
 
43
 
42
44
class AttemptsRESTView(JSONRESTView):
43
45
    '''REST view of a user's attempts at an exercise.'''
44
 
    
45
46
    def __init__(self, req, subject, year, semester, worksheet, 
46
47
                                                exercise, username):
47
48
        self.user = ivle.database.User.get_by_login(req.store, username)
48
49
        if self.user is None:
49
50
            raise NotFound()
 
51
        self.exercise = exercise
50
52
        
51
 
        self.worksheet_exercise = req.store.find(WorksheetExercise,
52
 
            WorksheetExercise.exercise_id == unicode(exercise),
53
 
            WorksheetExercise.worksheet_id == Worksheet.id,
 
53
        self.worksheet = req.store.find(Worksheet,
 
54
            Worksheet.name == worksheet,
54
55
            Worksheet.offering_id == Offering.id,
55
 
            Worksheet.identifier == unicode(worksheet),
56
56
            Offering.subject_id == Subject.id,
57
 
            Subject.short_name == subject,
 
57
            Subject.code == subject,
58
58
            Offering.semester_id == Semester.id,
59
59
            Semester.year == year,
60
60
            Semester.semester == semester).one()
64
64
    @require_permission('edit')
65
65
    def GET(self, req):
66
66
        """Handles a GET Attempts action."""
 
67
        exercise = req.store.find(Exercise, Exercise.id == self.exercise).one()
 
68
 
67
69
        attempts = req.store.find(ExerciseAttempt, 
68
 
                ExerciseAttempt.ws_ex_id == self.worksheet_exercise.id,
 
70
                ExerciseAttempt.exercise_id == exercise.id,
69
71
                ExerciseAttempt.user_id == self.user.id)
70
72
        # attempts is a list of ExerciseAttempt objects. Convert to dictionaries
71
73
        time_fmt = lambda dt: datetime.datetime.strftime(dt, TIMESTAMP_FORMAT)
78
80
    @require_permission('edit')
79
81
    def PUT(self, req, data):
80
82
        """ Tests the given submission """
81
 
        exercise = req.store.find(Exercise, 
82
 
            Exercise.id == self.worksheet_exercise.exercise_id).one()
 
83
        exercise = req.store.find(Exercise, Exercise.id == self.exercise).one()
83
84
        if exercise is None:
84
85
            raise NotFound()
85
86
 
86
87
        # Start a console to run the tests on
87
 
        jail_path = os.path.join(req.config['paths']['jails']['mounts'],
88
 
                                 req.user.login)
 
88
        jail_path = os.path.join(ivle.conf.jail_base, req.user.login)
89
89
        working_dir = os.path.join("/home", req.user.login)
90
 
        cons = ivle.console.Console(req.config, req.user.unixid, jail_path,
91
 
                                    working_dir)
 
90
        cons = ivle.console.Console(req.user.unixid, jail_path, working_dir)
92
91
 
93
92
        # Parse the file into a exercise object using the test suite
94
93
        exercise_obj = ivle.webapp.tutorial.test.parse_exercise_file(
102
101
        cons.close()
103
102
 
104
103
        attempt = ivle.database.ExerciseAttempt(user=req.user,
105
 
            worksheet_exercise = self.worksheet_exercise,
106
 
            date = datetime.datetime.now(),
107
 
            complete = test_results['passed'],
108
 
            text = unicode(data['code'])
109
 
        )
 
104
                                                exercise=exercise,
 
105
                                                date=datetime.datetime.now(),
 
106
                                                complete=test_results['passed'],
 
107
                                                worksheet=self.worksheet,
 
108
                                                text=unicode(data['code']))
110
109
 
111
110
        req.store.add(attempt)
112
111
 
113
112
        # Query the DB to get an updated score on whether or not this problem
114
113
        # has EVER been completed (may be different from "passed", if it has
115
114
        # been completed before), and the total number of attempts.
116
 
        completed, attempts = ivle.worksheet.utils.get_exercise_status(
117
 
                req.store, req.user, self.worksheet_exercise)
 
115
        completed, attempts = ivle.worksheet.get_exercise_status(req.store,
 
116
            req.user, exercise, self.worksheet)
118
117
        test_results["completed"] = completed
119
118
        test_results["attempts"] = attempts
120
119
 
124
123
class AttemptRESTView(JSONRESTView):
125
124
    '''REST view of an exercise attempt.'''
126
125
 
127
 
    def __init__(self, req, subject, year, semester, worksheet, exercise, 
128
 
                 username, date):
 
126
    def __init__(self, req, subject, worksheet, exercise, username, date):
129
127
        # TODO: Find exercise within worksheet.
130
128
        user = ivle.database.User.get_by_login(req.store, username)
131
129
        if user is None:
136
134
        except ValueError:
137
135
            raise NotFound()
138
136
 
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,
 
137
        exercise = ivle.database.Exercise.get_by_name(req.store, exercise)
 
138
        worksheet = req.store.find(Worksheet,
 
139
            Worksheet.name == self.worksheet,
152
140
            Worksheet.offering_id == Offering.id,
153
141
            Offering.subject_id == Subject.id,
154
 
            Subject.short_name == subject,
 
142
            Subject.code == self.subject,
155
143
            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) 
 
144
            Semester.year == self.year,
 
145
            Semester.semester == self.semester).one()
 
146
 
 
147
        attempt = ivle.worksheet.get_exercise_attempt(req.store, user,
 
148
            exercise, worksheet, as_of=date, allow_inactive=HISTORY_ALLOW_INACTIVE)
162
149
 
163
150
        if attempt is None:
164
151
            raise NotFound()
170
157
        return {'code': self.context.text}
171
158
 
172
159
 
173
 
class WorksheetExerciseRESTView(JSONRESTView):
174
 
    '''REST view of a worksheet exercise.'''
175
 
 
176
 
    def __init__(self, req, subject, year, semester, worksheet, exercise):
177
 
        self.context = req.store.find(WorksheetExercise,
178
 
            WorksheetExercise.exercise_id == exercise,
179
 
            WorksheetExercise.worksheet_id == Worksheet.id,
180
 
            Worksheet.offering_id == Offering.id,
181
 
            Offering.subject_id == Subject.id,
182
 
            Subject.short_name == subject,
183
 
            Offering.semester_id == Semester.id,
184
 
            Semester.year == year,
185
 
            Semester.semester == semester).one()
186
 
        
187
 
        if self.context is None:
188
 
            raise NotFound()
189
 
 
190
 
    @named_operation('view')
 
160
class ExerciseRESTView(JSONRESTView):
 
161
    '''REST view of an exercise.'''
 
162
 
 
163
    def get_permissions(self, user):
 
164
        # XXX: Do it properly.
 
165
        if user is not None:
 
166
            return set(['save'])
 
167
        else:
 
168
            return set()
 
169
 
 
170
    @named_operation('save')
191
171
    def save(self, req, text):
192
 
        # Find the appropriate WorksheetExercise to save to. If its not found,
193
 
        # the user is submitting against a non-existant worksheet/exercise
194
 
 
195
 
        old_save = req.store.find(ExerciseSave,
196
 
            ExerciseSave.ws_ex_id == self.context.id,
197
 
            ExerciseSave.user == req.user).one()
198
 
        
199
 
        #Overwrite the old, or create a new if there isn't one
200
 
        if old_save is None:
201
 
            new_save = ExerciseSave()
202
 
            req.store.add(new_save)
203
 
        else:
204
 
            new_save = old_save
205
 
        
206
 
        new_save.worksheet_exercise = self.context
207
 
        new_save.user = req.user
208
 
        new_save.text = unicode(text)
209
 
        new_save.date = datetime.datetime.now()
210
 
 
211
 
        return {"result": "ok"}
212
 
 
213
 
 
214
 
# Note that this is the view of an existing worksheet. Creation is handled
215
 
# by OfferingRESTView (as offerings have worksheets)
216
 
class WorksheetRESTView(JSONRESTView):
217
 
    """View used to update a worksheet."""
218
 
 
219
 
    def __init__(self, req, **kwargs):
220
 
    
221
 
        self.worksheet = kwargs['worksheet']
222
 
        self.subject = kwargs['subject']
223
 
        self.year = kwargs['year']
224
 
        self.semester = kwargs['semester']
225
 
    
226
 
        self.context = req.store.find(Worksheet,
227
 
            Worksheet.identifier == self.worksheet,
 
172
        # Need to open JUST so we know this is a real exercise.
 
173
        # (This avoids users submitting code for bogus exercises).
 
174
        exercise = req.store.find(Exercise,
 
175
            Exercise.id == self.exercise).one()
 
176
        worksheet = req.store.find(Worksheet,
 
177
            Worksheet.name == self.worksheet,
228
178
            Worksheet.offering_id == Offering.id,
229
179
            Offering.subject_id == Subject.id,
230
 
            Subject.short_name == self.subject,
231
 
            Offering.semester_id == Semester.id,
232
 
            Semester.year == self.year,
233
 
            Semester.semester == self.semester).one()
234
 
        
235
 
        if self.context is None:
236
 
            raise NotFound()
237
 
    
238
 
    @named_operation('edit')
239
 
    def save(self, req, name, assessable, data, format):
240
 
        """Takes worksheet data and saves it."""
241
 
        self.context.name = unicode(name)
242
 
        self.context.assessable = self.convert_bool(assessable)
243
 
        self.context.data = unicode(data)
244
 
        self.context.format = unicode(format)
245
 
        ivle.worksheet.utils.update_exerciselist(self.context)
246
 
        
247
 
        return {"result": "ok"}
248
 
 
249
 
class WorksheetsRESTView(JSONRESTView):
250
 
    """View used to update and create Worksheets."""
251
 
    
252
 
    def __init__(self, req, **kwargs):
253
 
    
254
 
        self.subject = kwargs['subject']
255
 
        self.year = kwargs['year']
256
 
        self.semester = kwargs['semester']
257
 
    
258
 
        self.context = req.store.find(Offering,
259
 
            Offering.subject_id == Subject.id,
260
 
            Subject.short_name == self.subject,
261
 
            Offering.semester_id == Semester.id,
262
 
            Semester.year == self.year,
263
 
            Semester.semester == self.semester).one()
264
 
        
265
 
        if self.context is None:
266
 
            raise NotFound()
267
 
 
268
 
    @named_operation('edit')
269
 
    def add_worksheet(self, req, identifier, name, assessable, data, format):
270
 
        """Takes worksheet data and adds it."""
271
 
        
272
 
        new_worksheet = Worksheet()
273
 
        new_worksheet.seq_no = self.context.worksheets.count()
274
 
        # Setting new_worksheet.offering implicitly adds new_worksheet,
275
 
        # hence worksheets.count MUST be called above it
276
 
        new_worksheet.offering = self.context
277
 
        new_worksheet.identifier = unicode(identifier)
278
 
        new_worksheet.name = unicode(name)
279
 
        new_worksheet.assessable = self.convert_bool(assessable)
280
 
        new_worksheet.data = unicode(data)
281
 
        new_worksheet.format = unicode(format)
282
 
        
283
 
        # This call is added for clarity, as the worksheet is implicitly added.        
284
 
        req.store.add(new_worksheet)
285
 
 
286
 
        ivle.worksheet.utils.update_exerciselist(new_worksheet)
287
 
 
288
 
        return {"result": "ok"}
289
 
 
290
 
    @named_operation('edit')
291
 
    def move_up(self, req, worksheetid):
292
 
        """Takes a list of worksheet-seq_no pairs and updates their 
293
 
        corresponding Worksheet objects to match."""
294
 
        
295
 
        worksheet_below = req.store.find(Worksheet,
296
 
            Worksheet.offering_id == self.context.id,
297
 
            Worksheet.identifier == unicode(worksheetid)).one()
298
 
        if worksheet_below is None:
299
 
            raise NotFound('worksheet_below')
300
 
        worksheet_above = req.store.find(Worksheet,
301
 
            Worksheet.offering_id == self.context.id,
302
 
            Worksheet.seq_no == (worksheet_below.seq_no - 1)).one()
303
 
        if worksheet_above is None:
304
 
            raise NotFound('worksheet_above')
305
 
 
306
 
        worksheet_below.seq_no = worksheet_below.seq_no - 1
307
 
        worksheet_above.seq_no = worksheet_above.seq_no + 1
308
 
        
309
 
        return {'result': 'ok'}
310
 
 
311
 
    @named_operation('edit')
312
 
    def move_down(self, req, worksheetid):
313
 
        """Takes a list of worksheet-seq_no pairs and updates their 
314
 
        corresponding Worksheet objects to match."""
315
 
        
316
 
        worksheet_above = req.store.find(Worksheet,
317
 
            Worksheet.offering_id == self.context.id,
318
 
            Worksheet.identifier == unicode(worksheetid)).one()
319
 
        if worksheet_above is None:
320
 
            raise NotFound('worksheet_below')
321
 
        worksheet_below = req.store.find(Worksheet,
322
 
            Worksheet.offering_id == self.context.id,
323
 
            Worksheet.seq_no == (worksheet_above.seq_no + 1)).one()
324
 
        if worksheet_below is None:
325
 
            raise NotFound('worksheet_above')
326
 
 
327
 
        worksheet_below.seq_no = worksheet_below.seq_no - 1
328
 
        worksheet_above.seq_no = worksheet_above.seq_no + 1
329
 
        
330
 
        return {'result': 'ok'}
 
180
            Subject.code == self.subject,
 
181
            Offering.semester_id == Semester.id,
 
182
            Semester.year == self.year,
 
183
            Semester.semester == self.semester).one()
 
184
        ivle.worksheet.save_exercise(req.store, req.user, exercise, worksheet,
 
185
                                     unicode(text), datetime.datetime.now())
 
186
        return {"result": "ok"}