30
30
from storm.locals import create_database, Store, Int, Unicode, DateTime, \
31
31
Reference, ReferenceSet, Bool, Storm, Desc
32
from storm.exceptions import NotOneError, IntegrityError
35
from ivle.worksheet.rst import rst
37
36
__all__ = ['get_store',
40
39
'ProjectSet', 'Project', 'ProjectGroup', 'ProjectGroupMembership',
41
40
'Exercise', 'Worksheet', 'WorksheetExercise',
42
41
'ExerciseSave', 'ExerciseAttempt',
43
'TestCase', 'TestSuite', 'TestSuiteVar'
42
'AlreadyEnrolledError', 'TestCase', 'TestSuite', 'TestSuiteVar'
46
45
def _kwarg_init(self, **kwargs):
100
99
studentid = Unicode()
101
100
settings = Unicode()
103
if self.rolenm is None:
105
return ivle.caps.Role(self.rolenm)
106
def _set_role(self, value):
107
if not isinstance(value, ivle.caps.Role):
108
raise TypeError("role must be an ivle.caps.Role")
109
self.rolenm = unicode(value)
110
role = property(_get_role, _set_role)
103
112
__init__ = _kwarg_init
105
114
def __repr__(self):
117
126
return self.hash_password(password) == self.passhash
128
def hasCap(self, capability):
129
"""Given a capability (which is a Role object), returns True if this
130
User has that capability, False otherwise.
132
return self.role.hasCap(capability)
120
135
def password_expired(self):
121
136
fieldval = self.pass_exp
197
212
return store.find(cls, cls.login == unicode(login)).one()
199
214
def get_permissions(self, user):
200
if user and user.admin or user is self:
215
if user and user.rolenm == 'admin' or user is self:
201
216
return set(['view', 'edit'])
234
249
id = Int(primary=True, name="semesterid")
236
251
semester = Unicode()
239
254
offerings = ReferenceSet(id, 'Offering.semester_id')
240
enrolments = ReferenceSet(id,
241
'Offering.semester_id',
243
'Enrolment.offering_id')
245
256
__init__ = _kwarg_init
275
286
return "<%s %r in %r>" % (type(self).__name__, self.subject,
278
def enrol(self, user, role=u'student'):
289
def enrol(self, user):
279
290
'''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 unenrol(self, user):
292
'''Unenrol a user from this offering.'''
293
enrolment = Store.of(self).find(Enrolment,
294
Enrolment.user_id == user.id,
295
Enrolment.offering_id == self.id).one()
296
Store.of(enrolment).remove(enrolment)
291
# We'll get a horrible database constraint violation error if we try
292
# to add a second enrolment.
293
if Store.of(self).find(Enrolment,
294
Enrolment.user_id == user.id,
295
Enrolment.offering_id == self.id).count() == 1:
296
raise AlreadyEnrolledError()
298
e = Enrolment(user=user, offering=self, active=True)
299
self.enrolments.add(e)
298
301
def get_permissions(self, user):
300
303
if user is not None:
301
enrolment = self.get_enrolment(user)
302
if enrolment or user.admin:
304
if (enrolment and enrolment.role in (u'tutor', u'lecturer')) \
305
if user.rolenm in ('admin', 'lecturer'):
306
306
perms.add('edit')
309
def get_enrolment(self, user):
311
enrolment = self.enrolments.find(user=user).one()
317
309
class Enrolment(Storm):
318
310
__storm_table__ = "enrolment"
319
311
__storm_primary__ = "user_id", "offering_id"
425
419
include = Unicode()
428
worksheet_exercises = ReferenceSet(id,
429
'WorksheetExercise.exercise_id')
431
422
worksheets = ReferenceSet(id,
432
423
'WorksheetExercise.exercise_id',
433
424
'WorksheetExercise.worksheet_id',
437
test_suites = ReferenceSet(id,
438
'TestSuite.exercise_id',
428
test_suites = ReferenceSet(id, 'TestSuite.exercise_id')
441
430
__init__ = _kwarg_init
446
435
def get_permissions(self, user):
449
437
if user is not None:
453
elif 'lecturer' in set((e.role for e in user.active_enrolments)):
438
if user.rolenm in ('admin', 'lecturer'):
459
def get_description(self):
460
return rst(self.description)
463
"""Deletes the exercise, providing it has no associated worksheets."""
464
if (self.worksheet_exercises.count() > 0):
465
raise IntegrityError()
466
for suite in self.test_suites:
468
Store.of(self).remove(self)
470
443
class Worksheet(Storm):
471
444
__storm_table__ = "worksheet"
482
455
attempts = ReferenceSet(id, "ExerciseAttempt.worksheetid")
483
456
offering = Reference(offering_id, 'Offering.id')
485
all_worksheet_exercises = ReferenceSet(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,
486
462
'WorksheetExercise.worksheet_id')
488
# Use worksheet_exercises to get access to the *active* WorksheetExercise
489
# objects binding worksheets to exercises. This is required to access the
493
def worksheet_exercises(self):
494
return self.all_worksheet_exercises.find(active=True)
496
465
__init__ = _kwarg_init
510
479
return store.find(cls, cls.subject == unicode(subjectname),
511
480
cls.name == unicode(worksheetname)).one()
513
def remove_all_exercises(self):
482
def remove_all_exercises(self, store):
515
484
Remove all exercises from this worksheet.
516
485
This does not delete the exercises themselves. It just removes them
517
486
from the worksheet.
519
store = Store.of(self)
520
for ws_ex in self.all_worksheet_exercises:
521
if ws_ex.saves.count() > 0 or ws_ex.attempts.count() > 0:
522
raise IntegrityError()
523
488
store.find(WorksheetExercise,
524
489
WorksheetExercise.worksheet == self).remove()
526
491
def get_permissions(self, user):
527
492
return self.offering.get_permissions(user)
530
"""Returns the xml of this worksheet, converts from rst if required."""
531
if self.format == u'rst':
532
ws_xml = rst(self.data)
538
"""Deletes the worksheet, provided it has no attempts on any exercises.
540
Returns True if delete succeeded, or False if this worksheet has
541
attempts attached."""
542
for ws_ex in self.all_worksheet_exercises:
543
if ws_ex.saves.count() > 0 or ws_ex.attempts.count() > 0:
544
raise IntegrityError()
546
self.remove_all_exercises()
547
Store.of(self).remove(self)
549
494
class WorksheetExercise(Storm):
550
495
__storm_table__ = "worksheet_exercise"
568
513
return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
569
514
self.worksheet.identifier)
571
def get_permissions(self, user):
572
return self.worksheet.get_permissions(user)
575
516
class ExerciseSave(Storm):
577
518
Represents a potential solution to an exercise that a user has submitted
635
576
function = Unicode()
636
577
stdin = Unicode()
637
578
exercise = Reference(exercise_id, Exercise.id)
638
test_cases = ReferenceSet(suiteid, 'TestCase.suiteid', order_by="seq_no")
639
variables = ReferenceSet(suiteid, 'TestSuiteVar.suiteid', order_by='arg_no')
642
"""Delete this suite, without asking questions."""
643
for vaariable in self.variables:
645
for test_case in self.test_cases:
647
Store.of(self).remove(self)
579
test_cases = ReferenceSet(suiteid, 'TestCase.suiteid')
580
variables = ReferenceSet(suiteid, 'TestSuiteVar.suiteid')
649
582
class TestCase(Storm):
650
583
"""A TestCase is a member of a TestSuite.
664
597
parts = ReferenceSet(testid, "TestCasePart.testid")
666
599
__init__ = _kwarg_init
669
for part in self.parts:
671
Store.of(self).remove(self)
673
601
class TestSuiteVar(Storm):
674
602
"""A container for the arguments of a Test Suite"""