def _validate_grades(c): assignment_names = get_assignment_name_set() c.execute("SELECT DISTINCT assignment FROM grades") for assignment_name, in c.fetchall(): assert assignment_name in assignment_names, ( "Unknown assignment in database: %s" % assignment_name) c.execute("SELECT DISTINCT assignment FROM gradeslog") for assignment_name, in c.fetchall(): assert assignment_name in assignment_names, ( "Unknown assignment in database: %s" % assignment_name) c.execute("SELECT DISTINCT job FROM builds") for assignment_name, in c.fetchall(): assert assignment_name in assignment_names, ( "Unknown assignment in database: %s" % assignment_name)
def _validate_grades(c): assignment_names = get_assignment_name_set() c.execute("SELECT DISTINCT assignment FROM grades") for assignment_name, in c.fetchall(): assert assignment_name in assignment_names, ("Unknown assignment in database: %s" % assignment_name) c.execute("SELECT DISTINCT assignment FROM gradeslog") for assignment_name, in c.fetchall(): assert assignment_name in assignment_names, ("Unknown assignment in database: %s" % assignment_name) c.execute("SELECT DISTINCT job FROM builds") for assignment_name, in c.fetchall(): assert assignment_name in assignment_names, ("Unknown assignment in database: %s" % assignment_name)
def assign_grade_batch(c, users, assignment, score, slipunits, transaction_name, description, source, manual=False, dont_lower=False): """ Assigns a new grade to one or more students. Also supports assigning slip units. You can use the special value `None` for score and/or slipunits to use the current value. If the dont_lower flag is True, then anybody in `users` who currently has a higher grade will be removed from the operation (and slip days will not be adjusted either). Returns a list of user ids whose grades were affected (will always be a subset of users). """ if assignment not in get_assignment_name_set(): raise ValueError("Assignment %s is not known" % assignment) if not users: return [] if score is None and slipunits is None: return [] timestamp = now_str() if dont_lower: if score is None: # It makes no sense to do this. raise ValueError("You can not use both dont_lower=True and have a score of None, if " + "slipunits is not None.") # This comparison (old score vs new score) MUST be done in Sqlite in order for the result # to be correct. Sqlite will round the floating point number in the same way it did when # the original result was inserted, and the two values will be equal. Converting this to a # float in another language may produce undesirable effects. c.execute('''SELECT user FROM grades WHERE assignment = ? AND score >= ? AND user IN (%s)''' % (','.join(['?'] * len(users))), [assignment, score] + users) users = list(set(users) - {user for user, in c.fetchall()}) if not users: return [] c.execute('''SELECT users.id FROM grades LEFT JOIN users ON grades.user = users.id WHERE grades.assignment = ? AND users.id IN (%s)''' % (','.join(["?"] * len(users))), [assignment] + users) for user in list(set(users) - {user for user, in c.fetchall()}): # Insert dummy values first, and we will update them later c.execute('''INSERT INTO grades (user, assignment) VALUES (?, ?)''', [user, assignment]) c.execute('''UPDATE grades SET updated = ?, manual = ? WHERE assignment = ? AND user IN (%s)''' % (','.join(['?'] * len(users))), [timestamp, int(manual), assignment] + users) if score is not None: c.execute('''UPDATE grades SET score = ? WHERE assignment = ? AND user IN (%s)''' % (','.join(['?'] * len(users))), [score, assignment] + users) if slipunits is not None: c.execute('''UPDATE grades SET slipunits = ? WHERE assignment = ? AND user IN (%s)''' % (','.join(['?'] * len(users))), [slipunits, assignment] + users) c.execute('''INSERT INTO gradeslog (transaction_name, description, source, updated, user, assignment, score, slipunits) VALUES %s''' % (','.join(['(?,?,?,?,?,?,?,?)'] * len(users))), [field for entry in [[transaction_name, description, source, timestamp, user, assignment, score, slipunits] for user in users] for field in entry]) return users