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

« back to all changes in this revision

Viewing changes to ivle/worksheet.py

Remove the last two uses of req.write_html_head_foot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
This module provides functions for tutorial and worksheet computations.
24
24
"""
25
25
 
26
 
from storm.locals import And, Asc, Desc, Store
27
 
import genshi
28
 
 
 
26
from storm.locals import And, Asc, Desc
29
27
import ivle.database
30
 
from ivle.database import ExerciseAttempt, ExerciseSave, Worksheet, \
31
 
                          WorksheetExercise, Exercise
 
28
from ivle.database import ExerciseAttempt, ExerciseSave, Worksheet
32
29
 
33
30
__all__ = ['get_exercise_status', 'get_exercise_stored_text',
34
31
           'get_exercise_attempts', 'get_exercise_attempt',
35
32
          ]
36
33
 
37
 
def get_exercise_status(store, user, worksheet_exercise):
 
34
def get_exercise_status(store, user, exercise, worksheet):
38
35
    """Given a storm.store, User and Exercise, returns information about
39
36
    the user's performance on that problem.
40
37
    Returns a tuple of:
46
43
    # A Storm expression denoting all active attempts by this user for this
47
44
    # exercise.
48
45
    is_relevant = ((ExerciseAttempt.user_id == user.id) &
49
 
            (ExerciseAttempt.ws_ex_id == worksheet_exercise.id) &
50
 
            (ExerciseAttempt.active == True))
 
46
                   (ExerciseAttempt.exercise_id == exercise.id) &
 
47
                   (ExerciseAttempt.active == True) &
 
48
                   (ExerciseAttempt.worksheetid == worksheet.id))
51
49
 
52
50
    # Get the first successful active attempt, or None if no success yet.
53
51
    # (For this user, for this exercise).
69
67
 
70
68
    return first_success is not None, num_attempts
71
69
 
72
 
def get_exercise_stored_text(store, user, worksheet_exercise):
73
 
    """Given a storm.store, User and WorksheetExercise, returns an
 
70
def get_exercise_stored_text(store, user, exercise, worksheet):
 
71
    """Given a storm.store, User and Exercise, returns an
74
72
    ivle.database.ExerciseSave object for the last saved/submitted attempt for
75
73
    this question (note that ExerciseAttempt is a subclass of ExerciseSave).
76
74
    Returns None if the user has not saved or made an attempt on this
82
80
    # Get the saved text, or None
83
81
    saved = store.find(ExerciseSave,
84
82
                ExerciseSave.user_id == user.id,
85
 
                ExerciseSave.ws_ex_id == worksheet_exercise.id).one()
 
83
                ExerciseSave.exercise_id == exercise.id,
 
84
                ExerciseSave.worksheetid == worksheet.id).one()
86
85
 
87
86
    # Get the most recent attempt, or None
88
87
    attempt = store.find(ExerciseAttempt,
89
88
            ExerciseAttempt.user_id == user.id,
 
89
            ExerciseAttempt.exercise_id == exercise.id,
 
90
            ExerciseAttempt.worksheetid == worksheet.id,
90
91
            ExerciseAttempt.active == True,
91
 
            ExerciseAttempt.ws_ex_id == worksheet_exercise.id
92
92
        ).order_by(Asc(ExerciseAttempt.date)).last()
93
93
 
94
94
    # Pick the most recent of these two
103
103
        else:
104
104
            return None
105
105
 
106
 
def _get_exercise_attempts(store, user, worksheet_exercise, as_of=None,
 
106
def _get_exercise_attempts(store, user, exercise, worksheet, as_of=None,
107
107
        allow_inactive=False):
108
108
    """Same as get_exercise_attempts, but doesn't convert Storm's iterator
109
109
    into a list."""
111
111
    # Get the most recent attempt before as_of, or None
112
112
    return store.find(ExerciseAttempt,
113
113
            ExerciseAttempt.user_id == user.id,
114
 
            ExerciseAttempt.ws_ex_id == worksheet_exercise.id,
 
114
            ExerciseAttempt.exercise_id == exercise.id,
 
115
            ExerciseAttempt.worksheetid == worksheet.id,
115
116
            True if allow_inactive else ExerciseAttempt.active == True,
116
117
            True if as_of is None else ExerciseAttempt.date <= as_of,
117
118
        ).order_by(Desc(ExerciseAttempt.date))
118
119
 
119
 
def get_exercise_attempts(store, user, worksheet_exercise, as_of=None,
 
120
def get_exercise_attempts(store, user, exercise, worksheet, as_of=None,
120
121
        allow_inactive=False):
121
122
    """Given a storm.store, User and Exercise, returns a list of
122
123
    ivle.database.ExerciseAttempt objects, one for each attempt made for the
126
127
        attempts made before or at this time.
127
128
    allow_inactive: If True, will return disabled attempts.
128
129
    """
129
 
    return list(_get_exercise_attempts(store, user, worksheet_exercise, as_of,
 
130
    return list(_get_exercise_attempts(store, user, exercise, worksheet, as_of,
130
131
        allow_inactive))
131
132
 
132
 
def get_exercise_attempt(store, user, worksheet_exercise, as_of=None,
 
133
def get_exercise_attempt(store, user, exercise, worksheet, as_of=None,
133
134
        allow_inactive=False):
134
 
    """Given a storm.store, User and WorksheetExercise, returns an
 
135
    """Given a storm.store, User and Exercise, returns an
135
136
    ivle.database.ExerciseAttempt object for the last submitted attempt for
136
137
    this question.
137
138
    Returns None if the user has not made an attempt on this
141
142
        attempts made before or at this time.
142
143
    allow_inactive: If True, will return disabled attempts.
143
144
    """
144
 
    return _get_exercise_attempts(store, user, worksheet_exercise, as_of,
 
145
    return _get_exercise_attempts(store, user, exercise, worksheet, as_of,
145
146
        allow_inactive).first()
146
147
 
147
 
def save_exercise(store, user, worksheet_exercise, text, date):
 
148
def save_exercise(store, user, exercise, worksheet, text, date):
148
149
    """Save an exercise for a user.
149
150
 
150
 
    Given a store, User, WorksheetExercise, text and date, save the text to the
 
151
    Given a store, User, Exercise and text and date, save the text to the
151
152
    database. This will create the ExerciseSave if needed.
152
153
    """
153
154
    saved = store.find(ivle.database.ExerciseSave,
154
155
                ivle.database.ExerciseSave.user_id == user.id,
155
 
                ivle.database.ExerciseSave.ws_ex_id == worksheet_exercise.id
 
156
                ivle.database.ExerciseSave.exercise_id == exercise.id,
 
157
                ivle.database.ExerciseSave.worksheetid == worksheet.id
156
158
                ).one()
157
159
    if saved is None:
158
 
        saved = ivle.database.ExerciseSave(user=user, 
159
 
                                        worksheet_exercise=worksheet_exercise)
 
160
        saved = ivle.database.ExerciseSave(user=user, exercise=exercise, 
 
161
                                           worksheet=worksheet)
160
162
        store.add(saved)
161
163
 
162
164
    saved.date = date
180
182
    # Get the student's pass/fail for each exercise in this worksheet
181
183
    for worksheet_exercise in worksheet.worksheet_exercises:
182
184
        exercise = worksheet_exercise.exercise
183
 
        worksheet = worksheet_exercise.worksheet
184
185
        optional = worksheet_exercise.optional
185
186
 
186
 
        done, _ = get_exercise_status(store, user, worksheet_exercise)
 
187
        done, _ = get_exercise_status(store, user, exercise)
187
188
        # done is a bool, whether this student has completed that problem
188
189
        if optional:
189
190
            opt_total += 1
193
194
            if done: mand_done += 1
194
195
 
195
196
    return mand_done, mand_total, opt_done, opt_total
196
 
 
197
 
def update_exerciselist(worksheet):
198
 
    """Runs through the worksheetstream, generating the appropriate
199
 
    WorksheetExercises, and de-activating the old ones."""
200
 
    exercises = []
201
 
    # Turns the worksheet into an xml stream, and then finds all the 
202
 
    # exercise nodes in the stream.
203
 
    worksheetdata = genshi.XML(worksheet.data)
204
 
    for kind, data, pos in worksheetdata:
205
 
        if kind is genshi.core.START:
206
 
            # Data is a tuple of tag name and a list of name->value tuples
207
 
            if data[0] == 'exercise':
208
 
                src = ""
209
 
                optional = False
210
 
                for attr in data[1]:
211
 
                    if attr[0] == 'src':
212
 
                        src = attr[1]
213
 
                    if attr[0] == 'optional':
214
 
                        optional = attr[1] == 'true'
215
 
                if src != "":
216
 
                    exercises.append((src, optional))
217
 
    ex_num = 0
218
 
    # Set all current worksheet_exercises to be inactive
219
 
    db_worksheet_exercises = Store.of(worksheet).find(WorksheetExercise,
220
 
        WorksheetExercise.worksheet_id == worksheet.id)
221
 
    for worksheet_exercise in db_worksheet_exercises:
222
 
        worksheet_exercise.active = False
223
 
    
224
 
    for exerciseid, optional in exercises:
225
 
        worksheet_exercise = Store.of(worksheet).find(WorksheetExercise,
226
 
            WorksheetExercise.worksheet_id == worksheet.id,
227
 
            Exercise.id == WorksheetExercise.exercise_id,
228
 
            Exercise.id == exerciseid).one()
229
 
        if worksheet_exercise is None:
230
 
            exercise = Store.of(worksheet).find(Exercise,
231
 
                Exercise.id == exerciseid
232
 
            ).one()
233
 
            if exercise is None:
234
 
                raise NotFound()
235
 
            worksheet_exercise = WorksheetExercise()
236
 
            worksheet_exercise.worksheet_id = worksheet.id
237
 
            worksheet_exercise.exercise_id = exercise.id
238
 
            Store.of(worksheet).add(worksheet_exercise)
239
 
        worksheet_exercise.active = True
240
 
        worksheet_exercise.seq_no = ex_num
241
 
        worksheet_exercise.optional = optional
242