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

« back to all changes in this revision

Viewing changes to ivle/database.py

  • Committer: Matt Giuca
  • Date: 2010-02-24 13:13:21 UTC
  • mfrom: (1689.1.19 worksheet-marks)
  • Revision ID: matt.giuca@gmail.com-20100224131321-eno7xbrqsyukz869
Added worksheet marks reporting UI for lecturers. This includes the ability to view worksheet marks table in the web application and download as a CSV, as well as some basic statistics on exercise completion. Removed the ivle-marks script, as now lecturers can get the same data themselves. Fixes Launchpad bug #520179.

Show diffs side-by-side

added added

removed removed

Lines of Context:
429
429
        # XXX: Respect extensions.
430
430
        return self.projects.find(Project.deadline > datetime.datetime.now())
431
431
 
432
 
    def has_worksheet_cutoff_passed(self, user):
433
 
        """Check whether the worksheet cutoff has passed.
434
 
        A user is required, in case we support extensions.
435
 
        """
436
 
        if self.worksheet_cutoff is None:
437
 
            return False
438
 
        else:
439
 
            return self.worksheet_cutoff < datetime.datetime.now()
440
 
 
441
432
    def clone_worksheets(self, source):
442
433
        """Clone all worksheets from the specified source to this offering."""
443
434
        import ivle.worksheet.utils
658
649
            return
659
650
        return assessed.submissions
660
651
 
661
 
    @property
662
 
    def can_delete(self):
663
 
        """Can only delete if there are no submissions."""
664
 
        return self.submissions.count() == 0
665
652
 
666
 
    def delete(self):
667
 
        """Delete the project. Fails if can_delete is False."""
668
 
        if not self.can_delete:
669
 
            raise IntegrityError()
670
 
        for assessed in self.assesseds:
671
 
            assessed.delete()
672
 
        Store.of(self).remove(self)
673
653
 
674
654
class ProjectGroup(Storm):
675
655
    """A group of students working together on a project."""
822
802
 
823
803
        return a
824
804
 
825
 
    def delete(self):
826
 
        """Delete the assessed. Fails if there are any submissions. Deletes
827
 
        extensions."""
828
 
        if self.submissions.count() > 0:
829
 
            raise IntegrityError()
830
 
        for extension in self.extensions:
831
 
            extension.delete()
832
 
        Store.of(self).remove(self)
833
805
 
834
806
class ProjectExtension(Storm):
835
807
    """An extension granted to a user or group on a particular project.
847
819
    approver = Reference(approver_id, User.id)
848
820
    notes = Unicode()
849
821
 
850
 
    def delete(self):
851
 
        """Delete the extension."""
852
 
        Store.of(self).remove(self)
853
 
 
854
822
class SubmissionError(Exception):
855
823
    """Denotes a validation error during submission."""
856
824
    pass
921
889
    id = Unicode(primary=True, name="identifier")
922
890
    name = Unicode()
923
891
    description = Unicode()
924
 
    _description_xhtml_cache = Unicode(name='description_xhtml_cache')
925
892
    partial = Unicode()
926
893
    solution = Unicode()
927
894
    include = Unicode()
970
937
 
971
938
        return perms
972
939
 
973
 
    def _cache_description_xhtml(self, invalidate=False):
974
 
        # Don't regenerate an existing cache unless forced.
975
 
        if self._description_xhtml_cache is not None and not invalidate:
976
 
            return
977
 
 
978
 
        if self.description:
979
 
            self._description_xhtml_cache = rst(self.description)
980
 
        else:
981
 
            self._description_xhtml_cache = None
982
 
 
983
 
    @property
984
 
    def description_xhtml(self):
985
 
        """The XHTML exercise description, converted from reStructuredText."""
986
 
        self._cache_description_xhtml()
987
 
        return self._description_xhtml_cache
988
 
 
989
 
    def set_description(self, description):
990
 
        self.description = description
991
 
        self._cache_description_xhtml(invalidate=True)
 
940
    def get_description(self):
 
941
        """Return the description interpreted as reStructuredText."""
 
942
        return rst(self.description)
992
943
 
993
944
    def delete(self):
994
945
        """Deletes the exercise, providing it has no associated worksheets."""
1013
964
    assessable = Bool()
1014
965
    published = Bool()
1015
966
    data = Unicode()
1016
 
    _data_xhtml_cache = Unicode(name='data_xhtml_cache')
1017
967
    seq_no = Int()
1018
968
    format = Unicode()
1019
969
 
1066
1016
 
1067
1017
        return perms
1068
1018
 
1069
 
    def _cache_data_xhtml(self, invalidate=False):
1070
 
        # Don't regenerate an existing cache unless forced.
1071
 
        if self._data_xhtml_cache is not None and not invalidate:
1072
 
            return
1073
 
 
1074
 
        if self.format == u'rst':
1075
 
            self._data_xhtml_cache = rst(self.data)
1076
 
        else:
1077
 
            self._data_xhtml_cache = None
1078
 
 
1079
 
    @property
1080
 
    def data_xhtml(self):
1081
 
        """The XHTML of this worksheet, converted from rST if required."""
1082
 
        # Update the rST -> XHTML cache, if required.
1083
 
        self._cache_data_xhtml()
1084
 
 
1085
 
        if self.format == u'rst':
1086
 
            return self._data_xhtml_cache
 
1019
    def get_xml(self):
 
1020
        """Returns the xml of this worksheet, converts from rst if required."""
 
1021
        if self.format == u'rst':
 
1022
            ws_xml = rst(self.data)
 
1023
            return ws_xml
1087
1024
        else:
1088
1025
            return self.data
1089
1026
 
1090
 
    def set_data(self, data):
1091
 
        self.data = data
1092
 
        self._cache_data_xhtml(invalidate=True)
1093
 
 
1094
1027
    def delete(self):
1095
1028
        """Deletes the worksheet, provided it has no attempts on any exercises.
1096
1029