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

« back to all changes in this revision

Viewing changes to ivle/database.py

  • Committer: William Grant
  • Date: 2009-05-26 02:02:56 UTC
  • Revision ID: grantw@unimelb.edu.au-20090526020256-py3q01f6l7f6nwbu
Add some doctests to ivle.date.

Show diffs side-by-side

added added

removed removed

Lines of Context:
234
234
        they may do everything. Otherwise they may do nothing.
235
235
        """
236
236
        if user and user.admin or user is self:
237
 
            return set(['view_public', 'view', 'edit', 'submit_project'])
 
237
            return set(['view', 'edit', 'submit_project'])
238
238
        else:
239
 
            return set(['view_public'])
 
239
            return set()
240
240
 
241
241
# SUBJECTS AND ENROLMENTS #
242
242
 
249
249
    code = Unicode(name="subj_code")
250
250
    name = Unicode(name="subj_name")
251
251
    short_name = Unicode(name="subj_short_name")
 
252
    url = Unicode()
252
253
 
253
254
    offerings = ReferenceSet(id, 'Offering.subject_id')
254
255
 
321
322
    subject = Reference(subject_id, Subject.id)
322
323
    semester_id = Int(name="semesterid")
323
324
    semester = Reference(semester_id, Semester.id)
324
 
    description = Unicode()
325
 
    url = Unicode()
326
325
    groups_student_permissions = Unicode()
327
326
 
328
327
    enrolments = ReferenceSet(id, 'Enrolment.offering_id')
331
330
                           'Enrolment.user_id',
332
331
                           'User.id')
333
332
    project_sets = ReferenceSet(id, 'ProjectSet.offering_id')
334
 
    projects = ReferenceSet(id,
335
 
                            'ProjectSet.offering_id',
336
 
                            'ProjectSet.id',
337
 
                            'Project.project_set_id')
338
333
 
339
334
    worksheets = ReferenceSet(id, 
340
335
        'Worksheet.offering_id', 
380
375
            if (enrolment and enrolment.role in (u'tutor', u'lecturer')) \
381
376
               or user.admin:
382
377
                perms.add('edit')
383
 
                # XXX Bug #493945 -- should tutors have these permissions?
384
 
                # Potentially move into the next category (lecturer & admin)
385
 
                perms.add('enrol')          # Can see enrolment screen at all
386
 
                perms.add('enrol_student')  # Can enrol students
387
 
            if (enrolment and enrolment.role in (u'lecturer')) or user.admin:
388
 
                perms.add('enrol_tutor')    # Can enrol tutors
389
 
            if user.admin:
390
 
                perms.add('enrol_lecturer') # Can enrol lecturers
391
378
        return perms
392
379
 
393
380
    def get_enrolment(self, user):
404
391
                Enrolment.user_id == User.id,
405
392
                Enrolment.offering_id == self.id,
406
393
                Enrolment.role == role
407
 
                ).order_by(User.login)
 
394
                )
408
395
 
409
396
    @property
410
397
    def students(self):
411
398
        return self.get_members_by_role(u'student')
412
399
 
413
 
    def get_open_projects_for_user(self, user):
414
 
        """Find all projects currently open to submissions by a user."""
415
 
        # XXX: Respect extensions.
416
 
        return self.projects.find(Project.deadline > datetime.datetime.now())
417
 
 
418
400
class Enrolment(Storm):
419
401
    """An enrolment of a user in an offering.
420
402
 
474
456
    def get_permissions(self, user):
475
457
        return self.offering.get_permissions(user)
476
458
 
477
 
    def get_groups_for_user(self, user):
478
 
        """List all groups in this offering of which the user is a member."""
479
 
        assert self.is_group
480
 
        return Store.of(self).find(
481
 
            ProjectGroup,
482
 
            ProjectGroupMembership.user_id == user.id,
483
 
            ProjectGroupMembership.project_group_id == ProjectGroup.id,
484
 
            ProjectGroup.project_set_id == self.id)
485
 
 
486
 
    def get_submission_principal(self, user):
487
 
        """Get the principal on behalf of which the user can submit.
488
 
 
489
 
        If this is a solo project set, the given user is returned. If
490
 
        the user is a member of exactly one group, all the group is
491
 
        returned. Otherwise, None is returned.
492
 
        """
493
 
        if self.is_group:
494
 
            groups = self.get_groups_for_user(user)
495
 
            if groups.count() == 1:
496
 
                return groups.one()
497
 
            else:
498
 
                return None
499
 
        else:
500
 
            return user
501
 
 
502
 
    @property
503
 
    def is_group(self):
504
 
        return self.max_students_per_group is not None
505
 
 
506
459
    @property
507
460
    def assigned(self):
508
461
        """Get the entities (groups or users) assigned to submit this project.
510
463
        This will be a Storm ResultSet.
511
464
        """
512
465
        #If its a solo project, return everyone in offering
513
 
        if self.is_group:
 
466
        if self.max_students_per_group is None:
 
467
            return self.offering.students
 
468
        else:
514
469
            return self.project_groups
515
 
        else:
516
 
            return self.offering.students
517
 
 
518
 
class DeadlinePassed(Exception):
519
 
    """An exception indicating that a project cannot be submitted because the
520
 
    deadline has passed."""
521
 
    def __init__(self):
522
 
        pass
523
 
    def __str__(self):
524
 
        return "The project deadline has passed"
525
470
 
526
471
class Project(Storm):
527
472
    """A student project for which submissions can be made."""
549
494
        return "<%s '%s' in %r>" % (type(self).__name__, self.short_name,
550
495
                                  self.project_set.offering)
551
496
 
552
 
    def can_submit(self, principal, user):
 
497
    def can_submit(self, principal):
553
498
        return (self in principal.get_projects() and
554
 
                not self.has_deadline_passed(user))
 
499
                self.deadline > datetime.datetime.now())
555
500
 
556
501
    def submit(self, principal, path, revision, who):
557
502
        """Submit a Subversion path and revision to a project.
563
508
        @param who: The user who is actually making the submission.
564
509
        """
565
510
 
566
 
        if not self.can_submit(principal, who):
567
 
            raise DeadlinePassed()
 
511
        if not self.can_submit(principal):
 
512
            raise Exception('cannot submit')
568
513
 
569
514
        a = Assessed.get(Store.of(self), principal, self)
570
515
        ps = ProjectSubmission()
592
537
            )
593
538
        )
594
539
 
595
 
    def has_deadline_passed(self, user):
596
 
        """Check whether the deadline has passed."""
597
 
        # XXX: Need to respect extensions.
598
 
        return self.deadline < datetime.datetime.now()
599
 
 
600
 
    def get_submissions_for_principal(self, principal):
601
 
        """Fetch a ResultSet of all submissions by a particular principal."""
602
 
        assessed = Assessed.get(Store.of(self), principal, self)
603
 
        if assessed is None:
604
 
            return
605
 
        return assessed.submissions
606
 
 
607
 
 
608
540
 
609
541
class ProjectGroup(Storm):
610
542
    """A group of students working together on a project."""
703
635
    project = Reference(project_id, Project.id)
704
636
 
705
637
    extensions = ReferenceSet(id, 'ProjectExtension.assessed_id')
706
 
    submissions = ReferenceSet(
707
 
        id, 'ProjectSubmission.assessed_id', order_by='date_submitted')
 
638
    submissions = ReferenceSet(id, 'ProjectSubmission.assessed_id')
708
639
 
709
640
    def __repr__(self):
710
641
        return "<%s %r in %r>" % (type(self).__name__,
719
650
    def principal(self):
720
651
        return self.project_group or self.user
721
652
 
722
 
    @property
723
 
    def checkout_location(self):
724
 
        """Returns the location of the Subversion workspace for this piece of
725
 
        assessment, relative to each group member's home directory."""
726
 
        subjectname = self.project.project_set.offering.subject.short_name
727
 
        if self.is_group:
728
 
            checkout_dir_name = self.principal.short_name
729
 
        else:
730
 
            checkout_dir_name = "mywork"
731
 
        return subjectname + "/" + checkout_dir_name
732
 
 
733
653
    @classmethod
734
654
    def get(cls, store, principal, project):
735
655
        """Find or create an Assessed for the given user or group and project.
744
664
        a = store.find(cls,
745
665
            (t is User) or (cls.project_group_id == principal.id),
746
666
            (t is ProjectGroup) or (cls.user_id == principal.id),
747
 
            cls.project_id == project.id).one()
 
667
            Project.id == project.id).one()
748
668
 
749
669
        if a is None:
750
670
            a = cls()
795
715
    submitter = Reference(submitter_id, User.id)
796
716
    date_submitted = DateTime()
797
717
 
798
 
    def get_verify_url(self, user):
799
 
        """Get the URL for verifying this submission, within the account of
800
 
        the given user."""
801
 
        # If this is a solo project, then self.path will be prefixed with the
802
 
        # subject name. Remove the first path segment.
803
 
        submitpath = self.path[1:] if self.path[:1] == '/' else self.path
804
 
        if not self.assessed.is_group:
805
 
            if '/' in submitpath:
806
 
                submitpath = submitpath.split('/', 1)[1]
807
 
            else:
808
 
                submitpath = ''
809
 
        return "/files/%s/%s/%s?r=%d" % (user.login,
810
 
            self.assessed.checkout_location, submitpath, self.revision)
811
718
 
812
719
# WORKSHEETS AND EXERCISES #
813
720
 
1052
959
 
1053
960
    def delete(self):
1054
961
        """Delete this suite, without asking questions."""
1055
 
        for variable in self.variables:
 
962
        for vaariable in self.variables:
1056
963
            variable.delete()
1057
964
        for test_case in self.test_cases:
1058
965
            test_case.delete()
1071
978
    suite = Reference(suiteid, "TestSuite.suiteid")
1072
979
    passmsg = Unicode()
1073
980
    failmsg = Unicode()
1074
 
    test_default = Unicode() # Currently unused - only used for file matching.
 
981
    test_default = Unicode()
1075
982
    seq_no = Int()
1076
983
 
1077
984
    parts = ReferenceSet(testid, "TestCasePart.testid")