513
513
frozenset(['date', 'text']),
514
514
frozenset(['problemid', 'loginid']))
516
def get_problem_attempts(self, login, exercisename, allow_inactive=True,
518
"""Given a login name and exercise name, returns a list of dicts, one
519
for each attempt made for that exercise.
520
Dicts are {'date': 'formatted_time', 'complete': bool}.
521
Ordered with the newest first.
523
Note: By default, returns de-activated problem attempts.
524
If allow_inactive is False, will not return disabled attempts.
526
Note: Even if dry, will still physically call get_problem_problemid,
527
which may mutate the DB, and get_user_loginid, which may fail.
529
problemid = self.get_problem_problemid(exercisename)
530
loginid = self.get_user_loginid(login) # May raise a DBException
531
andactive = '' if allow_inactive else ' AND active'
532
query = """SELECT date, complete FROM problem_attempt
533
WHERE loginid = %d AND problemid = %d%s
534
ORDER BY date DESC;""" % (loginid, problemid, andactive)
536
result = self.db.query(query).getresult()
537
# Make into dicts (could use dictresult, but want to convert values)
538
return [{'date': date, 'complete': _parse_boolean(complete)}
539
for date, complete in result]
541
def get_problem_attempt(self, login, exercisename, as_of,
542
allow_inactive=True, dry=False):
543
"""Given a login name, exercise name, and struct_time, returns the
544
text of the submitted attempt for this question as of that date.
545
Returns None if the user had not made an attempt on this problem at
548
Note: By default, returns de-activated problem attempts.
549
If allow_inactive is False, will not return disabled attempts.
551
Note: Even if dry, will still physically call get_problem_problemid,
552
which may mutate the DB, and get_user_loginid, which may fail.
554
problemid = self.get_problem_problemid(exercisename)
555
loginid = self.get_user_loginid(login) # May raise a DBException
556
# Very similar to query in get_problem_stored_text, but without
557
# looking in problem_save, and restricting to a certain date.
558
andactive = '' if allow_inactive else ' AND active'
559
query = """SELECT attempt FROM problem_attempt
560
WHERE loginid = %d AND problemid = %d%s AND date <= %s
562
LIMIT 1;""" % (loginid, problemid, andactive, _escape(as_of))
564
result = self.db.query(query)
565
if result.ntuples() == 1:
566
# The user has made at least 1 attempt. Return the newest.
567
return result.getresult()[0][0]
571
516
def _get_problem_status(self, login, exercisename, dry=False):
572
517
"""Given a login name and exercise name, returns information about the
573
518
user's performance on that problem.