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

Last change on this file since 14286 was 14247, checked in by Henrik Bettermann, 8 years ago

Replace course_registration_allowed by course_registration_forbidden method.

  • Property svn:keywords set to Id
File size: 26.0 KB
Line 
1## $Id: interfaces.py 14247 2016-11-02 07:14:58Z 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, IKofaUtils)
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(IKofaUtils).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(IKofaUtils).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
140    def getDegreeClassNumber(level_obj):
141        """Get degree class number (used for SessionResultsPresentation
142        reports).
143        """
144
145class IStudentsContainer(IKofaObject):
146    """A students container contains university students.
147    """
148    def addStudent(student):
149        """Add an IStudent object and subcontainers.
150        """
151
152    unique_student_id = Attribute('A unique student id')
153
154class IStudentNavigation(IStudentNavigationBase):
155    """Interface needed for navigation and logging. This interface is
156    implemented by all content classes in the students section.
157    """
158    student = Attribute('Student object of context')
159
160    def writeLogMessage(view, message):
161        """Add an INFO message to students.log.
162        """
163
164class IStudentBase(IKofaObject):
165    """Representation of student base data.
166    """
167    history = Attribute('Object history, a list of messages')
168    state = Attribute('Registration state')
169    translated_state = Attribute('Real name of the registration state')
170    certcode = Attribute('Certificate code of any chosen study course')
171    depcode = Attribute('Department code of any chosen study course')
172    faccode = Attribute('Faculty code of any chosen study course')
173    entry_session = Attribute('Entry session')
174    current_session = Attribute('Current session')
175    current_level = Attribute('Current level')
176    current_mode = Attribute('Current mode')
177    current_verdict = Attribute('Current verdict')
178    fullname = Attribute('All name parts separated by hyphens')
179    display_fullname = Attribute('Fullname as displayed on pages')
180    is_postgrad = Attribute('True if postgraduate student')
181    is_special_postgrad = Attribute('True if special postgraduate student')
182    is_fresh = Attribute('True if fresh student')
183    before_payment = Attribute('True if no previous payment has to be made')
184    personal_data_expired = Attribute('True if personal data expired')
185    transcript_enabled = Attribute('True if transcript processing is enabled')
186    clearance_locked = Attribute('True if clearance form is locked')
187
188    password = Attribute('Encrypted password')
189    temp_password = Attribute('Dictionary with user name, timestamp and encrypted password')
190
191    suspended = schema.Bool(
192        title = _(u'Account suspended'),
193        default = False,
194        required = False,
195        )
196
197    suspended_comment = schema.Text(
198        title = _(u"Reasons for Deactivation"),
199        required = False,
200        description = _(
201            u'This message will be shown if and only if deactivated '
202            'students try to login.'),
203        )
204
205    flash_notice = schema.TextLine(
206        title = _(u'Flash Notice'),
207        required = False,
208        readonly = False,
209        description = _(
210            u'This single-line message will be shown in a flash box.'),
211        )
212
213    student_id = schema.TextLine(
214        title = _(u'Student Id'),
215        required = False,
216        )
217
218    firstname = schema.TextLine(
219        title = _(u'First Name'),
220        required = True,
221        )
222
223    middlename = schema.TextLine(
224        title = _(u'Middle Name'),
225        required = False,
226        )
227
228    lastname = schema.TextLine(
229        title = _(u'Last Name (Surname)'),
230        required = True,
231        )
232
233    sex = schema.Choice(
234        title = _(u'Sex'),
235        source = GenderSource(),
236        required = True,
237        )
238
239    reg_number = TextLineChoice(
240        title = _(u'Registration Number'),
241        required = True,
242        readonly = False,
243        source = contextual_reg_num_source,
244        )
245
246    matric_number = TextLineChoice(
247        title = _(u'Matriculation Number'),
248        required = False,
249        readonly = False,
250        source = contextual_mat_num_source,
251        )
252
253    adm_code = schema.TextLine(
254        title = _(u'PWD Activation Code'),
255        required = False,
256        readonly = False,
257        )
258
259    email = schema.ASCIILine(
260        title = _(u'Email'),
261        required = False,
262        constraint=validate_email,
263        )
264    phone = PhoneNumber(
265        title = _(u'Phone'),
266        required = False,
267        )
268
269    def setTempPassword(user, password):
270        """Set a temporary password (LDAP-compatible) SSHA encoded for
271        officers.
272        """
273
274    def getTempPassword():
275        """Check if a temporary password has been set and if it
276        is not expired. Return the temporary password if valid,
277        None otherwise. Unset the temporary password if expired.
278        """
279
280    def transfer(certificate, current_session,
281        current_level, current_verdict):
282        """ Creates a new studycourse and backups the old one.
283        """
284
285    def revert_transfer():
286        """ Revert previous transfer.
287        """
288
289class IUGStudentClearance(IKofaObject):
290    """Representation of undergraduate student clearance data.
291    """
292    officer_comment = schema.Text(
293        title = _(u"Officer's Comment"),
294        required = False,
295        )
296
297    clr_code = schema.TextLine(
298        title = _(u'CLR Activation Code'),
299        required = False,
300        readonly = False,
301        )
302
303    date_of_birth = FormattedDate(
304        title = _(u'Date of Birth'),
305        required = True,
306        show_year = True,
307        )
308
309    nationality = schema.Choice(
310        vocabulary = nats_vocab,
311        title = _(u'Nationality'),
312        required = False,
313        )
314
315class IPGStudentClearance(IUGStudentClearance):
316    """Representation of postgraduate student clearance data.
317    """
318    employer = schema.TextLine(
319        title = _(u'Employer'),
320        required = False,
321        readonly = False,
322        )
323
324class IStudentPersonal(IKofaObject):
325    """Representation of student personal data.
326    """
327    personal_updated = schema.Datetime(
328        title = _(u'Updated'),
329        required = False,
330        readonly = False,
331        )
332
333    perm_address = schema.Text(
334        title = _(u'Permanent Address'),
335        required = False,
336        )
337
338class IStudentTranscript(IKofaObject):
339    """Representation of student transcript data.
340    """
341
342    transcript_comment = schema.Text(
343        title = _(u'Comment'),
344        required = False,
345        )
346
347
348class IStudent(IStudentBase,IUGStudentClearance,IPGStudentClearance,
349    IStudentPersonal, IStudentTranscript):
350    """Representation of a student.
351    """
352
353class IStudentPersonalEdit(IStudentPersonal):
354    """Interface for editing personal data by students.
355    Here we can repeat the fields from IStudentPersonal and set the
356    `required` if necessary.
357    """
358
359    perm_address = schema.Text(
360        title = _(u'Permanent Address'),
361        required = True,
362        )
363
364class IStudentUpdateByRegNo(IStudent):
365    """Representation of a student. Skip regular reg_number validation.
366    """
367    reg_number = schema.TextLine(
368        title = _(u'Registration Number'),
369        required = False,
370        )
371
372class IStudentUpdateByMatricNo(IStudent):
373    """Representation of a student. Skip regular matric_number validation.
374    """
375    matric_number = schema.TextLine(
376        title = _(u'Matriculation Number'),
377        required = False,
378        )
379
380class IStudentRequestPW(IStudent):
381    """Representation of a student for first-time password request.
382    This interface is used when students use the requestpw page to
383    login for the the first time.
384    """
385    number = schema.TextLine(
386        title = _(u'Registr. or Matric. Number'),
387        required = True,
388        )
389
390    firstname = schema.TextLine(
391        title = _(u'First Name'),
392        required = True,
393        )
394
395    email = schema.ASCIILine(
396        title = _(u'Email Address'),
397        required = True,
398        constraint=validate_email,
399        )
400
401class IStudentStudyCourse(IKofaObject):
402    """Representation of student study course data.
403    """
404    next_session_allowed = Attribute('True if the student can proceed to next session')
405    is_postgrad = Attribute('True if student is postgraduate student')
406    is_current = Attribute('True if the study course is the current course of studies')
407    is_previous = Attribute('True if the study course is the previous course of studies')
408
409    certificate = schema.Choice(
410        title = _(u'Certificate'),
411        source = CertificateSource(),
412        required = False,
413        )
414
415    entry_mode = schema.Choice(
416        title = _(u'Entry Mode'),
417        source = StudyModeSource(),
418        required = True,
419        readonly = False,
420        )
421
422    entry_session = schema.Choice(
423        title = _(u'Entry Session'),
424        source = academic_sessions_vocab,
425        #default = datetime.now().year,
426        required = True,
427        readonly = False,
428        )
429
430    current_session = schema.Choice(
431        title = _(u'Current Session'),
432        source = academic_sessions_vocab,
433        required = True,
434        readonly = False,
435        )
436
437    current_level = schema.Choice(
438        title = _(u'Current Level'),
439        source = StudyLevelSource(),
440        required = False,
441        readonly = False,
442        )
443
444    current_verdict = schema.Choice(
445        title = _(u'Current Verdict'),
446        source = VerdictSource(),
447        default = '0',
448        required = False,
449        )
450
451    previous_verdict = schema.Choice(
452        title = _(u'Previous Verdict'),
453        source = VerdictSource(),
454        default = '0',
455        required = False,
456        )
457
458    def addStudentStudyLevel(cert, studylevel):
459        """Add a study level object.
460        """
461
462    def getTranscriptData():
463        """Get a sorted list of dicts with level and course ticket data.
464        This method is used for transcripts.
465        """
466
467class IStudentStudyCourseTransfer(IStudentStudyCourse):
468    """An interface used for student transfers.
469    """
470    certificate = schema.Choice(
471        title = _(u'Certificate'),
472        source = CertificateSource(),
473        required = True,
474        )
475
476    current_level = schema.Choice(
477        title = _(u'Current Level'),
478        source = StudyLevelSource(),
479        required = True,
480        readonly = False,
481        )
482
483    entry_session = schema.Choice(
484        title = _(u'Entry Session'),
485        source = academic_sessions_vocab,
486        #default = datetime.now().year,
487        required = False,
488        readonly = False,
489        )
490
491
492IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
493    'certificate'].order
494IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
495    'current_level'].order
496
497class IStudentStudyCourseTranscript(IKofaObject):
498    """An interface for student transcripts.
499    """
500    entry_mode = schema.Choice(
501        title = _(u'Entry Mode'),
502        source = StudyModeSource(),
503        required = True,
504        readonly = False,
505        )
506
507    entry_session = schema.Choice(
508        title = _(u'Entry Session'),
509        source = academic_sessions_vocab,
510        #default = datetime.now().year,
511        required = True,
512        readonly = False,
513        )
514
515class IStudentVerdictUpdate(IKofaObject):
516    """A interface for verdict imports.
517    """
518    current_verdict = schema.Choice(
519        title = _(u'Current Verdict'),
520        source = VerdictSource(),
521        required = True,
522        )
523
524    current_session = schema.Choice(
525        title = _(u'Current Session'),
526        source = academic_sessions_vocab,
527        required = True,
528        )
529
530    current_level = schema.Choice(
531        title = _(u'Current Level'),
532        source = StudyLevelSource(),
533        required = True,
534        )
535
536    bypass_validation = schema.Bool(
537        title = _(u'Bypass validation'),
538        required = False,
539        )
540
541    validated_by = schema.TextLine(
542        title = _(u'Validated by'),
543        required = False,
544        )
545
546class IStudentStudyLevel(IKofaObject):
547    """A representation of student study level data.
548    """
549    certcode = Attribute('The certificate code of the study course')
550    is_current_level = Attribute('True if level is current level of the student')
551    level_title = Attribute('Level title from source')
552    getSessionString = Attribute('Session title from source')
553    number_of_tickets = Attribute('Number of tickets contained in this level')
554    passed_params = Attribute('Information about passed and failed courses')
555    gpa_params_rectified = Attribute('Corrected sessional GPA parameters')
556    gpa_params = Attribute('GPA parameters for this level.')
557    cumulative_params = Attribute(
558        'Cumulative GPA and other cumulative parameters for this level')
559    course_registration_forbidden = Attribute(
560        'Return error message if course registration is forbidden')
561
562    level = schema.Choice(
563        title = _(u'Level'),
564        source = StudyLevelSource(),
565        required = True,
566        readonly = False,
567        )
568
569    level_session = schema.Choice(
570        title = _(u'Session'),
571        source = academic_sessions_vocab,
572        required = True,
573        )
574
575    level_verdict = schema.Choice(
576        title = _(u'Verdict'),
577        source = VerdictSource(),
578        default = '0',
579        required = False,
580        )
581
582    validated_by = schema.TextLine(
583        title = _(u'Validated by'),
584        default = None,
585        required = False,
586        )
587
588    validation_date = schema.Datetime(
589        title = _(u'Validation Date'),
590        required = False,
591        readonly = False,
592        )
593
594    total_credits = schema.Int(
595        title = _(u'Total Credits'),
596        required = False,
597        readonly = True,
598        )
599
600    gpa = schema.Int(
601        title = _(u'Unrectified GPA'),
602        required = False,
603        readonly = True,
604        )
605
606    def addCourseTicket(ticket, course):
607        """Add a course ticket object.
608        """
609
610    def addCertCourseTickets(cert):
611        """Collect all certificate courses and create course
612        tickets automatically.
613        """
614
615class ICourseTicket(IKofaObject):
616    """A representation of course ticket data.
617    """
618    certcode = Attribute('Certificate code of the study course')
619    level_session = Attribute('Session of the study level the ticket has been added to')
620    level = Attribute('Level value of the study level the ticket has been added to')
621    total_score = Attribute('Score')
622    grade = Attribute('Grade calculated from total score')
623    weight = Attribute('Weight calculated from total score')
624    removable_by_student = Attribute('True if student is allowed to remove the ticket')
625    editable_by_lecturer = Attribute('True if lecturer is allowed to edit the ticket')
626
627    code = Attribute('Code of the original course')
628
629    title = schema.TextLine(
630        title = _(u'Title'),
631        required = False,
632        )
633
634    fcode = schema.TextLine(
635        title = _(u'Faculty Code'),
636        required = False,
637        )
638
639    dcode = schema.TextLine(
640        title = _(u'Department Code'),
641        required = False,
642        )
643
644    semester = schema.Choice(
645        title = _(u'Semester/Term'),
646        source = SemesterSource(),
647        required = False,
648        )
649
650    passmark = schema.Int(
651        title = _(u'Passmark'),
652        required = False,
653        )
654
655    credits = schema.Int(
656        title = _(u'Credits'),
657        required = False,
658        )
659
660    mandatory = schema.Bool(
661        title = _(u'Required'),
662        default = False,
663        required = False,
664        )
665
666    score = schema.Int(
667        title = _(u'Score'),
668        default = None,
669        required = False,
670        missing_value = None,
671        )
672
673    carry_over = schema.Bool(
674        title = _(u'Carry-over Course'),
675        default = False,
676        required = False,
677        )
678
679    automatic = schema.Bool(
680        title = _(u'Automatical Creation'),
681        default = False,
682        required = False,
683        )
684
685class ICourseTicketAdd(IKofaObject):
686    """An interface for adding course tickets.
687    """
688    course = schema.Choice(
689        title = _(u'Course'),
690        source = CourseSource(),
691        readonly = False,
692        )
693
694class ICourseTicketImport(ICourseTicket):
695    """An interface for importing course results and nothing more.
696    """
697    score = schema.Int(
698        title = _(u'Score'),
699        required = False,
700        readonly = False,
701        )
702
703    level_session = schema.Choice(
704        title = _(u'Level Session'),
705        source = academic_sessions_vocab,
706        required = False,
707        readonly = False,
708        )
709
710class IStudentAccommodation(IKofaObject):
711    """A container for student accommodation objects.
712    """
713
714    desired_hostel = schema.TextLine(
715        title = _(u'Desired Hostel'),
716        required = False,
717        )
718
719    def addBedTicket(bedticket):
720        """Add a bed ticket object.
721        """
722
723
724class IBedTicket(IKofaObject):
725    """A representation of accommodation booking data.
726    """
727    bed = Attribute('The bed object')
728    maint_payment_made = Attribute('True if maintenance payment is made')
729
730    display_coordinates = schema.TextLine(
731        title = _(u'Allocated Bed'),
732        required = False,
733        readonly = True,
734        )
735
736    bed_coordinates = schema.TextLine(
737        title = u'',
738        required = True,
739        readonly = False,
740        )
741
742    bed_type = schema.TextLine(
743        title = _(u'Requested Bed Type'),
744        required = True,
745        readonly = False,
746        )
747
748    booking_session = schema.Choice(
749        title = _(u'Session'),
750        source = academic_sessions_vocab,
751        required = True,
752        readonly = False
753        )
754
755    booking_date = schema.Datetime(
756        title = _(u'Booking Date'),
757        required = False,
758        readonly = False,
759        )
760
761    booking_code = schema.TextLine(
762        title = _(u'Booking Activation Code'),
763        required = False,
764        readonly = False,
765        )
766
767    def getSessionString():
768        """Returns the title of academic_sessions_vocab term of the session
769        when the bed was booked.
770        """
771
772class IStudentPaymentsContainer(IPaymentsContainer):
773    """A container for student payment objects.
774    """
775
776    certificate = Attribute('Certificate to determine the correct p_level value')
777
778class IStudentOnlinePayment(IOnlinePayment):
779    """A student payment via payment gateways.
780    """
781
782    certificate = Attribute('Certificate to determine the correct p_level value')
783    student = Attribute('Student')
784
785    p_current = schema.Bool(
786        title = _(u'Current Session Payment'),
787        default = True,
788        required = False,
789        )
790
791    p_level = schema.Choice(
792        title = _(u'Payment Level'),
793        source = StudyLevelSource(),
794        required = False,
795        )
796
797    def redeemTicket():
798        """Either create an appropriate access code or trigger an action
799        directly.
800        """
801
802    def doAfterStudentPayment():
803        """Process student after payment was made.
804        """
805
806    def doAfterStudentPaymentApproval():
807        """Process student after payment was approved.
808        """
809
810    def approveStudentPayment():
811        """Approve payment and process student.
812        """
813
814IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
815    'p_session'].order
816
817class IStudentPreviousPayment(IKofaObject):
818    """An interface for adding previous session payments.
819    """
820
821    p_category = schema.Choice(
822        title = _(u'Payment Category'),
823        default = u'schoolfee',
824        source = PreviousPaymentCategorySource(),
825        required = True,
826        )
827
828    p_session = schema.Choice(
829        title = _(u'Payment Session'),
830        source = academic_sessions_vocab,
831        required = True,
832        )
833
834    p_level = schema.Choice(
835        title = _(u'Payment Level'),
836        source = StudyLevelSource(),
837        required = True,
838        )
839
840class IStudentBalancePayment(IKofaObject):
841    """An interface for adding balances.
842    """
843
844    p_category = schema.Choice(
845        title = _(u'Payment Category'),
846        default = u'schoolfee',
847        required = True,
848        source = BalancePaymentCategorySource(),
849        )
850
851    balance_session = schema.Choice(
852        title = _(u'Payment Session'),
853        source = academic_sessions_vocab,
854        required = True,
855        )
856
857    balance_level = schema.Choice(
858        title = _(u'Payment Level'),
859        source = StudyLevelSource(),
860        required = True,
861        )
862
863    balance_amount = schema.Float(
864        title = _(u'Balance Amount'),
865        default = None,
866        required = True,
867        readonly = False,
868        description = _(
869            u'Balance in Naira '),
870        )
871
872class ICSVStudentExporter(ICSVExporter):
873    """A regular ICSVExporter that additionally supports exporting
874      data from a given student object.
875    """
876    def get_filtered(site, **kw):
877        """Get a filtered set of students.
878        """
879
880    def get_selected(site, selected):
881        """Get set of selected students.
882        """
883
884    def export_student(student, filepath=None):
885        """Export data for a given student.
886        """
887
888    def export_filtered(site, filepath=None, **kw):
889        """Export data for filtered set of students.
890        """
891
892    def export_selected(site, filepath=None, **kw):
893        """Export data for selected set of students.
894        """
Note: See TracBrowser for help on using the repository browser.