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

« back to all changes in this revision

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

This commit changes the tutorial service, which now almost exclusively
uses the database to store its data.

Whilst the modifications to tutorial are not yet complete, this commit
should stabilise the database model.

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
24
25
 
25
26
import ivle.util
26
27
import ivle.console
27
28
import ivle.database
28
 
from ivle.database import Exercise, ExerciseAttempt, ExerciseSave, Worksheet, Offering, Subject, Semester
 
29
from ivle.database import Exercise, ExerciseAttempt, ExerciseSave, Worksheet, \
 
30
                          Offering, Subject, Semester, WorksheetExercise
29
31
import ivle.worksheet
30
32
import ivle.conf
31
33
import ivle.webapp.tutorial.test
40
42
 
41
43
TIMESTAMP_FORMAT = '%Y-%m-%d %H:%M:%S'
42
44
 
43
 
 
44
45
class AttemptsRESTView(JSONRESTView):
45
46
    '''REST view of a user's attempts at an exercise.'''
46
47
    def __init__(self, req, subject, year, semester, worksheet, 
48
49
        self.user = ivle.database.User.get_by_login(req.store, username)
49
50
        if self.user is None:
50
51
            raise NotFound()
51
 
        self.exercise = exercise
52
52
        
53
 
        self.worksheet = req.store.find(Worksheet,
54
 
            Worksheet.name == worksheet,
 
53
        self.worksheet_exercise = req.store.find(WorksheetExercise,
 
54
            WorksheetExercise.exercise_id == exercise,
 
55
            WorksheetExercise.worksheet_id == Worksheet.id,
55
56
            Worksheet.offering_id == Offering.id,
56
57
            Offering.subject_id == Subject.id,
57
58
            Subject.code == subject,
64
65
    @require_permission('edit')
65
66
    def GET(self, req):
66
67
        """Handles a GET Attempts action."""
67
 
        exercise = req.store.find(Exercise, Exercise.id == self.exercise).one()
68
 
 
69
68
        attempts = req.store.find(ExerciseAttempt, 
70
 
                ExerciseAttempt.exercise_id == exercise.id,
 
69
                ExerciseAttempt.ws_ex_id == self.worksheet_exercise.id,
71
70
                ExerciseAttempt.user_id == self.user.id)
72
71
        # attempts is a list of ExerciseAttempt objects. Convert to dictionaries
73
72
        time_fmt = lambda dt: datetime.datetime.strftime(dt, TIMESTAMP_FORMAT)
80
79
    @require_permission('edit')
81
80
    def PUT(self, req, data):
82
81
        """ Tests the given submission """
83
 
        exercise = req.store.find(Exercise, Exercise.id == self.exercise).one()
 
82
        exercise = req.store.find(Exercise, 
 
83
            Exercise.id == self.worksheet_exercise.exercise_id).one()
84
84
        if exercise is None:
85
85
            raise NotFound()
86
86
 
101
101
        cons.close()
102
102
 
103
103
        attempt = ivle.database.ExerciseAttempt(user=req.user,
104
 
                                                exercise=exercise,
105
 
                                                date=datetime.datetime.now(),
106
 
                                                complete=test_results['passed'],
107
 
                                                worksheet=self.worksheet,
108
 
                                                text=unicode(data['code']))
 
104
            worksheet_exercise = self.worksheet_exercise,
 
105
            date = datetime.datetime.now(),
 
106
            complete = test_results['passed'],
 
107
            text = unicode(data['code'])
 
108
        )
109
109
 
110
110
        req.store.add(attempt)
111
111
 
113
113
        # has EVER been completed (may be different from "passed", if it has
114
114
        # been completed before), and the total number of attempts.
115
115
        completed, attempts = ivle.worksheet.get_exercise_status(req.store,
116
 
            req.user, exercise, self.worksheet)
 
116
            req.user, self.worksheet_exercise)
117
117
        test_results["completed"] = completed
118
118
        test_results["attempts"] = attempts
119
119
 
123
123
class AttemptRESTView(JSONRESTView):
124
124
    '''REST view of an exercise attempt.'''
125
125
 
126
 
    def __init__(self, req, subject, worksheet, exercise, username, date):
 
126
    def __init__(self, req, subject, year, semester, worksheet, exercise, 
 
127
                 username, date):
127
128
        # TODO: Find exercise within worksheet.
128
129
        user = ivle.database.User.get_by_login(req.store, username)
129
130
        if user is None:
134
135
        except ValueError:
135
136
            raise NotFound()
136
137
 
137
 
        exercise = ivle.database.Exercise.get_by_name(req.store, exercise)
138
 
        worksheet = req.store.find(Worksheet,
139
 
            Worksheet.name == self.worksheet,
 
138
        worksheet_exercise = req.store.find(WorksheetExercise,
 
139
            WorksheetExercise.exercise_id == exercise,
 
140
            WorksheetExercise.worksheet_id == Worksheet.id,
 
141
            Worksheet.identifier == worksheet,
140
142
            Worksheet.offering_id == Offering.id,
141
143
            Offering.subject_id == Subject.id,
142
 
            Subject.code == self.subject,
 
144
            Subject.code == subject,
143
145
            Offering.semester_id == Semester.id,
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)
 
146
            Semester.year == year,
 
147
            Semester.semester == semester).one()
 
148
            
 
149
        attempt = req.store.find(ExerciseAttempt,
 
150
            ExerciseAttempt.login_id == user.id,
 
151
            ExerciseAttempt.ws_ex_id == worksheet_exercise.id,
 
152
            ExerciseAttempt.date == date
 
153
        )
149
154
 
150
155
        if attempt is None:
151
156
            raise NotFound()
162
167
 
163
168
    def get_permissions(self, user):
164
169
        # XXX: Do it properly.
 
170
        # XXX: Does any user have the ability to save as themselves?
 
171
        # XXX: Does a user EVER have permission to save as another user?
165
172
        if user is not None:
166
173
            return set(['save'])
167
174
        else:
169
176
 
170
177
    @named_operation('save')
171
178
    def save(self, req, text):
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,
178
 
            Worksheet.offering_id == Offering.id,
179
 
            Offering.subject_id == Subject.id,
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())
 
179
        # Find the appropriate WorksheetExercise to save to. If its not found,
 
180
        # the user is submitting against a non-existant worksheet/exercise
 
181
        worksheet_exercise = req.store.find(WorksheetExercise,
 
182
            WorksheetExercise.exericise_id == self.exercise,
 
183
            WorksheetExercise.worksheet_id == Worksheet.id,
 
184
            Worksheet.offering_id == Offering.id,
 
185
            Offering.subject_id == Subject.id,
 
186
            Subject.code == self.subject,
 
187
            Offering.semester_id == Semester.id,
 
188
            Semester.year == self.year,
 
189
            Semester.semester == self.semester).one()
 
190
        
 
191
        if worksheet_exercise is None:
 
192
            raise NotFound()
 
193
 
 
194
        new_save = ExerciseSave()
 
195
        new_save.worksheet_exercise = worksheet_exercise
 
196
        new_save.user = req.user
 
197
        new_save.text = unicode(text)
 
198
        new_save.date = datetime.datetime.now()
 
199
        req.store.add(new_save)
 
200
        return {"result": "ok"}
 
201
 
 
202
 
 
203
class WorksheetRESTView(JSONRESTView):
 
204
    """View used to update a worksheet."""
 
205
 
 
206
    def generate_exerciselist(self, req, worksheet):
 
207
        """Runs through the worksheetstream, generating the appropriate
 
208
        WorksheetExercises, and de-activating the old ones."""
 
209
        exercises = []
 
210
        # Turns the worksheet into an xml stream, and then finds all the 
 
211
        # exercise nodes in the stream.
 
212
        worksheet = genshi.XML(worksheet)
 
213
        for kind, data, pos in worksheet:
 
214
            if kind is genshi.core.START:
 
215
                # Data is a tuple of tag name and a list of name->value tuples
 
216
                if data[0] == 'exercise':
 
217
                    src = ""
 
218
                    optional = False
 
219
                    for attr in data[1]:
 
220
                        if attr[0] == 'src':
 
221
                            src = attr[1]
 
222
                        if attr[0] == 'optional':
 
223
                            optional = attr[1] == 'true'
 
224
                    if src != "":
 
225
                        exercises.append((src, optional))
 
226
        ex_num = 0
 
227
        # Set all current worksheet_exercises to be inactive
 
228
        db_worksheet_exercises = req.store.find(WorksheetExercise,
 
229
            WorksheetExercise.worksheet_id == self.context.id)
 
230
        for worksheet_exercise in db_worksheet_exercises:
 
231
            worksheet_exercise.active = False
 
232
        
 
233
        for exerciseid, optional in exercises:
 
234
            worksheet_exercise = req.store.find(WorksheetExercise,
 
235
                WorksheetExercise.worksheet_id == self.context.id,
 
236
                Exercise.id == WorksheetExercise.exercise_id,
 
237
                Exercise.id == exerciseid).one()
 
238
            if worksheet_exercise is None:
 
239
                exercise = req.store.find(Exercise,
 
240
                    Exercise.id == exerciseid
 
241
                ).one()
 
242
                if exercise is None:
 
243
                    raise NotFound()
 
244
                worksheet_exercise = WorksheetExercise()
 
245
                worksheet_exercise.worksheet_id = self.context.id
 
246
                worksheet_exercise.exercise_id = exercise.id
 
247
                req.store.add(worksheet_exercise)
 
248
            worksheet_exercise.active = True
 
249
            worksheet_exercise.seq_no = ex_num
 
250
            worksheet_exercise.optional = optional
 
251
 
 
252
    def get_permissions(self, user):
 
253
        # XXX: Do it properly.
 
254
        # XXX: Lecturers should be allowed to add worksheets Only to subjects
 
255
        #      under their control
 
256
        if user is not None:
 
257
            if user.rolenm == 'admin':
 
258
                return set(['save'])
 
259
            else:
 
260
                return set()
 
261
        else:
 
262
            return set()    
 
263
 
 
264
    def __init__(self, req, **kwargs):
 
265
    
 
266
        self.worksheet = kwargs['worksheet']
 
267
        self.subject = kwargs['subject']
 
268
        self.year = kwargs['year']
 
269
        self.semester = kwargs['semester']
 
270
    
 
271
        self.context = req.store.find(Worksheet,
 
272
            Worksheet.identifier == self.worksheet,
 
273
            Worksheet.offering_id == Offering.id,
 
274
            Offering.subject_id == Subject.id,
 
275
            Subject.code == self.subject,
 
276
            Offering.semester_id == Semester.id,
 
277
            Semester.year == self.year,
 
278
            Semester.semester == self.semester).one()
 
279
        
 
280
        if self.context is None:
 
281
            raise NotFound()
 
282
    
 
283
    @named_operation('save')
 
284
    def save(self, req, name, assessable, data):
 
285
        """Takes worksheet data and saves it."""
 
286
        self.generate_exerciselist(req, data)
 
287
        
 
288
        self.context.name = unicode(name)
 
289
        self.context.data = unicode(data)
 
290
        self.context.assessable = self.convert_bool(assessable)
 
291
        
186
292
        return {"result": "ok"}