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