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

« back to all changes in this revision

Viewing changes to ivle/database.py

  • Committer: William Grant
  • Date: 2009-06-29 01:55:55 UTC
  • mto: This revision was merged to the branch mainline in revision 1322.
  • Revision ID: grantw@unimelb.edu.au-20090629015555-49xxv0piiieunx8e
Add docs on configuring Apache.

Show diffs side-by-side

added added

removed removed

Lines of Context:
215
215
            Semester.id == Offering.semester_id,
216
216
            (not active_only) or (Semester.state == u'current'),
217
217
            Enrolment.offering_id == Offering.id,
218
 
            Enrolment.user_id == self.id,
219
 
            Enrolment.active == True)
 
218
            Enrolment.user_id == self.id)
220
219
 
221
220
    @staticmethod
222
221
    def hash_password(password):
228
227
        """Find a user in a store by login name."""
229
228
        return store.find(cls, cls.login == unicode(login)).one()
230
229
 
231
 
    def get_permissions(self, user, config):
 
230
    def get_permissions(self, user):
232
231
        """Determine privileges held by a user over this object.
233
232
 
234
233
        If the user requesting privileges is this user or an admin,
235
234
        they may do everything. Otherwise they may do nothing.
236
235
        """
237
236
        if user and user.admin or user is self:
238
 
            return set(['view_public', 'view', 'edit', 'submit_project'])
 
237
            return set(['view', 'edit', 'submit_project'])
239
238
        else:
240
 
            return set(['view_public'])
 
239
            return set()
241
240
 
242
241
# SUBJECTS AND ENROLMENTS #
243
242
 
250
249
    code = Unicode(name="subj_code")
251
250
    name = Unicode(name="subj_name")
252
251
    short_name = Unicode(name="subj_short_name")
 
252
    url = Unicode()
253
253
 
254
254
    offerings = ReferenceSet(id, 'Offering.subject_id')
255
255
 
258
258
    def __repr__(self):
259
259
        return "<%s '%s'>" % (type(self).__name__, self.short_name)
260
260
 
261
 
    def get_permissions(self, user, config):
 
261
    def get_permissions(self, user):
262
262
        """Determine privileges held by a user over this object.
263
263
 
264
264
        If the user requesting privileges is an admin, they may edit.
322
322
    subject = Reference(subject_id, Subject.id)
323
323
    semester_id = Int(name="semesterid")
324
324
    semester = Reference(semester_id, Semester.id)
325
 
    description = Unicode()
326
 
    url = Unicode()
327
325
    groups_student_permissions = Unicode()
328
326
 
329
327
    enrolments = ReferenceSet(id, 'Enrolment.offering_id')
332
330
                           'Enrolment.user_id',
333
331
                           'User.id')
334
332
    project_sets = ReferenceSet(id, 'ProjectSet.offering_id')
335
 
    projects = ReferenceSet(id,
336
 
                            'ProjectSet.offering_id',
337
 
                            'ProjectSet.id',
338
 
                            'Project.project_set_id')
339
333
 
340
334
    worksheets = ReferenceSet(id, 
341
335
        'Worksheet.offering_id', 
372
366
                               Enrolment.offering_id == self.id).one()
373
367
        Store.of(enrolment).remove(enrolment)
374
368
 
375
 
    def get_permissions(self, user, config):
 
369
    def get_permissions(self, user):
376
370
        perms = set()
377
371
        if user is not None:
378
372
            enrolment = self.get_enrolment(user)
379
373
            if enrolment or user.admin:
380
374
                perms.add('view')
381
 
            if enrolment and enrolment.role == u'tutor':
382
 
                perms.add('view_project_submissions')
383
 
                # Site-specific policy on the role of tutors
384
 
                if config['policy']['tutors_can_enrol_students']:
385
 
                    perms.add('enrol')
386
 
                    perms.add('enrol_student')
387
 
                if config['policy']['tutors_can_edit_worksheets']:
388
 
                    perms.add('edit_worksheets')
389
 
                if config['policy']['tutors_can_admin_groups']:
390
 
                    perms.add('admin_groups')
391
 
            if (enrolment and enrolment.role in (u'lecturer')) or user.admin:
392
 
                perms.add('view_project_submissions')
393
 
                perms.add('admin_groups')
394
 
                perms.add('edit_worksheets')
395
 
                perms.add('edit')           # Can edit projects & details
396
 
                perms.add('enrol')          # Can see enrolment screen at all
397
 
                perms.add('enrol_student')  # Can enrol students
398
 
                perms.add('enrol_tutor')    # Can enrol tutors
399
 
            if user.admin:
400
 
                perms.add('enrol_lecturer') # Can enrol lecturers
 
375
            if (enrolment and enrolment.role in (u'tutor', u'lecturer')) \
 
376
               or user.admin:
 
377
                perms.add('edit')
401
378
        return perms
402
379
 
403
380
    def get_enrolment(self, user):
414
391
                Enrolment.user_id == User.id,
415
392
                Enrolment.offering_id == self.id,
416
393
                Enrolment.role == role
417
 
                ).order_by(User.login)
 
394
                )
418
395
 
419
396
    @property
420
397
    def students(self):
421
398
        return self.get_members_by_role(u'student')
422
399
 
423
 
    def get_open_projects_for_user(self, user):
424
 
        """Find all projects currently open to submissions by a user."""
425
 
        # XXX: Respect extensions.
426
 
        return self.projects.find(Project.deadline > datetime.datetime.now())
427
 
 
428
 
    def clone_worksheets(self, source):
429
 
        """Clone all worksheets from the specified source to this offering."""
430
 
        import ivle.worksheet.utils
431
 
        for worksheet in source.worksheets:
432
 
            newws = Worksheet()
433
 
            newws.seq_no = worksheet.seq_no
434
 
            newws.identifier = worksheet.identifier
435
 
            newws.name = worksheet.name
436
 
            newws.assessable = worksheet.assessable
437
 
            newws.data = worksheet.data
438
 
            newws.format = worksheet.format
439
 
            newws.offering = self
440
 
            Store.of(self).add(newws)
441
 
            ivle.worksheet.utils.update_exerciselist(newws)
442
 
 
443
 
 
444
400
class Enrolment(Storm):
445
401
    """An enrolment of a user in an offering.
446
402
 
472
428
        return "<%s %r in %r>" % (type(self).__name__, self.user,
473
429
                                  self.offering)
474
430
 
475
 
    def get_permissions(self, user, config):
476
 
        # A user can edit any enrolment that they could have created.
477
 
        perms = set()
478
 
        if ('enrol_' + str(self.role)) in self.offering.get_permissions(
479
 
            user, config):
480
 
            perms.add('edit')
481
 
        return perms
482
 
 
483
 
    def delete(self):
484
 
        """Delete this enrolment."""
485
 
        Store.of(self).remove(self)
486
 
 
487
 
 
488
431
# PROJECTS #
489
432
 
490
433
class ProjectSet(Storm):
510
453
        return "<%s %d in %r>" % (type(self).__name__, self.id,
511
454
                                  self.offering)
512
455
 
513
 
    def get_permissions(self, user, config):
514
 
        return self.offering.get_permissions(user, config)
515
 
 
516
 
    def get_groups_for_user(self, user):
517
 
        """List all groups in this offering of which the user is a member."""
518
 
        assert self.is_group
519
 
        return Store.of(self).find(
520
 
            ProjectGroup,
521
 
            ProjectGroupMembership.user_id == user.id,
522
 
            ProjectGroupMembership.project_group_id == ProjectGroup.id,
523
 
            ProjectGroup.project_set_id == self.id)
524
 
 
525
 
    def get_submission_principal(self, user):
526
 
        """Get the principal on behalf of which the user can submit.
527
 
 
528
 
        If this is a solo project set, the given user is returned. If
529
 
        the user is a member of exactly one group, all the group is
530
 
        returned. Otherwise, None is returned.
531
 
        """
532
 
        if self.is_group:
533
 
            groups = self.get_groups_for_user(user)
534
 
            if groups.count() == 1:
535
 
                return groups.one()
536
 
            else:
537
 
                return None
538
 
        else:
539
 
            return user
540
 
 
541
 
    @property
542
 
    def is_group(self):
543
 
        return self.max_students_per_group is not None
 
456
    def get_permissions(self, user):
 
457
        return self.offering.get_permissions(user)
544
458
 
545
459
    @property
546
460
    def assigned(self):
549
463
        This will be a Storm ResultSet.
550
464
        """
551
465
        #If its a solo project, return everyone in offering
552
 
        if self.is_group:
 
466
        if self.max_students_per_group is None:
 
467
            return self.offering.students
 
468
        else:
553
469
            return self.project_groups
554
 
        else:
555
 
            return self.offering.students
556
 
 
557
 
class DeadlinePassed(Exception):
558
 
    """An exception indicating that a project cannot be submitted because the
559
 
    deadline has passed."""
560
 
    def __init__(self):
561
 
        pass
562
 
    def __str__(self):
563
 
        return "The project deadline has passed"
564
470
 
565
471
class Project(Storm):
566
472
    """A student project for which submissions can be made."""
588
494
        return "<%s '%s' in %r>" % (type(self).__name__, self.short_name,
589
495
                                  self.project_set.offering)
590
496
 
591
 
    def can_submit(self, principal, user):
 
497
    def can_submit(self, principal):
592
498
        return (self in principal.get_projects() and
593
 
                not self.has_deadline_passed(user))
 
499
                self.deadline > datetime.datetime.now())
594
500
 
595
501
    def submit(self, principal, path, revision, who):
596
502
        """Submit a Subversion path and revision to a project.
602
508
        @param who: The user who is actually making the submission.
603
509
        """
604
510
 
605
 
        if not self.can_submit(principal, who):
606
 
            raise DeadlinePassed()
 
511
        if not self.can_submit(principal):
 
512
            raise Exception('cannot submit')
607
513
 
608
514
        a = Assessed.get(Store.of(self), principal, self)
609
515
        ps = ProjectSubmission()
615
521
 
616
522
        return ps
617
523
 
618
 
    def get_permissions(self, user, config):
619
 
        return self.project_set.offering.get_permissions(user, config)
 
524
    def get_permissions(self, user):
 
525
        return self.project_set.offering.get_permissions(user)
620
526
 
621
527
    @property
622
528
    def latest_submissions(self):
631
537
            )
632
538
        )
633
539
 
634
 
    def has_deadline_passed(self, user):
635
 
        """Check whether the deadline has passed."""
636
 
        # XXX: Need to respect extensions.
637
 
        return self.deadline < datetime.datetime.now()
638
 
 
639
 
    def get_submissions_for_principal(self, principal):
640
 
        """Fetch a ResultSet of all submissions by a particular principal."""
641
 
        assessed = Assessed.get(Store.of(self), principal, self)
642
 
        if assessed is None:
643
 
            return
644
 
        return assessed.submissions
645
 
 
646
 
 
647
540
 
648
541
class ProjectGroup(Storm):
649
542
    """A group of students working together on a project."""
700
593
            (not active_only) or (Semester.state == u'current'))
701
594
 
702
595
 
703
 
    def get_permissions(self, user, config):
 
596
    def get_permissions(self, user):
704
597
        if user.admin or user in self.members:
705
598
            return set(['submit_project'])
706
599
        else:
742
635
    project = Reference(project_id, Project.id)
743
636
 
744
637
    extensions = ReferenceSet(id, 'ProjectExtension.assessed_id')
745
 
    submissions = ReferenceSet(
746
 
        id, 'ProjectSubmission.assessed_id', order_by='date_submitted')
 
638
    submissions = ReferenceSet(id, 'ProjectSubmission.assessed_id')
747
639
 
748
640
    def __repr__(self):
749
641
        return "<%s %r in %r>" % (type(self).__name__,
758
650
    def principal(self):
759
651
        return self.project_group or self.user
760
652
 
761
 
    @property
762
 
    def checkout_location(self):
763
 
        """Returns the location of the Subversion workspace for this piece of
764
 
        assessment, relative to each group member's home directory."""
765
 
        subjectname = self.project.project_set.offering.subject.short_name
766
 
        if self.is_group:
767
 
            checkout_dir_name = self.principal.short_name
768
 
        else:
769
 
            checkout_dir_name = "mywork"
770
 
        return subjectname + "/" + checkout_dir_name
771
 
 
772
653
    @classmethod
773
654
    def get(cls, store, principal, project):
774
655
        """Find or create an Assessed for the given user or group and project.
783
664
        a = store.find(cls,
784
665
            (t is User) or (cls.project_group_id == principal.id),
785
666
            (t is ProjectGroup) or (cls.user_id == principal.id),
786
 
            cls.project_id == project.id).one()
 
667
            Project.id == project.id).one()
787
668
 
788
669
        if a is None:
789
670
            a = cls()
834
715
    submitter = Reference(submitter_id, User.id)
835
716
    date_submitted = DateTime()
836
717
 
837
 
    def get_verify_url(self, user):
838
 
        """Get the URL for verifying this submission, within the account of
839
 
        the given user."""
840
 
        # If this is a solo project, then self.path will be prefixed with the
841
 
        # subject name. Remove the first path segment.
842
 
        submitpath = self.path[1:] if self.path[:1] == '/' else self.path
843
 
        if not self.assessed.is_group:
844
 
            if '/' in submitpath:
845
 
                submitpath = submitpath.split('/', 1)[1]
846
 
            else:
847
 
                submitpath = ''
848
 
        return "/files/%s/%s/%s?r=%d" % (user.login,
849
 
            self.assessed.checkout_location, submitpath, self.revision)
850
718
 
851
719
# WORKSHEETS AND EXERCISES #
852
720
 
883
751
    def __repr__(self):
884
752
        return "<%s %s>" % (type(self).__name__, self.name)
885
753
 
886
 
    def get_permissions(self, user, config):
887
 
        return self.global_permissions(user, config)
888
 
 
889
 
    @staticmethod
890
 
    def global_permissions(user, config):
891
 
        """Gets the set of permissions this user has over *all* exercises.
892
 
        This is used to determine who may view the exercises list, and create
893
 
        new exercises."""
 
754
    def get_permissions(self, user):
894
755
        perms = set()
895
756
        roles = set()
896
757
        if user is not None:
900
761
            elif u'lecturer' in set((e.role for e in user.active_enrolments)):
901
762
                perms.add('edit')
902
763
                perms.add('view')
903
 
            elif (config['policy']['tutors_can_edit_worksheets']
904
 
            and u'tutor' in set((e.role for e in user.active_enrolments))):
905
 
                # Site-specific policy on the role of tutors
 
764
            elif u'tutor' in set((e.role for e in user.active_enrolments)):
906
765
                perms.add('edit')
907
766
                perms.add('view')
908
767
 
969
828
        store.find(WorksheetExercise,
970
829
            WorksheetExercise.worksheet == self).remove()
971
830
 
972
 
    def get_permissions(self, user, config):
973
 
        # Almost the same permissions as for the offering itself
974
 
        perms = self.offering.get_permissions(user, config)
975
 
        # However, "edit" permission is derived from the "edit_worksheets"
976
 
        # permission of the offering
977
 
        if 'edit_worksheets' in perms:
978
 
            perms.add('edit')
979
 
        else:
980
 
            perms.discard('edit')
981
 
        return perms
 
831
    def get_permissions(self, user):
 
832
        return self.offering.get_permissions(user)
982
833
 
983
834
    def get_xml(self):
984
835
        """Returns the xml of this worksheet, converts from rst if required."""
1029
880
        return "<%s %s in %s>" % (type(self).__name__, self.exercise.name,
1030
881
                                  self.worksheet.identifier)
1031
882
 
1032
 
    def get_permissions(self, user, config):
1033
 
        return self.worksheet.get_permissions(user, config)
 
883
    def get_permissions(self, user):
 
884
        return self.worksheet.get_permissions(user)
1034
885
 
1035
886
 
1036
887
class ExerciseSave(Storm):
1083
934
    complete = Bool()
1084
935
    active = Bool()
1085
936
 
1086
 
    def get_permissions(self, user, config):
 
937
    def get_permissions(self, user):
1087
938
        return set(['view']) if user is self.user else set()
1088
939
 
1089
940
class TestSuite(Storm):
1108
959
 
1109
960
    def delete(self):
1110
961
        """Delete this suite, without asking questions."""
1111
 
        for variable in self.variables:
 
962
        for vaariable in self.variables:
1112
963
            variable.delete()
1113
964
        for test_case in self.test_cases:
1114
965
            test_case.delete()
1127
978
    suite = Reference(suiteid, "TestSuite.suiteid")
1128
979
    passmsg = Unicode()
1129
980
    failmsg = Unicode()
1130
 
    test_default = Unicode() # Currently unused - only used for file matching.
 
981
    test_default = Unicode()
1131
982
    seq_no = Int()
1132
983
 
1133
984
    parts = ReferenceSet(testid, "TestCasePart.testid")