26
26
from storm.locals import And, Asc, Desc
27
27
import ivle.database
28
from ivle.database import ExerciseAttempt, ExerciseSave, Worksheet
30
29
__all__ = ['get_exercise_status', 'get_exercise_stored_text',
31
30
'get_exercise_attempts', 'get_exercise_attempt',
34
def get_exercise_status(store, user, exercise, worksheet):
33
def get_exercise_status(store, user, exercise):
35
34
"""Given a storm.store, User and Exercise, returns information about
36
35
the user's performance on that problem.
37
36
Returns a tuple of:
40
39
including the first successful attempt (or the total number of
41
40
attempts, if not yet successful).
42
ExerciseAttempt = ivle.database.ExerciseAttempt
43
43
# A Storm expression denoting all active attempts by this user for this
45
45
is_relevant = ((ExerciseAttempt.user_id == user.id) &
46
46
(ExerciseAttempt.exercise_id == exercise.id) &
47
(ExerciseAttempt.active == True) &
48
(ExerciseAttempt.worksheetid == worksheet.id))
47
(ExerciseAttempt.active == True))
50
49
# Get the first successful active attempt, or None if no success yet.
51
50
# (For this user, for this exercise).
68
67
return first_success is not None, num_attempts
70
def get_exercise_stored_text(store, user, exercise, worksheet):
69
def get_exercise_stored_text(store, user, exercise):
71
70
"""Given a storm.store, User and Exercise, returns an
72
71
ivle.database.ExerciseSave object for the last saved/submitted attempt for
73
72
this question (note that ExerciseAttempt is a subclass of ExerciseSave).
76
75
If the user has both saved and submitted, it returns whichever was
78
ExerciseSave = ivle.database.ExerciseSave
79
ExerciseAttempt = ivle.database.ExerciseAttempt
80
81
# Get the saved text, or None
81
82
saved = store.find(ExerciseSave,
82
83
ExerciseSave.user_id == user.id,
83
ExerciseSave.exercise_id == exercise.id,
84
ExerciseSave.worksheetid == worksheet.id).one()
84
ExerciseSave.exercise_id == exercise.id).one()
86
86
# Get the most recent attempt, or None
87
87
attempt = store.find(ExerciseAttempt,
88
88
ExerciseAttempt.user_id == user.id,
89
89
ExerciseAttempt.exercise_id == exercise.id,
90
ExerciseAttempt.worksheetid == worksheet.id,
91
90
ExerciseAttempt.active == True,
92
91
).order_by(Asc(ExerciseAttempt.date)).last()
106
def _get_exercise_attempts(store, user, exercise, worksheet, as_of=None,
105
def _get_exercise_attempts(store, user, exercise, as_of=None,
107
106
allow_inactive=False):
108
107
"""Same as get_exercise_attempts, but doesn't convert Storm's iterator
109
ExerciseAttempt = ivle.database.ExerciseAttempt
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
114
ExerciseAttempt.exercise_id == exercise.id,
115
ExerciseAttempt.worksheetid == worksheet.id,
116
115
True if allow_inactive else ExerciseAttempt.active == True,
117
116
True if as_of is None else ExerciseAttempt.date <= as_of,
118
117
).order_by(Desc(ExerciseAttempt.date))
120
def get_exercise_attempts(store, user, exercise, worksheet, as_of=None,
119
def get_exercise_attempts(store, user, exercise, as_of=None,
121
120
allow_inactive=False):
122
121
"""Given a storm.store, User and Exercise, returns a list of
123
122
ivle.database.ExerciseAttempt objects, one for each attempt made for the
127
126
attempts made before or at this time.
128
127
allow_inactive: If True, will return disabled attempts.
130
return list(_get_exercise_attempts(store, user, exercise, worksheet, as_of,
129
return list(_get_exercise_attempts(store, user, exercise, as_of,
133
def get_exercise_attempt(store, user, exercise, worksheet, as_of=None,
132
def get_exercise_attempt(store, user, exercise, as_of=None,
134
133
allow_inactive=False):
135
134
"""Given a storm.store, User and Exercise, returns an
136
135
ivle.database.ExerciseAttempt object for the last submitted attempt for
142
141
attempts made before or at this time.
143
142
allow_inactive: If True, will return disabled attempts.
145
return _get_exercise_attempts(store, user, exercise, worksheet, as_of,
144
return _get_exercise_attempts(store, user, exercise, as_of,
146
145
allow_inactive).first()
148
def save_exercise(store, user, exercise, worksheet, text, date):
147
def save_exercise(store, user, exercise, text, date):
149
148
"""Save an exercise for a user.
151
150
Given a store, User, Exercise and text and date, save the text to the
154
153
saved = store.find(ivle.database.ExerciseSave,
155
154
ivle.database.ExerciseSave.user_id == user.id,
156
ivle.database.ExerciseSave.exercise_id == exercise.id,
157
ivle.database.ExerciseSave.worksheetid == worksheet.id
155
ivle.database.ExerciseSave.exercise_id == exercise.id).one()
159
156
if saved is None:
160
saved = ivle.database.ExerciseSave(user=user, exercise=exercise,
157
saved = ivle.database.ExerciseSave(user=user, exercise=exercise)
164
160
saved.date = date