1
# IVLE - Informatics Virtual Learning Environment
2
# Copyright (C) 2007-2009 The University of Melbourne
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
Worksheet Utility Functions
23
This module provides functions for tutorial and worksheet computations.
26
from storm.locals import And, Asc, Desc
29
def get_exercise_status(store, user, exercise):
30
"""Given a storm.store, User and Exercise, returns information about
31
the user's performance on that problem.
33
- A boolean, whether they have successfully passed this exercise.
34
- An int, the number of attempts they have made up to and
35
including the first successful attempt (or the total number of
36
attempts, if not yet successful).
38
ExerciseAttempt = ivle.database.ExerciseAttempt
39
# A Storm expression denoting all active attempts by this user for this
41
is_relevant = ((ExerciseAttempt.user_id == user.id) &
42
(ExerciseAttempt.exercise_id == exercise.id) &
43
(ExerciseAttempt.active == True))
45
# Get the first successful active attempt, or None if no success yet.
46
# (For this user, for this exercise).
47
first_success = store.find(ExerciseAttempt, is_relevant,
48
ExerciseAttempt.complete == True
49
).order_by(Asc(ExerciseAttempt.date)).first()
51
if first_success is not None:
52
# Get the total number of active attempts up to and including the
53
# first successful attempt.
54
# (Subsequent attempts don't count, because the user had already
56
num_attempts = store.find(ExerciseAttempt, is_relevant,
57
ExerciseAttempt.date <= first_success.date).count()
59
# User has not yet succeeded.
60
# Get the total number of active attempts.
61
num_attempts = store.find(ExerciseAttempt, is_relevant).count()
63
return first_success is not None, num_attempts