source: main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py @ 13002

Last change on this file since 13002 was 13002, checked in by Henrik Bettermann, 9 years ago

More docs. Complete IStudentStudyCourse and IStudentStudyLevel interfaces and adjust unit tests.

  • Property svn:keywords set to Id
File size: 26.0 KB
Line 
1## $Id: interfaces.py 13002 2015-05-26 15:34:36Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18#from datetime import datetime
19from zope.component import getUtility
20from zope.interface import Attribute, Interface
21from zope import schema
22from zc.sourcefactory.contextual import BasicContextualSourceFactory
23from waeup.kofa.browser.interfaces import IStudentNavigationBase
24from waeup.kofa.interfaces import (
25    IKofaObject, academic_sessions_vocab, validate_email, ICSVExporter,
26    ContextualDictSourceFactoryBase)
27from waeup.kofa.interfaces import MessageFactory as _
28from waeup.kofa.schema import TextLineChoice, FormattedDate, PhoneNumber
29from waeup.kofa.students.vocabularies import (
30    StudyLevelSource, contextual_reg_num_source, contextual_mat_num_source,
31    GenderSource, nats_vocab
32    )
33from waeup.kofa.payments.interfaces import (
34    IPaymentsContainer, IOnlinePayment)
35from waeup.kofa.university.vocabularies import (
36    CourseSource, StudyModeSource, CertificateSource, SemesterSource,
37    )
38
39class PreviousPaymentCategorySource(ContextualDictSourceFactoryBase):
40    """A source that delivers all selectable categories of previous session
41    payments.
42    """
43    #: name of dict to deliver from kofa utils.
44    DICT_NAME = 'PREVIOUS_PAYMENT_CATEGORIES'
45
46class BalancePaymentCategorySource(ContextualDictSourceFactoryBase):
47    """A source that delivers all selectable items of balance payments.
48    """
49    #: name of dict to deliver from kofa utils.
50    DICT_NAME = 'BALANCE_PAYMENT_CATEGORIES'
51
52# VerdictSource can't be placed into the vocabularies module because it
53# requires importing IStudentsUtils which then leads to circular imports.
54class VerdictSource(BasicContextualSourceFactory):
55    """A verdicts source delivers all verdicts provided
56    in the portal.
57    """
58    def getValues(self, context):
59        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
60        return sorted(verdicts_dict.keys())
61
62    def getToken(self, context, value):
63        return value
64
65    def getTitle(self, context, value):
66        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
67        if value != '0':
68            return verdicts_dict[value] + ' (%s)' % value
69        return verdicts_dict[value]
70
71
72class IStudentsUtils(Interface):
73    """A collection of methods which are subject to customization.
74    """
75    def setReturningData(student):
76        """ This method defines what happens after school fee payment
77        depending on the student's senate verdict.
78
79        In the base configuration current level is always increased
80        by 100 no matter which verdict has been assigned.
81        """
82
83    def setPaymentDetails(category, student, previous_session=None,
84            previous_level=None,):
85        """Create Payment object and set the payment data of a student for
86        the payment category specified.
87        """
88
89    def increaseMatricInteger(student):
90        """Increase counter for matric numbers.
91
92        This counter can be a centrally stored attribute or an attribute of
93        faculties, departments or certificates. In the base package the counter
94        is as an attribute of the site configuration object.
95        """
96
97    def constructMatricNumber(student):
98        """Fetch the matric number counter which fits the student and
99        construct the new matric number of the student.
100
101        In the base package the counter is returned which is as an attribute
102        of the site configuration object.
103        """
104
105    def setMatricNumber(student):
106        """Set matriculation number of student.
107
108        If the student's matric number is unset a new matric number is
109        constructed according to the matriculation number construction rules
110        defined in the constructMatricNumber method. The new matric number is
111        set, the students catalog updated. The corresponding matric number
112        counter is increased by one.
113
114        This method is tested but not used in the base package. It can
115        be used in custom packages by adding respective views
116        and by customizing increaseMatricInteger and constructMatricNumber
117        according to the university's matriculation number construction rules.
118
119        The method can be disabled by setting the counter to zero.
120        """
121
122    def getAccommodation_details(student):
123        """Determine the accommodation dates of a student.
124        """
125
126    def selectBed(available_beds):
127        """Select a bed from a list of available beds.
128        In the standard configuration we select the first bed found,
129        but can also randomize the selection if we like.
130        """
131
132    def getPDFCreator(context):
133        """Get some IPDFCreator instance suitable for use with `context`.
134        """
135
136    def renderPDF(view, subject='', filename='slip.pdf',):
137        """Render pdf slips for various pages.
138        """
139
140class IStudentsContainer(IKofaObject):
141    """A students container contains university students.
142    """
143    def addStudent(student):
144        """Add an IStudent object and subcontainers.
145        """
146
147    def archive(id=None):
148        """Create on-dist archive of students.
149
150        If id is `None`, all students are archived.
151
152        If id contains a single id string, only the respective
153        students are archived.
154
155        If id contains a list of id strings all of the respective
156        students types are saved to disk.
157        """
158
159    def clear(id=None, archive=True):
160        """Remove students of type given by 'id'.
161
162        Optionally archive the students.
163
164        If id is `None`, all students are archived.
165
166        If id contains a single id string, only the respective
167        students are archived.
168
169        If id contains a list of id strings all of the respective
170        student types are saved to disk.
171
172        If `archive` is ``False`` none of the archive-handling is done
173        and respective students are simply removed from the
174        database.
175        """
176
177    unique_student_id = Attribute("""A unique student id.""")
178
179class IStudentNavigation(IStudentNavigationBase):
180    """Interface needed for student navigation, logging, etc.
181    """
182    student = Attribute('Student object of context.')
183
184    def writeLogMessage(view, message):
185        """Write a view specific log message into students.log.
186
187        """
188
189class IStudentBase(IKofaObject):
190    """Representation of student base data.
191    """
192    password = Attribute('Encrypted password')
193    temp_password = Attribute('Dictionary with user name, timestamp and encrypted password')
194    history = Attribute('Object history, a list of messages')
195    state = Attribute('Registration state')
196    certcode = Attribute('Certificate code of any chosen study course')
197    depcode = Attribute('Department code of any chosen study course')
198    faccode = Attribute('Faculty code of any chosen study course')
199    entry_session = Attribute('Entry session')
200    current_session = Attribute('Current session')
201    current_level = Attribute('Current level')
202    current_mode = Attribute('Current mode')
203    current_verdict = Attribute('Current verdict')
204    fullname = Attribute('All name parts separated by hyphens')
205    display_fullname = Attribute('Fullname as displayed on pages')
206    is_postgrad = Attribute('True if postgraduate student')
207    is_special_postgrad = Attribute('True if special postgraduate student')
208    is_fresh = Attribute('True if fresh student')
209    before_payment = Attribute('True if no previous payment has to be made')
210    personal_data_expired = Attribute('True if personal data expired')
211    transcript_enabled = Attribute('True if transcript processing is enabled')
212
213    suspended = schema.Bool(
214        title = _(u'Account suspended'),
215        default = False,
216        required = False,
217        )
218
219    suspended_comment = schema.Text(
220        title = _(u"Reasons for Deactivation"),
221        required = False,
222        description = _(
223            u'This message will be shown if and only if deactivated '
224            'students try to login.'),
225        )
226
227    student_id = schema.TextLine(
228        title = _(u'Student Id'),
229        required = False,
230        )
231
232    firstname = schema.TextLine(
233        title = _(u'First Name'),
234        required = True,
235        )
236
237    middlename = schema.TextLine(
238        title = _(u'Middle Name'),
239        required = False,
240        )
241
242    lastname = schema.TextLine(
243        title = _(u'Last Name (Surname)'),
244        required = True,
245        )
246
247    sex = schema.Choice(
248        title = _(u'Sex'),
249        source = GenderSource(),
250        required = True,
251        )
252
253    reg_number = TextLineChoice(
254        title = _(u'Registration Number'),
255        required = True,
256        readonly = False,
257        source = contextual_reg_num_source,
258        )
259
260    matric_number = TextLineChoice(
261        title = _(u'Matriculation Number'),
262        required = False,
263        readonly = False,
264        source = contextual_mat_num_source,
265        )
266
267    adm_code = schema.TextLine(
268        title = _(u'PWD Activation Code'),
269        required = False,
270        readonly = False,
271        )
272
273    email = schema.ASCIILine(
274        title = _(u'Email'),
275        required = False,
276        constraint=validate_email,
277        )
278    phone = PhoneNumber(
279        title = _(u'Phone'),
280        description = u'',
281        required = False,
282        )
283
284    def writeLogMessage(view, message):
285        """Write formatted log message into students.log.
286        """
287
288    def setTempPassword(user, password):
289        """Set a temporary password (LDAP-compatible) SSHA encoded for
290        officers.
291        """
292
293    def getTempPassword():
294        """Check if a temporary password has been set and if it
295        is not expired. Return the temporary password if valid,
296        None otherwise. Unset the temporary password if expired.
297        """
298
299    def transfer(certificate, current_session,
300        current_level, current_verdict):
301        """ Creates a new studycourse and backups the old one.
302        """
303
304    def revert_transfer():
305        """ Revert previous transfer.
306        """
307
308class IUGStudentClearance(IKofaObject):
309    """Representation of undergraduate student clearance data.
310    """
311    officer_comment = schema.Text(
312        title = _(u"Officer's Comment"),
313        required = False,
314        )
315
316    clearance_locked = schema.Bool(
317        title = _(u'Clearance form locked'),
318        default = False,
319        required = False,
320        )
321
322    clr_code = schema.TextLine(
323        title = _(u'CLR Activation Code'),
324        required = False,
325        readonly = False,
326        )
327
328    date_of_birth = FormattedDate(
329        title = _(u'Date of Birth'),
330        required = True,
331        show_year = True,
332        )
333
334    nationality = schema.Choice(
335        vocabulary = nats_vocab,
336        title = _(u'Nationality'),
337        required = False,
338        )
339
340class IPGStudentClearance(IUGStudentClearance):
341    """Representation of postgraduate student clearance data.
342    """
343    employer = schema.TextLine(
344        title = _(u'Employer'),
345        required = False,
346        readonly = False,
347        )
348
349class IStudentPersonal(IKofaObject):
350    """Representation of student personal data.
351    """
352    personal_updated = schema.Datetime(
353        title = _(u'Updated'),
354        required = False,
355        readonly = False,
356        )
357
358    perm_address = schema.Text(
359        title = _(u'Permanent Address'),
360        required = False,
361        )
362
363class IStudentTranscript(IKofaObject):
364    """Representation of student transcript data.
365    """
366
367    transcript_comment = schema.Text(
368        title = _(u'Comment'),
369        required = False,
370        )
371
372
373class IStudent(IStudentBase,IUGStudentClearance,IPGStudentClearance,
374    IStudentPersonal, IStudentTranscript):
375    """Representation of a student.
376    """
377
378class IStudentPersonalEdit(IStudentPersonal):
379    """Interface for editing personal data by students.
380    Here we can repeat the fields from IStudentPersonal and set the
381    `required` if necessary.
382    """
383
384    perm_address = schema.Text(
385        title = _(u'Permanent Address'),
386        required = True,
387        )
388
389class IStudentUpdateByRegNo(IStudent):
390    """Representation of a student. Skip regular reg_number validation.
391    """
392    reg_number = schema.TextLine(
393        title = _(u'Registration Number'),
394        required = False,
395        )
396
397class IStudentUpdateByMatricNo(IStudent):
398    """Representation of a student. Skip regular matric_number validation.
399    """
400    matric_number = schema.TextLine(
401        title = _(u'Matriculation Number'),
402        required = False,
403        )
404
405class IStudentRequestPW(IStudent):
406    """Representation of a student for first-time password request.
407    This interface is used when students use the requestpw page to
408    login for the the first time.
409    """
410    number = schema.TextLine(
411        title = _(u'Registr. or Matric. Number'),
412        required = True,
413        )
414
415    firstname = schema.TextLine(
416        title = _(u'First Name'),
417        required = True,
418        )
419
420    email = schema.ASCIILine(
421        title = _(u'Email Address'),
422        required = True,
423        constraint=validate_email,
424        )
425
426class IStudentStudyCourse(IKofaObject):
427    """Representation of student study course data.
428    """
429    student = Attribute('Student object')
430    next_session_allowed = Attribute('True if the student can proceed to next session')
431    is_postgrad = Attribute('True if student is postgraduate student')
432    is_current = Attribute('True if the study course is the current course of studies')
433    is_previous = Attribute('True if the study course is the previous course of studies')
434
435    certificate = schema.Choice(
436        title = _(u'Certificate'),
437        source = CertificateSource(),
438        required = False,
439        )
440
441    entry_mode = schema.Choice(
442        title = _(u'Entry Mode'),
443        source = StudyModeSource(),
444        required = True,
445        readonly = False,
446        )
447
448    entry_session = schema.Choice(
449        title = _(u'Entry Session'),
450        source = academic_sessions_vocab,
451        #default = datetime.now().year,
452        required = True,
453        readonly = False,
454        )
455
456    current_session = schema.Choice(
457        title = _(u'Current Session'),
458        source = academic_sessions_vocab,
459        required = True,
460        readonly = False,
461        )
462
463    current_level = schema.Choice(
464        title = _(u'Current Level'),
465        source = StudyLevelSource(),
466        required = False,
467        readonly = False,
468        )
469
470    current_verdict = schema.Choice(
471        title = _(u'Current Verdict'),
472        source = VerdictSource(),
473        default = '0',
474        required = False,
475        )
476
477    previous_verdict = schema.Choice(
478        title = _(u'Previous Verdict'),
479        source = VerdictSource(),
480        default = '0',
481        required = False,
482        )
483
484    def writeLogMessage(view, message):
485        """Write formatted log message into students.log.
486        """
487
488    def addStudentStudyLevel(cert, studylevel):
489        """Add a study level object.
490        """
491
492    def getTranscriptData():
493        """Get a sorted list of dicts with level and course ticket data.
494        This method is used for transcripts.
495        """
496
497class IStudentStudyCourseTransfer(IStudentStudyCourse):
498    """An interface used for student transfers.
499    """
500    certificate = schema.Choice(
501        title = _(u'Certificate'),
502        source = CertificateSource(),
503        required = True,
504        )
505
506    current_level = schema.Choice(
507        title = _(u'Current Level'),
508        source = StudyLevelSource(),
509        required = True,
510        readonly = False,
511        )
512
513    entry_session = schema.Choice(
514        title = _(u'Entry Session'),
515        source = academic_sessions_vocab,
516        #default = datetime.now().year,
517        required = False,
518        readonly = False,
519        )
520
521
522IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
523    'certificate'].order
524IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
525    'current_level'].order
526
527class IStudentStudyCourseTranscript(IKofaObject):
528    """An interface for student transcripts.
529    """
530    entry_mode = schema.Choice(
531        title = _(u'Entry Mode'),
532        source = StudyModeSource(),
533        required = True,
534        readonly = False,
535        )
536
537    entry_session = schema.Choice(
538        title = _(u'Entry Session'),
539        source = academic_sessions_vocab,
540        #default = datetime.now().year,
541        required = True,
542        readonly = False,
543        )
544
545class IStudentVerdictUpdate(IKofaObject):
546    """A interface for verdict imports.
547    """
548    current_verdict = schema.Choice(
549        title = _(u'Current Verdict'),
550        source = VerdictSource(),
551        required = True,
552        )
553
554    current_session = schema.Choice(
555        title = _(u'Current Session'),
556        source = academic_sessions_vocab,
557        required = True,
558        )
559
560    current_level = schema.Choice(
561        title = _(u'Current Level'),
562        source = StudyLevelSource(),
563        required = True,
564        )
565
566    bypass_validation = schema.Bool(
567        title = _(u'Bypass validation'),
568        required = False,
569        )
570
571    validated_by = schema.TextLine(
572        title = _(u'Validated by'),
573        required = False,
574        )
575
576class IStudentStudyLevel(IKofaObject):
577    """A representation of student study level data.
578    """
579    student = Attribute('Student object')
580
581    certcode = Attribute('The certificate code of the study course')
582    is_current_level = Attribute('True if level is current level of the student')
583    level_title = Attribute('Level title from source')
584    getSessionString = Attribute('Session title from source')
585    number_of_tickets = Attribute('Number of tickets contained in this level')
586    passed_params = Attribute('Information about passed and failed courses')
587    gpa_params_rectified = Attribute('Corrected sessional GPA parameters')
588    gpa_params = Attribute('GPA parameters for this level.')
589    cumulative_params = Attribute('Cumulative GPA and other cumulative parameters for this level')
590
591    level = schema.Choice(
592        title = _(u'Level'),
593        source = StudyLevelSource(),
594        required = True,
595        readonly = False,
596        )
597
598    level_session = schema.Choice(
599        title = _(u'Session'),
600        source = academic_sessions_vocab,
601        required = True,
602        )
603
604    level_verdict = schema.Choice(
605        title = _(u'Verdict'),
606        source = VerdictSource(),
607        default = '0',
608        required = False,
609        )
610
611    validated_by = schema.TextLine(
612        title = _(u'Validated by'),
613        default = None,
614        required = False,
615        )
616
617    validation_date = schema.Datetime(
618        title = _(u'Validation Date'),
619        required = False,
620        readonly = False,
621        )
622
623    total_credits = schema.Int(
624        title = _(u'Total Credits'),
625        required = False,
626        readonly = True,
627        )
628
629    gpa = schema.Int(
630        title = _(u'Unrectified GPA'),
631        required = False,
632        readonly = True,
633        )
634
635    def writeLogMessage(view, message):
636        """Write formatted log message into students.log.
637        """
638
639    def addCourseTicket(ticket, course):
640        """Add a course ticket object.
641        """
642
643    def addCertCourseTickets(cert):
644        """Collect all certificate courses and create course
645        tickets automatically.
646        """
647
648class ICourseTicket(IKofaObject):
649    """A representation of course ticket data.
650    """
651    code = Attribute('code of the original course')
652    certcode = Attribute('certificate code of the study course')
653    grade = Attribute('grade calculated from score')
654    weight = Attribute('weight calculated from score')
655    removable_by_student = Attribute('Is student allowed to remove the ticket?')
656    level_session = Attribute('session of the level the ticket has been added to')
657    level = Attribute('id of the level the ticket has been added to')
658
659    title = schema.TextLine(
660        title = _(u'Title'),
661        required = False,
662        )
663
664    fcode = schema.TextLine(
665        title = _(u'Faculty Code'),
666        required = False,
667        )
668
669    dcode = schema.TextLine(
670        title = _(u'Department Code'),
671        required = False,
672        )
673
674    semester = schema.Choice(
675        title = _(u'Semester/Term'),
676        source = SemesterSource(),
677        required = False,
678        )
679
680    passmark = schema.Int(
681        title = _(u'Passmark'),
682        required = False,
683        )
684
685    credits = schema.Int(
686        title = _(u'Credits'),
687        required = False,
688        )
689
690    mandatory = schema.Bool(
691        title = _(u'Required'),
692        default = False,
693        required = False,
694        )
695
696    score = schema.Int(
697        title = _(u'Score'),
698        default = None,
699        required = False,
700        missing_value = None,
701        )
702
703    carry_over = schema.Bool(
704        title = _(u'Carry-over Course'),
705        default = False,
706        required = False,
707        )
708
709    automatic = schema.Bool(
710        title = _(u'Automatical Creation'),
711        default = False,
712        required = False,
713        )
714
715
716class ICourseTicketAdd(IKofaObject):
717    """An interface for adding course tickets.
718    """
719    course = schema.Choice(
720        title = _(u'Course'),
721        source = CourseSource(),
722        readonly = False,
723        )
724
725class ICourseTicketImport(ICourseTicket):
726    """An interface for importing course results and nothing more.
727    """
728    score = schema.Int(
729        title = _(u'Score'),
730        required = False,
731        readonly = False,
732        )
733
734    level_session = schema.Choice(
735        title = _(u'Level Session'),
736        source = academic_sessions_vocab,
737        required = False,
738        readonly = False,
739        )
740
741class IStudentAccommodation(IKofaObject):
742    """A container for student accommodation objects.
743    """
744
745    def addBedTicket(bedticket):
746        """Add a bed ticket object.
747        """
748
749
750class IBedTicket(IKofaObject):
751    """A representation of accommodation booking data.
752    """
753    bed = Attribute('The bed object.')
754
755    bed_coordinates = schema.TextLine(
756        title = u'',
757        required = True,
758        readonly = False,
759        )
760
761    display_coordinates = schema.TextLine(
762        title = _(u'Allocated Bed'),
763        required = False,
764        readonly = True,
765        )
766
767    bed_type = schema.TextLine(
768        title = _(u'Requested Bed Type'),
769        required = True,
770        readonly = False,
771        )
772
773    booking_session = schema.Choice(
774        title = _(u'Session'),
775        source = academic_sessions_vocab,
776        required = True,
777        readonly = True,
778        )
779
780    booking_date = schema.Datetime(
781        title = _(u'Booking Date'),
782        required = False,
783        readonly = True,
784        )
785
786    booking_code = schema.TextLine(
787        title = _(u'Booking Activation Code'),
788        required = False,
789        readonly = True,
790        )
791
792    def getSessionString():
793        """Returns the title of academic_sessions_vocab term.
794        """
795
796class IStudentPaymentsContainer(IPaymentsContainer):
797    """A container for student payment objects.
798    """
799
800class IStudentOnlinePayment(IOnlinePayment):
801    """A student payment via payment gateways.
802    """
803
804    p_current = schema.Bool(
805        title = _(u'Current Session Payment'),
806        default = True,
807        required = False,
808        )
809
810    p_level = schema.Int(
811        title = _(u'Payment Level'),
812        required = False,
813        )
814
815    def doAfterStudentPayment():
816        """Process student after payment was made.
817        """
818
819    def doAfterStudentPaymentApproval():
820        """Process student after payment was approved.
821        """
822
823    def approveStudentPayment():
824        """Approve payment and process student.
825        """
826
827IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
828    'p_session'].order
829
830class IStudentPreviousPayment(IKofaObject):
831    """An interface for adding previous session payments.
832    """
833
834    p_category = schema.Choice(
835        title = _(u'Payment Category'),
836        default = u'schoolfee',
837        source = PreviousPaymentCategorySource(),
838        required = True,
839        )
840
841    p_session = schema.Choice(
842        title = _(u'Payment Session'),
843        source = academic_sessions_vocab,
844        required = True,
845        )
846
847    p_level = schema.Choice(
848        title = _(u'Payment Level'),
849        source = StudyLevelSource(),
850        required = True,
851        )
852
853class IStudentBalancePayment(IKofaObject):
854    """An interface for adding balances.
855    """
856
857    p_category = schema.Choice(
858        title = _(u'Payment Category'),
859        default = u'schoolfee',
860        required = True,
861        source = BalancePaymentCategorySource(),
862        )
863
864    balance_session = schema.Choice(
865        title = _(u'Payment Session'),
866        source = academic_sessions_vocab,
867        required = True,
868        )
869
870    balance_level = schema.Choice(
871        title = _(u'Payment Level'),
872        source = StudyLevelSource(),
873        required = True,
874        )
875
876    balance_amount = schema.Float(
877        title = _(u'Balance Amount'),
878        default = None,
879        required = True,
880        readonly = False,
881        description = _(
882            u'Balance in Naira '),
883        )
884
885class ICSVStudentExporter(ICSVExporter):
886    """A regular ICSVExporter that additionally supports exporting
887      data from a given student object.
888    """
889    def get_filtered(site, **kw):
890        """Get a filtered set of students.
891        """
892
893    def get_selected(site, selected):
894        """Get set of selected students.
895        """
896
897    def export_student(student, filepath=None):
898        """Export data for a given student.
899        """
900
901    def export_filtered(site, filepath=None, **kw):
902        """Export data for filtered set of students.
903        """
904
905    def export_selected(site, filepath=None, **kw):
906        """Export data for selected set of students.
907        """
Note: See TracBrowser for help on using the repository browser.