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

« back to all changes in this revision

Viewing changes to ivle/database.py

  • Committer: William Grant
  • Date: 2010-02-11 05:09:56 UTC
  • Revision ID: grantw@unimelb.edu.au-20100211050956-t5i2z6b8iulxteza
Unbreak existing tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
 
29
29
from storm.locals import create_database, Store, Int, Unicode, DateTime, \
30
30
                         Reference, ReferenceSet, Bool, Storm, Desc
 
31
from storm.expr import Select, Max
31
32
from storm.exceptions import NotOneError, IntegrityError
32
33
 
33
34
from ivle.worksheet.rst import rst
116
117
 
117
118
    @property
118
119
    def display_name(self):
 
120
        """Returns the "nice name" of the user or group."""
119
121
        return self.fullname
120
122
 
121
123
    @property
 
124
    def short_name(self):
 
125
        """Returns the database "identifier" name of the user or group."""
 
126
        return self.login
 
127
 
 
128
    @property
122
129
    def password_expired(self):
123
130
        fieldval = self.pass_exp
124
131
        return fieldval is not None and datetime.datetime.now() > fieldval
227
234
        they may do everything. Otherwise they may do nothing.
228
235
        """
229
236
        if user and user.admin or user is self:
230
 
            return set(['view', 'edit', 'submit_project'])
 
237
            return set(['view_public', 'view', 'edit', 'submit_project'])
231
238
        else:
232
 
            return set()
 
239
            return set(['view_public'])
233
240
 
234
241
# SUBJECTS AND ENROLMENTS #
235
242
 
242
249
    code = Unicode(name="subj_code")
243
250
    name = Unicode(name="subj_name")
244
251
    short_name = Unicode(name="subj_short_name")
245
 
    url = Unicode()
246
252
 
247
253
    offerings = ReferenceSet(id, 'Offering.subject_id')
248
254
 
315
321
    subject = Reference(subject_id, Subject.id)
316
322
    semester_id = Int(name="semesterid")
317
323
    semester = Reference(semester_id, Semester.id)
 
324
    description = Unicode()
 
325
    url = Unicode()
318
326
    groups_student_permissions = Unicode()
319
327
 
320
328
    enrolments = ReferenceSet(id, 'Enrolment.offering_id')
323
331
                           'Enrolment.user_id',
324
332
                           'User.id')
325
333
    project_sets = ReferenceSet(id, 'ProjectSet.offering_id')
 
334
    projects = ReferenceSet(id,
 
335
                            'ProjectSet.offering_id',
 
336
                            'ProjectSet.id',
 
337
                            'Project.project_set_id')
326
338
 
327
339
    worksheets = ReferenceSet(id, 
328
340
        'Worksheet.offering_id', 
368
380
            if (enrolment and enrolment.role in (u'tutor', u'lecturer')) \
369
381
               or user.admin:
370
382
                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
371
391
        return perms
372
392
 
373
393
    def get_enrolment(self, user):
379
399
 
380
400
        return enrolment
381
401
 
 
402
    def get_members_by_role(self, role):
 
403
        return Store.of(self).find(User,
 
404
                Enrolment.user_id == User.id,
 
405
                Enrolment.offering_id == self.id,
 
406
                Enrolment.role == role
 
407
                ).order_by(User.login)
 
408
 
 
409
    @property
 
410
    def students(self):
 
411
        return self.get_members_by_role(u'student')
 
412
 
 
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
 
382
418
class Enrolment(Storm):
383
419
    """An enrolment of a user in an offering.
384
420
 
438
474
    def get_permissions(self, user):
439
475
        return self.offering.get_permissions(user)
440
476
 
 
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
    @property
 
507
    def assigned(self):
 
508
        """Get the entities (groups or users) assigned to submit this project.
 
509
 
 
510
        This will be a Storm ResultSet.
 
511
        """
 
512
        #If its a solo project, return everyone in offering
 
513
        if self.is_group:
 
514
            return self.project_groups
 
515
        else:
 
516
            return self.offering.students
 
517
 
441
518
class Project(Storm):
442
519
    """A student project for which submissions can be made."""
443
520
 
494
571
    def get_permissions(self, user):
495
572
        return self.project_set.offering.get_permissions(user)
496
573
 
 
574
    @property
 
575
    def latest_submissions(self):
 
576
        """Return the latest submission for each Assessed."""
 
577
        return Store.of(self).find(ProjectSubmission,
 
578
            Assessed.project_id == self.id,
 
579
            ProjectSubmission.assessed_id == Assessed.id,
 
580
            ProjectSubmission.date_submitted == Select(
 
581
                    Max(ProjectSubmission.date_submitted),
 
582
                    ProjectSubmission.assessed_id == Assessed.id,
 
583
                    tables=ProjectSubmission
 
584
            )
 
585
        )
 
586
 
 
587
    def has_deadline_passed(self, user):
 
588
        """Check whether the deadline has passed."""
 
589
        # XXX: Need to respect extensions.
 
590
        return self.deadline < datetime.datetime.now()
 
591
 
 
592
    def get_submissions_for_principal(self, principal):
 
593
        """Fetch a ResultSet of all submissions by a particular principal."""
 
594
        assessed = Assessed.get(Store.of(self), principal, self)
 
595
        if assessed is None:
 
596
            return
 
597
        return assessed.submissions
 
598
 
 
599
 
497
600
 
498
601
class ProjectGroup(Storm):
499
602
    """A group of students working together on a project."""
522
625
 
523
626
    @property
524
627
    def display_name(self):
525
 
        return '%s (%s)' % (self.nick, self.name)
 
628
        """Returns the "nice name" of the user or group."""
 
629
        return self.nick
 
630
 
 
631
    @property
 
632
    def short_name(self):
 
633
        """Returns the database "identifier" name of the user or group."""
 
634
        return self.name
526
635
 
527
636
    def get_projects(self, offering=None, active_only=True):
528
637
        '''Find projects that the group can submit.
586
695
    project = Reference(project_id, Project.id)
587
696
 
588
697
    extensions = ReferenceSet(id, 'ProjectExtension.assessed_id')
589
 
    submissions = ReferenceSet(id, 'ProjectSubmission.assessed_id')
 
698
    submissions = ReferenceSet(
 
699
        id, 'ProjectSubmission.assessed_id', order_by='date_submitted')
590
700
 
591
701
    def __repr__(self):
592
702
        return "<%s %r in %r>" % (type(self).__name__,
593
703
            self.user or self.project_group, self.project)
594
704
 
595
705
    @property
 
706
    def is_group(self):
 
707
        """True if the Assessed is a group, False if it is a user."""
 
708
        return self.project_group is not None
 
709
 
 
710
    @property
596
711
    def principal(self):
597
712
        return self.project_group or self.user
598
713
 
610
725
        a = store.find(cls,
611
726
            (t is User) or (cls.project_group_id == principal.id),
612
727
            (t is ProjectGroup) or (cls.user_id == principal.id),
613
 
            Project.id == project.id).one()
 
728
            cls.project_id == project.id).one()
614
729
 
615
730
        if a is None:
616
731
            a = cls()
905
1020
 
906
1021
    def delete(self):
907
1022
        """Delete this suite, without asking questions."""
908
 
        for vaariable in self.variables:
 
1023
        for variable in self.variables:
909
1024
            variable.delete()
910
1025
        for test_case in self.test_cases:
911
1026
            test_case.delete()
924
1039
    suite = Reference(suiteid, "TestSuite.suiteid")
925
1040
    passmsg = Unicode()
926
1041
    failmsg = Unicode()
927
 
    test_default = Unicode()
 
1042
    test_default = Unicode() # Currently unused - only used for file matching.
928
1043
    seq_no = Int()
929
1044
 
930
1045
    parts = ReferenceSet(testid, "TestCasePart.testid")