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

Last change on this file since 10009 was 9984, checked in by Henrik Bettermann, 12 years ago

FCEOkene wants to hide the bed coordinates if maintenance fee is not yet paid. Thus we need additional property attributes which return the p_item (payment tickets) and the bed_coordinates attributes (bed tickets) by default and can be easily customized to hide this information in certain cases. bed_coordinates and p_item must be omitted on forms. The new display_ attributes are displayed instead.

All packages must now be adjusted.

The 'cost-benefit ratio' of these kinds of customizations is quite bad and we should think about declining such customization requests. However, I started customization and these are the changed made in the base package.

  • Property svn:keywords set to Id
File size: 21.9 KB
RevLine 
[7191]1## $Id: interfaces.py 9984 2013-02-24 08:29:24Z henrik $
[6621]2##
[7191]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##
[8409]18#from datetime import datetime
[7620]19from zope.component import getUtility
[7256]20from zope.interface import Attribute, Interface
[6621]21from zope import schema
[7620]22from zc.sourcefactory.contextual import BasicContextualSourceFactory
[9217]23from waeup.kofa.browser.interfaces import IStudentNavigationBase
[7811]24from waeup.kofa.interfaces import (
[8409]25    IKofaObject, academic_sessions_vocab, validate_email, ICSVExporter)
[7811]26from waeup.kofa.interfaces import MessageFactory as _
[8176]27from waeup.kofa.schema import TextLineChoice, FormattedDate, PhoneNumber
[7811]28from waeup.kofa.students.vocabularies import (
[7915]29    StudyLevelSource, contextual_reg_num_source, contextual_mat_num_source,
[9420]30    GenderSource, nats_vocab
[7915]31    )
[8160]32from waeup.kofa.payments.interfaces import (
[8174]33    IPaymentsContainer, IOnlinePayment)
[7915]34from waeup.kofa.university.vocabularies import (
[9864]35    CourseSource, StudyModeSource, CertificateSource, SemesterSource,
36    ContextualDictSourceFactoryBase)
[6621]37
[9864]38class PreviousPaymentCategorySource(ContextualDictSourceFactoryBase):
39    """A source that delivers all selectable categories of previous session
40    payments.
41    """
42    #: name of dict to deliver from kofa utils.
43    DICT_NAME = 'PREVIOUS_PAYMENT_CATEGORIES'
44
[9868]45class BalancePaymentCategorySource(ContextualDictSourceFactoryBase):
[9864]46    """A source that delivers all selectable items of balance payments.
47    """
48    #: name of dict to deliver from kofa utils.
[9868]49    DICT_NAME = 'BALANCE_PAYMENT_CATEGORIES'
[9864]50
[7620]51# VerdictSource can't be placed into the vocabularies module because it
52# requires importing IStudentsUtils which then leads to circular imports.
53class VerdictSource(BasicContextualSourceFactory):
54    """A verdicts source delivers all verdicts provided
55    in the portal.
56    """
57    def getValues(self, context):
[7841]58        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
[8820]59        return sorted(verdicts_dict.keys())
[7620]60
61    def getToken(self, context, value):
62        return value
63
64    def getTitle(self, context, value):
[7841]65        verdicts_dict = getUtility(IStudentsUtils).VERDICTS_DICT
[8820]66        if value != '0':
67            return verdicts_dict[value] + ' (%s)' % value
[7688]68        return verdicts_dict[value]
[7620]69
[7681]70
[7150]71class IStudentsUtils(Interface):
72    """A collection of methods which are subject to customization.
73
74    """
[7841]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
[9148]83    def setPaymentDetails(category, student, previous_session=None,
84            previous_level=None,):
[8595]85        """Create Payment object and set the payment data of a student for
86        the payment category specified.
[7150]87
88        """
89
[7186]90    def getAccommodation_details(student):
[7150]91        """Determine the accommodation dates of a student.
92
93        """
94
[7186]95    def selectBed(available_beds):
[7150]96        """Select a bed from a list of available beds.
97
98        In the standard configuration we select the first bed found,
99        but can also randomize the selection if we like.
100        """
101
[9949]102    def getPDFCreator(context):
103        """Get some IPDFCreator instance suitable for use with `context`.
104        """
105
[7186]106    def renderPDF(view, subject='', filename='slip.pdf',):
[7150]107        """Render pdf slips for various pages.
108
109        """
110
[7819]111class IStudentsContainer(IKofaObject):
[7096]112    """A students container contains university students.
[6692]113
114    """
115    def addStudent(student):
116        """Add an IStudent object and subcontainers.
117
118        """
119
120    def archive(id=None):
121        """Create on-dist archive of students.
122
123        If id is `None`, all students are archived.
124
125        If id contains a single id string, only the respective
126        students are archived.
127
128        If id contains a list of id strings all of the respective
129        students types are saved to disk.
130        """
131
132    def clear(id=None, archive=True):
133        """Remove students of type given by 'id'.
134
135        Optionally archive the students.
136
137        If id is `None`, all students are archived.
138
139        If id contains a single id string, only the respective
140        students are archived.
141
142        If id contains a list of id strings all of the respective
143        student types are saved to disk.
144
145        If `archive` is ``False`` none of the archive-handling is done
146        and respective students are simply removed from the
147        database.
148        """
149
[8408]150    unique_student_id = Attribute("""A unique student id.""")
151
[9217]152class IStudentNavigation(IStudentNavigationBase):
[8735]153    """Interface needed for student navigation, logging, etc.
[7150]154
[6642]155    """
[8736]156    student = Attribute('Student object of context.')
[7150]157
[8735]158    def writeLogMessage(view, message):
159        """Write a view specific log message into students.log.
160
161        """
162
[7819]163class IStudentBase(IKofaObject):
[6631]164    """Representation of student base data.
[7150]165
[6621]166    """
[7062]167    history = Attribute('Object history, a list of messages')
[6637]168    state = Attribute('Returns the registration state of a student')
[6699]169    password = Attribute('Encrypted password of a student')
[9334]170    temp_password = Attribute(
171        'Dictionary with user name, timestamp and encrypted password')
[7203]172    certcode = Attribute('The certificate code of any chosen study course')
173    depcode = Attribute('The department code of any chosen study course')
174    faccode = Attribute('The faculty code of any chosen study course')
[9761]175    entry_session = Attribute('The entry session of the student')
[7062]176    current_session = Attribute('The current session of the student')
[9142]177    current_level = Attribute('The current level of the student')
[7641]178    current_mode = Attribute('The current mode of the student')
[9182]179    current_verdict = Attribute('The current verdict of the student')
[7364]180    fullname = Attribute('All name parts separated by hyphens')
181    display_fullname = Attribute('The fullname of an applicant')
[8969]182    is_postgrad = Attribute('True if postgraduate student')
[6637]183
[8983]184    suspended = schema.Bool(
185        title = _(u'Account suspended'),
186        default = False,
[9035]187        required = False,
[8983]188        )
189
[9702]190    suspended_comment = schema.Text(
191        title = _(u"Reasons for Deactivation"),
192        required = False,
193        description = _(
194            u'This message will be shown if and only if deactivated '
195            'students try to login.'),
196        )
197
[6665]198    student_id = schema.TextLine(
[7723]199        title = _(u'Student Id'),
[6849]200        required = False,
[6665]201        )
202
[7357]203    firstname = schema.TextLine(
[7723]204        title = _(u'First Name'),
[6621]205        required = True,
206        )
207
[7357]208    middlename = schema.TextLine(
[7723]209        title = _(u'Middle Name'),
[7357]210        required = False,
211        )
212
213    lastname = schema.TextLine(
[7723]214        title = _(u'Last Name (Surname)'),
[7357]215        required = True,
216        )
217
[6996]218    sex = schema.Choice(
[7723]219        title = _(u'Sex'),
[6996]220        source = GenderSource(),
221        required = True,
222        )
223
[6788]224    reg_number = TextLineChoice(
[7723]225        title = _(u'Registration Number'),
[6696]226        required = True,
227        readonly = False,
[6788]228        source = contextual_reg_num_source,
[6696]229        )
230
[6788]231    matric_number = TextLineChoice(
[7723]232        title = _(u'Matriculation Number'),
[6750]233        required = False,
234        readonly = False,
[6788]235        source = contextual_mat_num_source,
[6750]236        )
237
[6769]238    adm_code = schema.TextLine(
[7723]239        title = _(u'PWD Activation Code'),
[6769]240        required = False,
[8977]241        readonly = False,
[6769]242        )
243
[7133]244    email = schema.ASCIILine(
[7723]245        title = _(u'Email'),
[7133]246        required = False,
247        constraint=validate_email,
248        )
[8176]249    phone = PhoneNumber(
[7723]250        title = _(u'Phone'),
[7331]251        description = u'',
[7133]252        required = False,
253        )
254
[9334]255    def setTempPassword(user, password):
256        """Set a temporary password (LDAP-compatible) SSHA encoded for
257        officers.
258
259        """
260
261    def getTempPassword():
262        """Check if a temporary password has been set and if it
263        is not expired.
264
265        Return the temporary password if valid,
266        None otherwise. Unset the temporary password if expired.
267        """
268
[9131]269    def transfer(certificate, current_session,
270        current_level, current_verdict):
271        """ Creates a new studycourse and backups the old one.
272
273        """
274
[7993]275class IUGStudentClearance(IKofaObject):
276    """Representation of undergraduate student clearance data.
[7150]277
[6631]278    """
[9543]279    officer_comment = schema.Text(
280        title = _(u"Officer's Comment"),
281        required = False,
[6631]282        )
283
[6695]284    clearance_locked = schema.Bool(
[7723]285        title = _(u'Clearance form locked'),
[6695]286        default = False,
[9035]287        required = False,
[6695]288        )
289
[6769]290    clr_code = schema.TextLine(
[7723]291        title = _(u'CLR Activation Code'),
[6769]292        required = False,
[8977]293        readonly = False,
[6769]294        )
295
[9543]296    date_of_birth = FormattedDate(
297        title = _(u'Date of Birth'),
298        required = True,
299        show_year = True,
300        )
301
[7523]302    nationality = schema.Choice(
[8069]303        vocabulary = nats_vocab,
[7723]304        title = _(u'Nationality'),
[7983]305        required = False,
[7523]306        )
307
[7993]308class IPGStudentClearance(IUGStudentClearance):
309    """Representation of postgraduate student clearance data.
310
311    """
312    employer = schema.TextLine(
313        title = _(u'Employer'),
314        required = False,
315        readonly = False,
316        )
317
[7819]318class IStudentPersonal(IKofaObject):
[6631]319    """Representation of student personal data.
[7150]320
[6631]321    """
[9543]322    personal_updated = schema.Datetime(
323        title = _(u'Updated'),
324        required = False,
325        readonly = False,
326        )
327
[6651]328    perm_address = schema.Text(
[7723]329        title = _(u'Permanent Address'),
[6631]330        required = False,
331        )
332
[8008]333class IStudent(IStudentBase,IUGStudentClearance,IPGStudentClearance,
334    IStudentPersonal):
[6631]335    """Representation of a student.
[7150]336
[6631]337    """
338
[9563]339class IStudentPersonalEdit(IStudentPersonal):
340    """Interface for editing personal data by students.
341
342    Here we can repeat the fields from IStudentPersonal and set the
343    `required` if necessary.
344    """
345
346    perm_address = schema.Text(
347        title = _(u'Permanent Address'),
348        required = True,
349        )
350
[6849]351class IStudentUpdateByRegNo(IStudent):
352    """Representation of a student. Skip regular reg_number validation.
[7150]353
[6849]354    """
355    reg_number = schema.TextLine(
[7723]356        title = _(u'Registration Number'),
[6849]357        required = False,
358        )
359
360class IStudentUpdateByMatricNo(IStudent):
361    """Representation of a student. Skip regular matric_number validation.
[7150]362
[6849]363    """
364    matric_number = schema.TextLine(
[7723]365        title = _(u'Matriculation Number'),
[6849]366        required = False,
367        )
368
[8779]369class IStudentRequestPW(IStudent):
370    """Representation of an student for first-time password request.
371
372    This interface is used when students use the requestpw page to
373    login for the the first time.
374    """
[8854]375    number = schema.TextLine(
376        title = _(u'Registr. or Matric. Number'),
[8779]377        required = True,
378        )
379
380    firstname = schema.TextLine(
381        title = _(u'First Name'),
382        required = True,
383        )
384
385    email = schema.ASCIILine(
386        title = _(u'Email Address'),
387        required = True,
388        constraint=validate_email,
389        )
390
[7819]391class IStudentStudyCourse(IKofaObject):
[6633]392    """A container for student study levels.
393
394    """
[6648]395    certificate = schema.Choice(
[7723]396        title = _(u'Certificate'),
[6648]397        source = CertificateSource(),
[7209]398        required = False,
[6633]399        )
[6635]400
[6996]401    entry_mode = schema.Choice(
[7723]402        title = _(u'Entry Mode'),
[7681]403        source = StudyModeSource(),
[6996]404        required = True,
405        readonly = False,
406        )
407
408    entry_session = schema.Choice(
[7723]409        title = _(u'Entry Session'),
[6996]410        source = academic_sessions_vocab,
[7425]411        #default = datetime.now().year,
[6996]412        required = True,
413        readonly = False,
414        )
415
[6724]416    current_session = schema.Choice(
[7723]417        title = _(u'Current Session'),
[6744]418        source = academic_sessions_vocab,
[6724]419        required = True,
[6996]420        readonly = False,
[6724]421        )
422
423    current_level = schema.Choice(
[7723]424        title = _(u'Current Level'),
[6725]425        source = StudyLevelSource(),
426        required = False,
[6996]427        readonly = False,
[6724]428        )
429
430    current_verdict = schema.Choice(
[7723]431        title = _(u'Current Verdict'),
[7619]432        source = VerdictSource(),
[8820]433        default = '0',
[6725]434        required = False,
[6724]435        )
436
437    previous_verdict = schema.Choice(
[7723]438        title = _(u'Previous Verdict'),
[7619]439        source = VerdictSource(),
[8820]440        default = '0',
[6725]441        required = False,
[6724]442        )
443
[9138]444class IStudentStudyCourseTransfer(IStudentStudyCourse):
445    """An student transfers.
446
447    """
448
449    certificate = schema.Choice(
450        title = _(u'Certificate'),
451        source = CertificateSource(),
452        required = True,
453        )
454
455    current_level = schema.Choice(
456        title = _(u'Current Level'),
457        source = StudyLevelSource(),
458        required = True,
459        readonly = False,
460        )
461
[9960]462    entry_session = schema.Choice(
463        title = _(u'Entry Session'),
464        source = academic_sessions_vocab,
465        #default = datetime.now().year,
466        required = False,
467        readonly = False,
468        )
469
470
[9138]471IStudentStudyCourseTransfer['certificate'].order = IStudentStudyCourse[
472    'certificate'].order
473IStudentStudyCourseTransfer['current_level'].order = IStudentStudyCourse[
474    'current_level'].order
475
[7951]476class IStudentVerdictUpdate(IKofaObject):
477    """A interface for verdict imports.
478
479    """
480
481    current_verdict = schema.Choice(
482        title = _(u'Current Verdict'),
483        source = VerdictSource(),
484        required = True,
485        )
486
487    current_session = schema.Choice(
488        title = _(u'Current Session'),
489        source = academic_sessions_vocab,
490        required = True,
491        )
492
493    current_level = schema.Choice(
494        title = _(u'Current Level'),
495        source = StudyLevelSource(),
496        required = True,
497        )
498
[9296]499    bypass_validation = schema.Bool(
500        title = _(u'Bypass validation'),
501        required = False,
502        )
503
504    validated_by = schema.TextLine(
505        title = _(u'Validated by'),
506        required = False,
507        )
508
[7819]509class IStudentStudyLevel(IKofaObject):
[6774]510    """A container for course tickets.
511
512    """
513    level = Attribute('The level code')
[9235]514    number_of_tickets = Attribute('Number of tickets contained in this level')
[9253]515    certcode = Attribute('The certificate code of the study course')
[9257]516    is_current_level = Attribute('Is this level the current level of the student?')
[6774]517
[6793]518    level_session = schema.Choice(
[7723]519        title = _(u'Session'),
[6793]520        source = academic_sessions_vocab,
[9437]521        required = True,
[6793]522        )
[6781]523
[6793]524    level_verdict = schema.Choice(
[7723]525        title = _(u'Verdict'),
[7619]526        source = VerdictSource(),
[8820]527        default = '0',
[6793]528        required = False,
529        )
530
[9161]531    validated_by = schema.TextLine(
532        title = _(u'Validated by'),
533        default = None,
534        required = False,
535        )
536
537    validation_date = schema.Datetime(
538        title = _(u'Validation Date'),
539        required = False,
540        readonly = False,
541        )
542
[9690]543    total_credits = schema.Int(
544        title = _(u'Total Credits'),
545        required = False,
546        readonly = True,
547        )
548
549    gpa = schema.Int(
550        title = _(u'GPA'),
551        required = False,
552        readonly = True,
553        )
554
[8920]555    def addCourseTicket(ticket, course):
[8182]556        """Add a course ticket object.
557        """
558
[9501]559    def addCertCourseTickets(cert):
560        """Collect all certificate courses and create course
561        tickets automatically.
562        """
563
[7819]564class ICourseTicket(IKofaObject):
[9420]565    """An interface for course tickets.
[6781]566
567    """
[6783]568    code = Attribute('code of the original course')
[9253]569    certcode = Attribute('certificate code of the study course')
[9684]570    grade = Attribute('grade calculated from score')
571    weight = Attribute('weight calculated from score')
[9698]572    removable_by_student = Attribute('Is student allowed to remove the ticket?')
[9925]573    level_session = Attribute('session of the level the ticket has been added to')
574    level = Attribute('id of the level the ticket has been added to')
[6781]575
[9420]576    title = schema.TextLine(
577        title = _(u'Title'),
578        required = False,
579        )
580
581    fcode = schema.TextLine(
582        title = _(u'Faculty Code'),
583        required = False,
584        )
585
586    dcode = schema.TextLine(
587        title = _(u'Department Code'),
588        required = False,
589        )
590
591    semester = schema.Choice(
592        title = _(u'Semester/Term'),
593        source = SemesterSource(),
594        required = False,
595        )
596
597    passmark = schema.Int(
598        title = _(u'Passmark'),
599        required = False,
600        )
601
602    credits = schema.Int(
603        title = _(u'Credits'),
604        required = False,
605        )
606
[7665]607    mandatory = schema.Bool(
[9320]608        title = _(u'Required'),
[6795]609        default = False,
610        required = False,
611        )
612
[6781]613    score = schema.Int(
[7723]614        title = _(u'Score'),
[9684]615        default = None,
[6781]616        required = False,
617        )
618
[7661]619    carry_over = schema.Bool(
[7723]620        title = _(u'Carry-over Course'),
[7661]621        default = False,
622        required = False,
623        )
624
[9420]625    automatic = schema.Bool(
626        title = _(u'Automatical Creation'),
627        default = False,
[9316]628        required = False,
629        )
630
[7633]631
[9420]632class ICourseTicketAdd(IKofaObject):
[7150]633    """An interface for adding course tickets.
[6795]634
635    """
636    course = schema.Choice(
[7723]637        title = _(u'Course'),
[6795]638        source = CourseSource(),
639        readonly = False,
640        )
641
[9420]642class ICourseTicketImport(ICourseTicket):
643    """An interface for importing course results and nothing more.
644
645    """
646    score = schema.Int(
647        title = _(u'Score'),
648        required = False,
649        readonly = False,
650        )
651
652    level_session = schema.Choice(
653        title = _(u'Level Session'),
654        source = academic_sessions_vocab,
655        required = False,
656        readonly = False,
657        )
658
[7819]659class IStudentAccommodation(IKofaObject):
[6635]660    """A container for student accommodation objects.
661
662    """
663
[9423]664    def addBedTicket(bedticket):
665        """Add a bed ticket object.
666        """
667
668
[7819]669class IBedTicket(IKofaObject):
[6989]670    """A ticket for accommodation booking.
671
672    """
[6996]673    bed = Attribute('The bed object.')
674
675    bed_coordinates = schema.TextLine(
[9984]676        title = u'',
[9423]677        required = True,
[7014]678        readonly = False,
[6992]679        )
680
[9984]681    display_coordinates = schema.TextLine(
682        title = _(u'Allocated Bed'),
683        required = False,
684        readonly = True,
685        )
686
[6996]687    bed_type = schema.TextLine(
[9424]688        title = _(u'Requested Bed Type'),
[9423]689        required = True,
[7014]690        readonly = False,
[6996]691        )
692
[6992]693    booking_session = schema.Choice(
[7723]694        title = _(u'Session'),
[6992]695        source = academic_sessions_vocab,
696        required = True,
[7014]697        readonly = True,
[6992]698        )
699
[8170]700    booking_date = schema.Datetime(
[7723]701        title = _(u'Booking Date'),
[6992]702        required = False,
[7014]703        readonly = True,
[6992]704        )
705
706    booking_code = schema.TextLine(
[7723]707        title = _(u'Booking Activation Code'),
[6992]708        required = False,
[7014]709        readonly = True,
[6992]710        )
711
[6994]712    def getSessionString():
[7633]713        """Returns the title of academic_sessions_vocab term.
[7150]714
[6994]715        """
[6992]716
[6860]717class IStudentPaymentsContainer(IPaymentsContainer):
[6635]718    """A container for student payment objects.
719
720    """
721
[6877]722class IStudentOnlinePayment(IOnlinePayment):
723    """A student payment via payment gateways.
724
725    """
726
[9148]727    p_current = schema.Bool(
728        title = _(u'Current Session Payment'),
729        default = True,
730        required = False,
731        )
732
[8268]733    p_level = schema.Int(
734        title = _(u'Payment Level'),
735        required = False,
736        )
[6877]737
[8422]738    def doAfterStudentPayment():
739        """Process student after payment was made.
740
741        """
742
[8453]743    def doAfterStudentPaymentApproval():
744        """Process student after payment was approved.
745
746        """
747
[8420]748    def approveStudentPayment():
[8422]749        """Approve payment and process student.
[8420]750
751        """
752
[8268]753IStudentOnlinePayment['p_level'].order = IStudentOnlinePayment[
754    'p_session'].order
[8408]755
[9864]756class IStudentPreviousPayment(IKofaObject):
[9148]757    """An interface for adding previous session payments.
758
759    """
760
[9864]761    p_category = schema.Choice(
762        title = _(u'Payment Category'),
763        default = u'schoolfee',
764        source = PreviousPaymentCategorySource(),
765        required = True,
766        )
767
[9148]768    p_session = schema.Choice(
769        title = _(u'Payment Session'),
770        source = academic_sessions_vocab,
771        required = True,
772        )
773
774    p_level = schema.Choice(
775        title = _(u'Payment Level'),
776        source = StudyLevelSource(),
777        required = True,
778        )
779
[9864]780class IStudentBalancePayment(IKofaObject):
781    """An interface for adding balances.
782
783    """
784
[9868]785    p_category = schema.Choice(
[9864]786        title = _(u'Payment Category'),
787        default = u'schoolfee',
788        required = True,
[9868]789        source = BalancePaymentCategorySource(),
[9864]790        )
791
792    balance_session = schema.Choice(
793        title = _(u'Payment Session'),
794        source = academic_sessions_vocab,
795        required = True,
796        )
797
798    balance_level = schema.Choice(
799        title = _(u'Payment Level'),
800        source = StudyLevelSource(),
801        required = True,
802        )
803
804    balance_amount = schema.Float(
805        title = _(u'Balance Amount'),
[9874]806        default = None,
[9864]807        required = True,
808        readonly = False,
809        description = _(
810            u'Balance in Naira '),
811        )
812
[8408]813class ICSVStudentExporter(ICSVExporter):
814    """A regular ICSVExporter that additionally supports exporting
815      data from a given student object.
816    """
[9801]817    def get_filtered(site, **kw):
[9797]818        """Get a filtered set of students.
819        """
[8408]820
821    def export_student(student, filepath=None):
822        """Export data for a given student.
823        """
[9734]824
[9797]825    def export_filtered(site, filepath=None, **kw):
[9734]826        """Export filtered set of students.
827        """
Note: See TracBrowser for help on using the repository browser.