~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to ivle/database.py

Tutorial: Added a message, "no attempts have been made to this exercise",
    rather than displaying the empty box and View button.
    As a contingency, also fixed the View button - won't crash if there are no
    items in the list.

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
            'ProjectSet', 'Project', 'ProjectGroup', 'ProjectGroupMembership',
40
40
            'Exercise', 'Worksheet', 'WorksheetExercise',
41
41
            'ExerciseSave', 'ExerciseAttempt',
42
 
            'AlreadyEnrolledError', 'TestCase', 'TestSuite', 'TestSuiteVar'
 
42
            'AlreadyEnrolledError'
43
43
        ]
44
44
 
45
45
def _kwarg_init(self, **kwargs):
53
53
    """
54
54
    Returns the Storm connection string, generated from the conf file.
55
55
    """
56
 
 
57
 
    clusterstr = ''
58
 
    if ivle.conf.db_user:
59
 
        clusterstr += ivle.conf.db_user
60
 
        if ivle.conf.db_password:
61
 
            clusterstr += ':' + ivle.conf.db_password
62
 
        clusterstr += '@'
63
 
 
64
 
    host = ivle.conf.db_host or 'localhost'
65
 
    port = ivle.conf.db_port or 5432
66
 
 
67
 
    clusterstr += '%s:%d' % (host, port)
68
 
 
69
 
    return "postgres://%s/%s" % (clusterstr, ivle.conf.db_dbname)
 
56
    return "postgres://%s:%s@%s:%d/%s" % (ivle.conf.db_user,
 
57
        ivle.conf.db_password, ivle.conf.db_host, ivle.conf.db_port,
 
58
        ivle.conf.db_dbname)
70
59
 
71
60
def get_store():
72
61
    """
141
130
        fieldval = self.acct_exp
142
131
        return fieldval is not None and datetime.datetime.now() > fieldval
143
132
 
144
 
    @property
145
 
    def valid(self):
146
 
        return self.state == 'enabled' and not self.account_expired
147
 
 
148
133
    def _get_enrolments(self, justactive):
149
134
        return Store.of(self).find(Enrolment,
150
135
            Enrolment.user_id == self.id,
211
196
        """
212
197
        return store.find(cls, cls.login == unicode(login)).one()
213
198
 
214
 
    def get_permissions(self, user):
215
 
        if user and user.rolenm == 'admin' or user is self:
216
 
            return set(['view', 'edit'])
217
 
        else:
218
 
            return set()
219
 
 
220
199
# SUBJECTS AND ENROLMENTS #
221
200
 
222
201
class Subject(Storm):
235
214
    def __repr__(self):
236
215
        return "<%s '%s'>" % (type(self).__name__, self.short_name)
237
216
 
238
 
    def get_permissions(self, user):
239
 
        perms = set()
240
 
        if user is not None:
241
 
            perms.add('view')
242
 
            if user.rolenm == 'admin':
243
 
                perms.add('edit')
244
 
        return perms
245
 
 
246
217
class Semester(Storm):
247
218
    __storm_table__ = "semester"
248
219
 
275
246
                           'User.id')
276
247
    project_sets = ReferenceSet(id, 'ProjectSet.offering_id')
277
248
 
278
 
    worksheets = ReferenceSet(id, 
279
 
        'Worksheet.offering_id', 
280
 
        order_by="Worksheet.seq_no"
281
 
    )
282
 
 
283
249
    __init__ = _kwarg_init
284
250
 
285
251
    def __repr__(self):
298
264
        e = Enrolment(user=user, offering=self, active=True)
299
265
        self.enrolments.add(e)
300
266
 
301
 
    def get_permissions(self, user):
302
 
        perms = set()
303
 
        if user is not None:
304
 
            perms.add('view')
305
 
            if user.rolenm in ('admin', 'lecturer'):
306
 
                perms.add('edit')
307
 
        return perms
308
 
 
309
267
class Enrolment(Storm):
310
268
    __storm_table__ = "enrolment"
311
269
    __storm_primary__ = "user_id", "offering_id"
410
368
# WORKSHEETS AND EXERCISES #
411
369
 
412
370
class Exercise(Storm):
413
 
    __storm_table__ = "exercise"
414
 
    id = Unicode(primary=True, name="identifier")
415
 
    name = Unicode()
416
 
    description = Unicode()
417
 
    partial = Unicode()
418
 
    solution = Unicode()
419
 
    include = Unicode()
420
 
    num_rows = Int()
 
371
    # Note: Table "problem" is called "Exercise" in the Object layer, since
 
372
    # it's called that everywhere else.
 
373
    __storm_table__ = "problem"
 
374
 
 
375
    id = Int(primary=True, name="problemid")
 
376
    name = Unicode(name="identifier")
 
377
    spec = Unicode()
421
378
 
422
379
    worksheets = ReferenceSet(id,
423
380
        'WorksheetExercise.exercise_id',
424
381
        'WorksheetExercise.worksheet_id',
425
382
        'Worksheet.id'
426
383
    )
427
 
    
428
 
    test_suites = ReferenceSet(id, 'TestSuite.exercise_id')
429
384
 
430
385
    __init__ = _kwarg_init
431
386
 
432
387
    def __repr__(self):
433
388
        return "<%s %s>" % (type(self).__name__, self.name)
434
389
 
435
 
    def get_permissions(self, user):
436
 
        perms = set()
437
 
        if user is not None:
438
 
            if user.rolenm in ('admin', 'lecturer'):
439
 
                perms.add('edit')
440
 
                perms.add('view')
441
 
        return perms
 
390
    @classmethod
 
391
    def get_by_name(cls, store, name):
 
392
        """
 
393
        Get the Exercise from the db associated with a given store and name.
 
394
        If the exercise is not in the database, creates it and inserts it
 
395
        automatically.
 
396
        """
 
397
        ex = store.find(cls, cls.name == unicode(name)).one()
 
398
        if ex is not None:
 
399
            return ex
 
400
        ex = Exercise(name=unicode(name))
 
401
        store.add(ex)
 
402
        store.commit()
 
403
        return ex
442
404
 
443
405
class Worksheet(Storm):
444
406
    __storm_table__ = "worksheet"
445
407
 
446
408
    id = Int(primary=True, name="worksheetid")
447
 
    offering_id = Int(name="offeringid")
448
 
    identifier = Unicode()
449
 
    name = Unicode()
 
409
    # XXX subject is not linked to a Subject object. This is a property of
 
410
    # the database, and will be refactored.
 
411
    subject = Unicode()
 
412
    name = Unicode(name="identifier")
450
413
    assessable = Bool()
451
 
    data = Unicode()
452
 
    seq_no = Int()
453
 
    format = Unicode()
454
 
 
455
 
    attempts = ReferenceSet(id, "ExerciseAttempt.worksheetid")
456
 
    offering = Reference(offering_id, 'Offering.id')
457
 
 
 
414
    mtime = DateTime()
 
415
 
 
416
    exercises = ReferenceSet(id,
 
417
        'WorksheetExercise.worksheet_id',
 
418
        'WorksheetExercise.exercise_id',
 
419
        Exercise.id)
458
420
    # Use worksheet_exercises to get access to the WorksheetExercise objects
459
421
    # binding worksheets to exercises. This is required to access the
460
422
    # "optional" field.
461
423
    worksheet_exercises = ReferenceSet(id,
462
424
        'WorksheetExercise.worksheet_id')
463
 
        
464
425
 
465
426
    __init__ = _kwarg_init
466
427
 
487
448
        """
488
449
        store.find(WorksheetExercise,
489
450
            WorksheetExercise.worksheet == self).remove()
490
 
            
491
 
    def get_permissions(self, user):
492
 
        return self.offering.get_permissions(user)
493
451
 
494
452
class WorksheetExercise(Storm):
495
 
    __storm_table__ = "worksheet_exercise"
496
 
    
497
 
    id = Int(primary=True, name="ws_ex_id")
 
453
    __storm_table__ = "worksheet_problem"
 
454
    __storm_primary__ = "worksheet_id", "exercise_id"
498
455
 
499
456
    worksheet_id = Int(name="worksheetid")
500
457
    worksheet = Reference(worksheet_id, Worksheet.id)
501
 
    exercise_id = Unicode(name="exerciseid")
 
458
    exercise_id = Int(name="problemid")
502
459
    exercise = Reference(exercise_id, Exercise.id)
503
460
    optional = Bool()
504
 
    active = Bool()
505
 
    seq_no = Int()
506
 
    
507
 
    saves = ReferenceSet(id, "ExerciseSave.ws_ex_id")
508
 
    attempts = ReferenceSet(id, "ExerciseAttempt.ws_ex_id")
509
461
 
510
462
    __init__ = _kwarg_init
511
463
 
512
464
    def __repr__(self):
513
465
        return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
514
 
                                  self.worksheet.identifier)
 
466
                                  self.worksheet.name)
515
467
 
516
468
class ExerciseSave(Storm):
517
469
    """
522
474
    ExerciseSave may be extended with additional semantics (such as
523
475
    ExerciseAttempt).
524
476
    """
525
 
    __storm_table__ = "exercise_save"
526
 
    __storm_primary__ = "ws_ex_id", "user_id"
527
 
 
528
 
    ws_ex_id = Int(name="ws_ex_id")
529
 
    worksheet_exercise = Reference(ws_ex_id, "WorksheetExercise.id")
530
 
 
 
477
    __storm_table__ = "problem_save"
 
478
    __storm_primary__ = "exercise_id", "user_id", "date"
 
479
 
 
480
    exercise_id = Int(name="problemid")
 
481
    exercise = Reference(exercise_id, Exercise.id)
531
482
    user_id = Int(name="loginid")
532
483
    user = Reference(user_id, User.id)
533
484
    date = DateTime()
552
503
        they won't count (either as a penalty or success), but will still be
553
504
        stored.
554
505
    """
555
 
    __storm_table__ = "exercise_attempt"
556
 
    __storm_primary__ = "ws_ex_id", "user_id", "date"
 
506
    __storm_table__ = "problem_attempt"
 
507
    __storm_primary__ = "exercise_id", "user_id", "date"
557
508
 
558
509
    # The "text" field is the same but has a different name in the DB table
559
510
    # for some reason.
560
511
    text = Unicode(name="attempt")
561
512
    complete = Bool()
562
513
    active = Bool()
563
 
    
564
 
    def get_permissions(self, user):
565
 
        return set(['view']) if user is self.user else set()
566
 
  
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"
571
 
    
572
 
    suiteid = Int()
573
 
    exercise_id = Unicode(name="exerciseid")
574
 
    description = Unicode()
575
 
    seq_no = Int()
576
 
    function = Unicode()
577
 
    stdin = Unicode()
578
 
    exercise = Reference(exercise_id, Exercise.id)
579
 
    test_cases = ReferenceSet(suiteid, 'TestCase.suiteid')
580
 
    variables = ReferenceSet(suiteid, 'TestSuiteVar.suiteid')
581
 
 
582
 
class TestCase(Storm):
583
 
    """A TestCase is a member of a TestSuite.
584
 
    
585
 
    It contains the data necessary to check if an exercise is correct"""
586
 
    __storm_table__ = "test_case"
587
 
    __storm_primary__ = "testid", "suiteid"
588
 
    
589
 
    testid = Int()
590
 
    suiteid = Int()
591
 
    suite = Reference(suiteid, "TestSuite.suiteid")
592
 
    passmsg = Unicode()
593
 
    failmsg = Unicode()
594
 
    test_default = Unicode()
595
 
    seq_no = Int()
596
 
    
597
 
    parts = ReferenceSet(testid, "TestCasePart.testid")
598
 
    
599
 
    __init__ = _kwarg_init
600
 
 
601
 
class TestSuiteVar(Storm):
602
 
    """A container for the arguments of a Test Suite"""
603
 
    __storm_table__ = "suite_variable"
604
 
    __storm_primary__ = "varid"
605
 
    
606
 
    varid = Int()
607
 
    suiteid = Int()
608
 
    var_name = Unicode()
609
 
    var_value = Unicode()
610
 
    var_type = Unicode()
611
 
    arg_no = Int()
612
 
    
613
 
    suite = Reference(suiteid, "TestSuite.suiteid")
614
 
    
615
 
    __init__ = _kwarg_init
616
 
    
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"
621
 
    
622
 
    partid = Int()
623
 
    testid = Int()
624
 
    
625
 
    part_type = Unicode()
626
 
    test_type = Unicode()
627
 
    data = Unicode()
628
 
    filename = Unicode()
629
 
    
630
 
    test = Reference(testid, "TestCase.testid")
631
 
    
632
 
    __init__ = _kwarg_init