275
226
def __repr__(self):
276
227
return "<%s %r in %r>" % (type(self).__name__, self.user,
279
class AlreadyEnrolledError(Exception):
284
class ProjectSet(Storm):
285
__storm_table__ = "project_set"
287
id = Int(name="projectsetid", primary=True)
288
offering_id = Int(name="offeringid")
289
offering = Reference(offering_id, Offering.id)
290
max_students_per_group = Int()
292
__init__ = _kwarg_init
295
return "<%s %d in %r>" % (type(self).__name__, self.id,
298
class Project(Storm):
299
__storm_table__ = "project"
301
id = Int(name="projectid", primary=True)
304
project_set_id = Int(name="projectsetid")
305
project_set = Reference(project_set_id, ProjectSet.id)
306
deadline = DateTime()
308
__init__ = _kwarg_init
311
return "<%s '%s' in %r>" % (type(self).__name__, self.synopsis,
312
self.project_set.offering)
314
class ProjectGroup(Storm):
315
__storm_table__ = "project_group"
317
id = Int(name="groupid", primary=True)
318
name = Unicode(name="groupnm")
319
project_set_id = Int(name="projectsetid")
320
project_set = Reference(project_set_id, ProjectSet.id)
322
created_by_id = Int(name="createdby")
323
created_by = Reference(created_by_id, User.id)
326
__init__ = _kwarg_init
329
return "<%s %s in %r>" % (type(self).__name__, self.name,
330
self.project_set.offering)
334
return Store.of(self).find(User,
335
ProjectGroupMembership.project_group_id == self.id,
336
User.id == ProjectGroupMembership.user_id)
338
class ProjectGroupMembership(Storm):
339
__storm_table__ = "group_member"
340
__storm_primary__ = "user_id", "project_group_id"
342
user_id = Int(name="loginid")
343
user = Reference(user_id, User.id)
344
project_group_id = Int(name="groupid")
345
project_group = Reference(project_group_id, ProjectGroup.id)
347
__init__ = _kwarg_init
350
return "<%s %r in %r>" % (type(self).__name__, self.user,
353
# WORKSHEETS AND EXERCISES #
355
class Exercise(Storm):
356
# Note: Table "problem" is called "Exercise" in the Object layer, since
357
# it's called that everywhere else.
358
__storm_table__ = "problem"
360
id = Int(primary=True, name="problemid")
361
name = Unicode(name="identifier")
364
worksheets = ReferenceSet(id,
365
'WorksheetExercise.exercise_id',
366
'WorksheetExercise.worksheet_id',
370
__init__ = _kwarg_init
373
return "<%s %s>" % (type(self).__name__, self.name)
376
def get_by_name(cls, store, name):
378
Get the Exercise from the db associated with a given store and name.
379
If the exercise is not in the database, creates it and inserts it
382
ex = store.find(cls, cls.name == unicode(name)).one()
385
ex = Exercise(name=unicode(name))
390
class Worksheet(Storm):
391
__storm_table__ = "worksheet"
393
id = Int(primary=True, name="worksheetid")
394
# XXX subject is not linked to a Subject object. This is a property of
395
# the database, and will be refactored.
397
name = Unicode(name="identifier")
401
exercises = ReferenceSet(id,
402
'WorksheetExercise.worksheet_id',
403
'WorksheetExercise.exercise_id',
405
# Use worksheet_exercises to get access to the WorksheetExercise objects
406
# binding worksheets to exercises. This is required to access the
408
worksheet_exercises = ReferenceSet(id,
409
'WorksheetExercise.worksheet_id')
411
__init__ = _kwarg_init
414
return "<%s %s>" % (type(self).__name__, self.name)
416
# XXX Refactor this - make it an instance method of Subject rather than a
417
# class method of Worksheet. Can't do that now because Subject isn't
418
# linked referentially to the Worksheet.
420
def get_by_name(cls, store, subjectname, worksheetname):
422
Get the Worksheet from the db associated with a given store, subject
423
name and worksheet name.
425
return store.find(cls, cls.subject == unicode(subjectname),
426
cls.name == unicode(worksheetname)).one()
428
def remove_all_exercises(self, store):
430
Remove all exercises from this worksheet.
431
This does not delete the exercises themselves. It just removes them
434
store.find(WorksheetExercise,
435
WorksheetExercise.worksheet == self).remove()
437
class WorksheetExercise(Storm):
438
__storm_table__ = "worksheet_problem"
439
__storm_primary__ = "worksheet_id", "exercise_id"
441
worksheet_id = Int(name="worksheetid")
442
worksheet = Reference(worksheet_id, Worksheet.id)
443
exercise_id = Int(name="problemid")
444
exercise = Reference(exercise_id, Exercise.id)
447
__init__ = _kwarg_init
450
return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
453
class ExerciseSave(Storm):
455
Represents a potential solution to an exercise that a user has submitted
456
to the server for storage.
457
A basic ExerciseSave is just the current saved text for this exercise for
458
this user (doesn't count towards their attempts).
459
ExerciseSave may be extended with additional semantics (such as
462
__storm_table__ = "problem_save"
463
__storm_primary__ = "exercise_id", "user_id", "date"
465
exercise_id = Int(name="problemid")
466
exercise = Reference(exercise_id, Exercise.id)
467
user_id = Int(name="loginid")
468
user = Reference(user_id, User.id)
472
__init__ = _kwarg_init
475
return "<%s %s by %s at %s>" % (type(self).__name__,
476
self.exercise.name, self.user.login, self.date.strftime("%c"))
478
class ExerciseAttempt(ExerciseSave):
480
An ExerciseAttempt is a special case of an ExerciseSave. Like an
481
ExerciseSave, it constitutes exercise solution data that the user has
482
submitted to the server for storage.
483
In addition, it contains additional information about the submission.
484
complete - True if this submission was successful, rendering this exercise
485
complete for this user.
486
active - True if this submission is "active" (usually true). Submissions
487
may be de-activated by privileged users for special reasons, and then
488
they won't count (either as a penalty or success), but will still be
491
__storm_table__ = "problem_attempt"
492
__storm_primary__ = "exercise_id", "user_id", "date"
494
# The "text" field is the same but has a different name in the DB table
496
text = Unicode(name="attempt")