36
__all__ = ['get_store',
38
'Subject', 'Semester', 'Offering', 'Enrolment',
39
'ProjectSet', 'Project', 'ProjectGroup', 'ProjectGroupMembership',
40
'Exercise', 'Worksheet', 'WorksheetExercise',
41
'ExerciseSave', 'ExerciseAttempt',
42
'AlreadyEnrolledError', 'TestCase', 'TestSuite', 'TestSuiteVar'
45
36
def _kwarg_init(self, **kwargs):
46
37
for k,v in kwargs.items():
47
if k.startswith('_') or not hasattr(self.__class__, k):
38
if k.startswith('_') or not hasattr(self, k):
48
39
raise TypeError("%s got an unexpected keyword argument '%s'"
49
% (self.__class__.__name__, k))
40
% self.__class__.__name__, k)
50
41
setattr(self, k, v)
52
43
def get_conn_string():
54
45
Returns the Storm connection string, generated from the conf file.
59
clusterstr += ivle.conf.db_user
60
if ivle.conf.db_password:
61
clusterstr += ':' + ivle.conf.db_password
64
host = ivle.conf.db_host or 'localhost'
65
port = ivle.conf.db_port or 5432
67
clusterstr += '%s:%d' % (host, port)
69
return "postgres://%s/%s" % (clusterstr, ivle.conf.db_dbname)
47
return "postgres://%s:%s@%s:%d/%s" % (ivle.conf.db_user,
48
ivle.conf.db_password, ivle.conf.db_host, ivle.conf.db_port,
317
221
notes = Unicode()
322
return Store.of(self).find(ProjectGroup,
323
ProjectSet.offering_id == self.offering.id,
324
ProjectGroup.project_set_id == ProjectSet.id,
325
ProjectGroupMembership.project_group_id == ProjectGroup.id,
326
ProjectGroupMembership.user_id == self.user.id)
328
__init__ = _kwarg_init
331
return "<%s %r in %r>" % (type(self).__name__, self.user,
334
class AlreadyEnrolledError(Exception):
339
class ProjectSet(Storm):
340
__storm_table__ = "project_set"
342
id = Int(name="projectsetid", primary=True)
343
offering_id = Int(name="offeringid")
344
offering = Reference(offering_id, Offering.id)
345
max_students_per_group = Int()
347
projects = ReferenceSet(id, 'Project.project_set_id')
348
project_groups = ReferenceSet(id, 'ProjectGroup.project_set_id')
350
__init__ = _kwarg_init
353
return "<%s %d in %r>" % (type(self).__name__, self.id,
356
class Project(Storm):
357
__storm_table__ = "project"
359
id = Int(name="projectid", primary=True)
362
project_set_id = Int(name="projectsetid")
363
project_set = Reference(project_set_id, ProjectSet.id)
364
deadline = DateTime()
366
__init__ = _kwarg_init
369
return "<%s '%s' in %r>" % (type(self).__name__, self.synopsis,
370
self.project_set.offering)
372
class ProjectGroup(Storm):
373
__storm_table__ = "project_group"
375
id = Int(name="groupid", primary=True)
376
name = Unicode(name="groupnm")
377
project_set_id = Int(name="projectsetid")
378
project_set = Reference(project_set_id, ProjectSet.id)
380
created_by_id = Int(name="createdby")
381
created_by = Reference(created_by_id, User.id)
384
members = ReferenceSet(id,
385
"ProjectGroupMembership.project_group_id",
386
"ProjectGroupMembership.user_id",
389
__init__ = _kwarg_init
392
return "<%s %s in %r>" % (type(self).__name__, self.name,
393
self.project_set.offering)
395
class ProjectGroupMembership(Storm):
396
__storm_table__ = "group_member"
397
__storm_primary__ = "user_id", "project_group_id"
399
user_id = Int(name="loginid")
400
user = Reference(user_id, User.id)
401
project_group_id = Int(name="groupid")
402
project_group = Reference(project_group_id, ProjectGroup.id)
404
__init__ = _kwarg_init
407
return "<%s %r in %r>" % (type(self).__name__, self.user,
410
# WORKSHEETS AND EXERCISES #
412
class Exercise(Storm):
413
__storm_table__ = "exercise"
414
id = Unicode(primary=True, name="identifier")
416
description = Unicode()
422
worksheets = ReferenceSet(id,
423
'WorksheetExercise.exercise_id',
424
'WorksheetExercise.worksheet_id',
428
test_suites = ReferenceSet(id, 'TestSuite.exercise_id')
430
__init__ = _kwarg_init
433
return "<%s %s>" % (type(self).__name__, self.name)
435
def get_permissions(self, user):
438
if user.rolenm in ('admin', 'lecturer'):
443
class Worksheet(Storm):
444
__storm_table__ = "worksheet"
446
id = Int(primary=True, name="worksheetid")
447
offering_id = Int(name="offeringid")
448
identifier = Unicode()
455
attempts = ReferenceSet(id, "ExerciseAttempt.worksheetid")
456
offering = Reference(offering_id, 'Offering.id')
458
# Use worksheet_exercises to get access to the WorksheetExercise objects
459
# binding worksheets to exercises. This is required to access the
461
worksheet_exercises = ReferenceSet(id,
462
'WorksheetExercise.worksheet_id')
465
__init__ = _kwarg_init
468
return "<%s %s>" % (type(self).__name__, self.name)
470
# XXX Refactor this - make it an instance method of Subject rather than a
471
# class method of Worksheet. Can't do that now because Subject isn't
472
# linked referentially to the Worksheet.
474
def get_by_name(cls, store, subjectname, worksheetname):
476
Get the Worksheet from the db associated with a given store, subject
477
name and worksheet name.
479
return store.find(cls, cls.subject == unicode(subjectname),
480
cls.name == unicode(worksheetname)).one()
482
def remove_all_exercises(self, store):
484
Remove all exercises from this worksheet.
485
This does not delete the exercises themselves. It just removes them
488
store.find(WorksheetExercise,
489
WorksheetExercise.worksheet == self).remove()
491
def get_permissions(self, user):
492
return self.offering.get_permissions(user)
494
class WorksheetExercise(Storm):
495
__storm_table__ = "worksheet_exercise"
497
id = Int(primary=True, name="ws_ex_id")
499
worksheet_id = Int(name="worksheetid")
500
worksheet = Reference(worksheet_id, Worksheet.id)
501
exercise_id = Unicode(name="exerciseid")
502
exercise = Reference(exercise_id, Exercise.id)
507
saves = ReferenceSet(id, "ExerciseSave.ws_ex_id")
508
attempts = ReferenceSet(id, "ExerciseAttempt.ws_ex_id")
510
__init__ = _kwarg_init
513
return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
514
self.worksheet.identifier)
516
class ExerciseSave(Storm):
518
Represents a potential solution to an exercise that a user has submitted
519
to the server for storage.
520
A basic ExerciseSave is just the current saved text for this exercise for
521
this user (doesn't count towards their attempts).
522
ExerciseSave may be extended with additional semantics (such as
525
__storm_table__ = "exercise_save"
526
__storm_primary__ = "ws_ex_id", "user_id"
528
ws_ex_id = Int(name="ws_ex_id")
529
worksheet_exercise = Reference(ws_ex_id, "WorksheetExercise.id")
531
user_id = Int(name="loginid")
532
user = Reference(user_id, User.id)
536
__init__ = _kwarg_init
539
return "<%s %s by %s at %s>" % (type(self).__name__,
540
self.exercise.name, self.user.login, self.date.strftime("%c"))
542
class ExerciseAttempt(ExerciseSave):
544
An ExerciseAttempt is a special case of an ExerciseSave. Like an
545
ExerciseSave, it constitutes exercise solution data that the user has
546
submitted to the server for storage.
547
In addition, it contains additional information about the submission.
548
complete - True if this submission was successful, rendering this exercise
549
complete for this user.
550
active - True if this submission is "active" (usually true). Submissions
551
may be de-activated by privileged users for special reasons, and then
552
they won't count (either as a penalty or success), but will still be
555
__storm_table__ = "exercise_attempt"
556
__storm_primary__ = "ws_ex_id", "user_id", "date"
558
# The "text" field is the same but has a different name in the DB table
560
text = Unicode(name="attempt")
564
def get_permissions(self, user):
565
return set(['view']) if user is self.user else set()
567
class TestSuite(Storm):
568
"""A Testsuite acts as a container for the test cases of an exercise."""
569
__storm_table__ = "test_suite"
570
__storm_primary__ = "exercise_id", "suiteid"
573
exercise_id = Unicode(name="exerciseid")
574
description = Unicode()
578
exercise = Reference(exercise_id, Exercise.id)
579
test_cases = ReferenceSet(suiteid, 'TestCase.suiteid')
580
variables = ReferenceSet(suiteid, 'TestSuiteVar.suiteid')
582
class TestCase(Storm):
583
"""A TestCase is a member of a TestSuite.
585
It contains the data necessary to check if an exercise is correct"""
586
__storm_table__ = "test_case"
587
__storm_primary__ = "testid", "suiteid"
591
suite = Reference(suiteid, "TestSuite.suiteid")
594
test_default = Unicode()
597
parts = ReferenceSet(testid, "TestCasePart.testid")
599
__init__ = _kwarg_init
601
class TestSuiteVar(Storm):
602
"""A container for the arguments of a Test Suite"""
603
__storm_table__ = "suite_variable"
604
__storm_primary__ = "varid"
609
var_value = Unicode()
613
suite = Reference(suiteid, "TestSuite.suiteid")
615
__init__ = _kwarg_init
617
class TestCasePart(Storm):
618
"""A container for the test elements of a Test Case"""
619
__storm_table__ = "test_case_part"
620
__storm_primary__ = "partid"
625
part_type = Unicode()
626
test_type = Unicode()
630
test = Reference(testid, "TestCase.testid")
632
__init__ = _kwarg_init
224
__init__ = _kwarg_init
227
return "<%s %r in %r>" % (type(self).__name__, self.user,