197
133
return store.find(cls, cls.login == unicode(login)).one()
199
def get_permissions(self, user):
200
if user and user.admin or user is self:
201
return set(['view', 'edit'])
205
# SUBJECTS AND ENROLMENTS #
207
class Subject(Storm):
208
__storm_table__ = "subject"
210
id = Int(primary=True, name="subjectid")
211
code = Unicode(name="subj_code")
212
name = Unicode(name="subj_name")
213
short_name = Unicode(name="subj_short_name")
216
offerings = ReferenceSet(id, 'Offering.subject_id')
218
__init__ = _kwarg_init
221
return "<%s '%s'>" % (type(self).__name__, self.short_name)
223
def get_permissions(self, user):
231
class Semester(Storm):
232
__storm_table__ = "semester"
234
id = Int(primary=True, name="semesterid")
239
offerings = ReferenceSet(id, 'Offering.semester_id')
240
enrolments = ReferenceSet(id,
241
'Offering.semester_id',
243
'Enrolment.offering_id')
245
__init__ = _kwarg_init
248
return "<%s %s/%s>" % (type(self).__name__, self.year, self.semester)
250
class Offering(Storm):
251
__storm_table__ = "offering"
253
id = Int(primary=True, name="offeringid")
254
subject_id = Int(name="subject")
255
subject = Reference(subject_id, Subject.id)
256
semester_id = Int(name="semesterid")
257
semester = Reference(semester_id, Semester.id)
258
groups_student_permissions = Unicode()
260
enrolments = ReferenceSet(id, 'Enrolment.offering_id')
261
members = ReferenceSet(id,
262
'Enrolment.offering_id',
265
project_sets = ReferenceSet(id, 'ProjectSet.offering_id')
267
worksheets = ReferenceSet(id,
268
'Worksheet.offering_id',
272
__init__ = _kwarg_init
275
return "<%s %r in %r>" % (type(self).__name__, self.subject,
278
def enrol(self, user, role=u'student'):
279
'''Enrol a user in this offering.'''
280
enrolment = Store.of(self).find(Enrolment,
281
Enrolment.user_id == user.id,
282
Enrolment.offering_id == self.id).one()
284
if enrolment is None:
285
enrolment = Enrolment(user=user, offering=self)
286
self.enrolments.add(enrolment)
288
enrolment.active = True
289
enrolment.role = role
291
def get_permissions(self, user):
299
def get_enrolment(self, user):
301
enrolment = self.enrolments.find(user=user).one()
307
class Enrolment(Storm):
308
__storm_table__ = "enrolment"
309
__storm_primary__ = "user_id", "offering_id"
311
user_id = Int(name="loginid")
312
user = Reference(user_id, User.id)
313
offering_id = Int(name="offeringid")
314
offering = Reference(offering_id, Offering.id)
321
return Store.of(self).find(ProjectGroup,
322
ProjectSet.offering_id == self.offering.id,
323
ProjectGroup.project_set_id == ProjectSet.id,
324
ProjectGroupMembership.project_group_id == ProjectGroup.id,
325
ProjectGroupMembership.user_id == self.user.id)
327
__init__ = _kwarg_init
330
return "<%s %r in %r>" % (type(self).__name__, self.user,
335
class ProjectSet(Storm):
336
__storm_table__ = "project_set"
338
id = Int(name="projectsetid", primary=True)
339
offering_id = Int(name="offeringid")
340
offering = Reference(offering_id, Offering.id)
341
max_students_per_group = Int()
343
projects = ReferenceSet(id, 'Project.project_set_id')
344
project_groups = ReferenceSet(id, 'ProjectGroup.project_set_id')
346
__init__ = _kwarg_init
349
return "<%s %d in %r>" % (type(self).__name__, self.id,
352
class Project(Storm):
353
__storm_table__ = "project"
355
id = Int(name="projectid", primary=True)
358
project_set_id = Int(name="projectsetid")
359
project_set = Reference(project_set_id, ProjectSet.id)
360
deadline = DateTime()
362
__init__ = _kwarg_init
365
return "<%s '%s' in %r>" % (type(self).__name__, self.synopsis,
366
self.project_set.offering)
368
class ProjectGroup(Storm):
369
__storm_table__ = "project_group"
371
id = Int(name="groupid", primary=True)
372
name = Unicode(name="groupnm")
373
project_set_id = Int(name="projectsetid")
374
project_set = Reference(project_set_id, ProjectSet.id)
376
created_by_id = Int(name="createdby")
377
created_by = Reference(created_by_id, User.id)
380
members = ReferenceSet(id,
381
"ProjectGroupMembership.project_group_id",
382
"ProjectGroupMembership.user_id",
385
__init__ = _kwarg_init
388
return "<%s %s in %r>" % (type(self).__name__, self.name,
389
self.project_set.offering)
391
class ProjectGroupMembership(Storm):
392
__storm_table__ = "group_member"
393
__storm_primary__ = "user_id", "project_group_id"
395
user_id = Int(name="loginid")
396
user = Reference(user_id, User.id)
397
project_group_id = Int(name="groupid")
398
project_group = Reference(project_group_id, ProjectGroup.id)
400
__init__ = _kwarg_init
403
return "<%s %r in %r>" % (type(self).__name__, self.user,
406
# WORKSHEETS AND EXERCISES #
408
class Exercise(Storm):
409
__storm_table__ = "exercise"
410
id = Unicode(primary=True, name="identifier")
412
description = Unicode()
418
worksheet_exercises = ReferenceSet(id,
419
'WorksheetExercise.exercise_id')
421
worksheets = ReferenceSet(id,
422
'WorksheetExercise.exercise_id',
423
'WorksheetExercise.worksheet_id',
427
test_suites = ReferenceSet(id,
428
'TestSuite.exercise_id',
431
__init__ = _kwarg_init
434
return "<%s %s>" % (type(self).__name__, self.name)
436
def get_permissions(self, user):
444
def get_description(self):
445
return "<div class='exercise_description'>" + \
446
rst(self.description) + "</div>"
448
class Worksheet(Storm):
449
__storm_table__ = "worksheet"
451
id = Int(primary=True, name="worksheetid")
452
offering_id = Int(name="offeringid")
453
identifier = Unicode()
460
attempts = ReferenceSet(id, "ExerciseAttempt.worksheetid")
461
offering = Reference(offering_id, 'Offering.id')
463
all_worksheet_exercises = ReferenceSet(id,
464
'WorksheetExercise.worksheet_id')
466
# Use worksheet_exercises to get access to the *active* WorksheetExercise
467
# objects binding worksheets to exercises. This is required to access the
471
def worksheet_exercises(self):
472
return self.all_worksheet_exercises.find(active=True)
474
__init__ = _kwarg_init
477
return "<%s %s>" % (type(self).__name__, self.name)
479
# XXX Refactor this - make it an instance method of Subject rather than a
480
# class method of Worksheet. Can't do that now because Subject isn't
481
# linked referentially to the Worksheet.
483
def get_by_name(cls, store, subjectname, worksheetname):
485
Get the Worksheet from the db associated with a given store, subject
486
name and worksheet name.
488
return store.find(cls, cls.subject == unicode(subjectname),
489
cls.name == unicode(worksheetname)).one()
491
def remove_all_exercises(self, store):
493
Remove all exercises from this worksheet.
494
This does not delete the exercises themselves. It just removes them
497
store.find(WorksheetExercise,
498
WorksheetExercise.worksheet == self).remove()
500
def get_permissions(self, user):
501
return self.offering.get_permissions(user)
504
"""Returns the xml of this worksheet, converts from rst if required."""
505
if self.format == u'rst':
506
ws_xml = '<worksheet>' + rst(self.data) + '</worksheet>'
511
class WorksheetExercise(Storm):
512
__storm_table__ = "worksheet_exercise"
514
id = Int(primary=True, name="ws_ex_id")
516
worksheet_id = Int(name="worksheetid")
517
worksheet = Reference(worksheet_id, Worksheet.id)
518
exercise_id = Unicode(name="exerciseid")
519
exercise = Reference(exercise_id, Exercise.id)
524
saves = ReferenceSet(id, "ExerciseSave.ws_ex_id")
525
attempts = ReferenceSet(id, "ExerciseAttempt.ws_ex_id")
527
__init__ = _kwarg_init
530
return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
531
self.worksheet.identifier)
533
class ExerciseSave(Storm):
535
Represents a potential solution to an exercise that a user has submitted
536
to the server for storage.
537
A basic ExerciseSave is just the current saved text for this exercise for
538
this user (doesn't count towards their attempts).
539
ExerciseSave may be extended with additional semantics (such as
542
__storm_table__ = "exercise_save"
543
__storm_primary__ = "ws_ex_id", "user_id"
545
ws_ex_id = Int(name="ws_ex_id")
546
worksheet_exercise = Reference(ws_ex_id, "WorksheetExercise.id")
548
user_id = Int(name="loginid")
549
user = Reference(user_id, User.id)
553
__init__ = _kwarg_init
556
return "<%s %s by %s at %s>" % (type(self).__name__,
557
self.exercise.name, self.user.login, self.date.strftime("%c"))
559
class ExerciseAttempt(ExerciseSave):
561
An ExerciseAttempt is a special case of an ExerciseSave. Like an
562
ExerciseSave, it constitutes exercise solution data that the user has
563
submitted to the server for storage.
564
In addition, it contains additional information about the submission.
565
complete - True if this submission was successful, rendering this exercise
566
complete for this user.
567
active - True if this submission is "active" (usually true). Submissions
568
may be de-activated by privileged users for special reasons, and then
569
they won't count (either as a penalty or success), but will still be
572
__storm_table__ = "exercise_attempt"
573
__storm_primary__ = "ws_ex_id", "user_id", "date"
575
# The "text" field is the same but has a different name in the DB table
577
text = Unicode(name="attempt")
581
def get_permissions(self, user):
582
return set(['view']) if user is self.user else set()
584
class TestSuite(Storm):
585
"""A Testsuite acts as a container for the test cases of an exercise."""
586
__storm_table__ = "test_suite"
587
__storm_primary__ = "exercise_id", "suiteid"
590
exercise_id = Unicode(name="exerciseid")
591
description = Unicode()
595
exercise = Reference(exercise_id, Exercise.id)
596
test_cases = ReferenceSet(suiteid, 'TestCase.suiteid', order_by="seq_no")
597
variables = ReferenceSet(suiteid, 'TestSuiteVar.suiteid', order_by='arg_no')
599
class TestCase(Storm):
600
"""A TestCase is a member of a TestSuite.
602
It contains the data necessary to check if an exercise is correct"""
603
__storm_table__ = "test_case"
604
__storm_primary__ = "testid", "suiteid"
608
suite = Reference(suiteid, "TestSuite.suiteid")
611
test_default = Unicode()
614
parts = ReferenceSet(testid, "TestCasePart.testid")
616
__init__ = _kwarg_init
618
class TestSuiteVar(Storm):
619
"""A container for the arguments of a Test Suite"""
620
__storm_table__ = "suite_variable"
621
__storm_primary__ = "varid"
626
var_value = Unicode()
630
suite = Reference(suiteid, "TestSuite.suiteid")
632
__init__ = _kwarg_init
634
class TestCasePart(Storm):
635
"""A container for the test elements of a Test Case"""
636
__storm_table__ = "test_case_part"
637
__storm_primary__ = "partid"
642
part_type = Unicode()
643
test_type = Unicode()
647
test = Reference(testid, "TestCase.testid")
649
__init__ = _kwarg_init