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

Last change on this file since 8334 was 8307, checked in by Henrik Bettermann, 13 years ago

Remove school fee from session configuration. School fees are now attributes of the certificates.

Adjust and improve tests.

Fix getPaymentDetails.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 30.9 KB
Line 
1## $Id: interfaces.py 8307 2012-04-29 06:51:19Z 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##
18import os
19import re
20import codecs
21import zope.i18nmessageid
22from datetime import datetime
23from hurry.file.interfaces import IFileRetrieval
24from hurry.workflow.interfaces import IWorkflow, IWorkflowInfo
25from zc.sourcefactory.basic import BasicSourceFactory
26from zope import schema
27from zope.pluggableauth.interfaces import IPrincipalInfo
28from zope.security.interfaces import IGroupClosureAwarePrincipal as IPrincipal
29from zope.component import getUtility
30from zope.component.interfaces import IObjectEvent
31from zope.container.interfaces import INameChooser
32from zope.interface import Interface, Attribute, implements
33from zope.schema.interfaces import IObject
34from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
35from waeup.kofa.schema import PhoneNumber
36
37_ = MessageFactory = zope.i18nmessageid.MessageFactory('waeup.kofa')
38
39DELETION_MARKER = 'XXX'
40IGNORE_MARKER = '<IGNORE>'
41
42CREATED = 'created'
43ADMITTED = 'admitted'
44CLEARANCE = 'clearance started'
45REQUESTED = 'clearance requested'
46CLEARED = 'cleared'
47PAID = 'school fee paid'
48RETURNING = 'returning'
49REGISTERED = 'courses registered'
50VALIDATED = 'courses validated'
51
52default_frontpage = u'' + codecs.open(os.path.join(
53        os.path.dirname(__file__), 'frontpage.rst'),
54        encoding='utf-8', mode='rb').read()
55
56def SimpleKofaVocabulary(*terms):
57    """A well-buildt vocabulary provides terms with a value, token and
58       title for each term
59    """
60    return SimpleVocabulary([
61            SimpleTerm(value, value, title) for title, value in terms])
62
63def year_range():
64    curr_year = datetime.now().year
65    return range(curr_year - 4, curr_year + 5)
66
67def academic_sessions():
68    curr_year = datetime.now().year
69    year_range = range(curr_year - 10, curr_year + 2)
70    return [('%s/%s' % (year,year+1), year) for year in year_range]
71
72academic_sessions_vocab = SimpleKofaVocabulary(*academic_sessions())
73
74registration_states_vocab = SimpleKofaVocabulary(
75    (_('created'), CREATED),
76    (_('admitted'), ADMITTED),
77    (_('clearance started'), CLEARANCE),
78    (_('clearance requested'), REQUESTED),
79    (_('cleared'), CLEARED),
80    (_('school fee paid'), PAID),
81    (_('returning'), RETURNING),
82    (_('courses registered'), REGISTERED),
83    (_('courses validated'), VALIDATED),
84    )
85
86class SubjectSource(BasicSourceFactory):
87    """A source for school subjects used in exam documentation.
88    """
89    def getValues(self):
90        subjects_dict = getUtility(IKofaUtils).EXAM_SUBJECTS_DICT
91        return sorted(subjects_dict.keys())
92
93    def getTitle(self, value):
94        subjects_dict = getUtility(IKofaUtils).EXAM_SUBJECTS_DICT
95        return "%s:" % subjects_dict[value]
96
97class GradeSource(BasicSourceFactory):
98    """A source for exam grades.
99    """
100    def getValues(self):
101        for entry in getUtility(IKofaUtils).EXAM_GRADES:
102            yield entry[0]
103
104    def getTitle(self, value):
105        return dict(getUtility(IKofaUtils).EXAM_GRADES)[value]
106
107# Define a validation method for email addresses
108class NotAnEmailAddress(schema.ValidationError):
109    __doc__ = u"Invalid email address"
110
111check_email = re.compile(
112    r"[a-zA-Z0-9._%-']+@([a-zA-Z0-9-]+.)*[a-zA-Z]{2,4}").match
113
114def validate_email(value):
115    if not check_email(value):
116        raise NotAnEmailAddress(value)
117    return True
118
119# Define a validation method for international phone numbers
120class InvalidPhoneNumber(schema.ValidationError):
121    __doc__ = u"Invalid phone number"
122
123# represent format +NNN-NNNN-NNNN
124RE_INT_PHONE = re.compile(r"^\+?\d+\-\d+\-[\d\-]+$")
125
126def validate_phone(value):
127    if not RE_INT_PHONE.match(value):
128        raise InvalidPhoneNumber(value)
129    return True
130
131class FatalCSVError(Exception):
132    """Some row could not be processed.
133    """
134    pass
135
136class DuplicationError(Exception):
137    """An exception that can be raised when duplicates are found.
138
139    When raising :exc:`DuplicationError` you can, beside the usual
140    message, specify a list of objects which are duplicates. These
141    values can be used by catching code to print something helpful or
142    similar.
143    """
144    def __init__(self, msg, entries=[]):
145        self.msg = msg
146        self.entries = entries
147
148    def __str__(self):
149        return '%r' % self.msg
150
151class RoleSource(BasicSourceFactory):
152    """A source for site roles.
153    """
154    def getValues(self):
155        # late import: in interfaces we should not import local modules
156        from waeup.kofa.permissions import get_waeup_role_names
157        return get_waeup_role_names()
158
159    def getTitle(self, value):
160        # late import: in interfaces we should not import local modules
161        from waeup.kofa.permissions import get_all_roles
162        roles = dict(get_all_roles())
163        if value in roles.keys():
164            title = roles[value].title
165            if '.' in title:
166                title = title.split('.', 2)[1]
167        return title
168
169class CaptchaSource(BasicSourceFactory):
170    """A source for captchas.
171    """
172    def getValues(self):
173        captchas = ['No captcha', 'Testing captcha', 'ReCaptcha']
174        try:
175            # we have to 'try' because IConfiguration can only handle
176            # interfaces from w.k.interface.
177            from waeup.kofa.browser.interfaces import ICaptchaManager
178        except:
179            return captchas
180        return sorted(getUtility(ICaptchaManager).getAvailCaptchas().keys())
181
182    def getTitle(self, value):
183        return value
184
185class IResultEntry(Interface):
186    """A school grade entry.
187    """
188    subject = schema.Choice(
189        title = _(u'Subject'),
190        source = SubjectSource(),
191        )
192    grade = schema.Choice(
193        title = _(u'Grade'),
194        source = GradeSource(),
195        )
196
197class IResultEntryField(IObject):
198    """A zope.schema-like field for usage in interfaces.
199
200    Marker interface to distuingish result entries from ordinary
201    object fields. Needed for registration of widgets.
202    """
203
204class IKofaUtils(Interface):
205    """A collection of methods which are subject to customization.
206    """
207
208    PORTAL_LANGUAGE = Attribute("Dict of global language setting")
209    PREFERRED_LANGUAGES_DICT = Attribute("Dict of preferred languages")
210    EXAM_SUBJECTS_DICT = Attribute("Dict of examination subjects")
211    EXAM_GRADES_DICT = Attribute("Dict of examination grades")
212    INST_TYPES_DICT = Attribute("Dict if institution types")
213    STUDY_MODES_DICT = Attribute("Dict of study modes")
214    APP_CATS_DICT = Attribute("Dict of application categories")
215    SEMESTER_DICT = Attribute("Dict of semesters or trimesters")
216    INT_PHONE_PREFIXES = Attribute("Dict of international phone number prefixes")
217
218    def sendContactForm(
219          from_name,from_addr,rcpt_name,rcpt_addr,
220          from_username,usertype,portal,body,subject):
221        """Send an email with data provided by forms.
222        """
223
224    def fullname(firstname,lastname,middlename):
225        """Full name constructor.
226        """
227
228    def sendCredentials(user, password, login_url, msg):
229        """Send credentials as email.
230
231        Input is the applicant for which credentials are sent and the
232        password.
233
234        Returns True or False to indicate successful operation.
235        """
236
237    def genPassword(length, chars):
238        """Generate a random password.
239        """
240
241class IKofaObject(Interface):
242    """A Kofa object.
243
244    This is merely a marker interface.
245    """
246
247class IUniversity(IKofaObject):
248    """Representation of a university.
249    """
250
251
252class IKofaContainer(IKofaObject):
253    """A container for Kofa objects.
254    """
255
256class IKofaContained(IKofaObject):
257    """An item contained in an IKofaContainer.
258    """
259
260class ICSVExporter(Interface):
261    """A CSV file exporter for objects.
262    """
263    fields = Attribute("""List of fieldnames in resulting CSV""")
264
265    title = schema.TextLine(
266        title = u'Title',
267        description = u'Description to be displayed in selections.',
268        )
269    def mangle_value(value, name, obj):
270        """Mangle `value` extracted from `obj` or suobjects thereof.
271
272        This is called by export before actually writing to the result file.
273        """
274
275    def export(iterable, filepath=None):
276        """Export iterables as rows in a CSV file.
277
278        If `filepath` is not given, a string with the data should be returned.
279
280        What kind of iterables are acceptable depends on the specific
281        exporter implementation.
282        """
283
284    def export_all(site, filapath=None):
285        """Export all items in `site` as CSV file.
286
287        if `filepath` is not given, a string with the data should be returned.
288        """
289
290class IKofaExporter(Interface):
291    """An exporter for objects.
292    """
293    def export(obj, filepath=None):
294        """Export by pickling.
295
296        Returns a file-like object containing a representation of `obj`.
297
298        This is done using `pickle`. If `filepath` is ``None``, a
299        `cStringIO` object is returned, that contains the saved data.
300        """
301
302class IKofaXMLExporter(Interface):
303    """An XML exporter for objects.
304    """
305    def export(obj, filepath=None):
306        """Export as XML.
307
308        Returns an XML representation of `obj`.
309
310        If `filepath` is ``None``, a StringIO` object is returned,
311        that contains the transformed data.
312        """
313
314class IKofaXMLImporter(Interface):
315    """An XML import for objects.
316    """
317    def doImport(filepath):
318        """Create Python object from XML.
319
320        Returns a Python object.
321        """
322
323class IBatchProcessor(Interface):
324    """A batch processor that handles mass-operations.
325    """
326    name = schema.TextLine(
327        title = _(u'Processor name')
328        )
329
330    def doImport(path, headerfields, mode='create', user='Unknown',
331                 logger=None, ignore_empty=True):
332        """Read data from ``path`` and update connected object.
333
334        `headerfields` is a list of headerfields as read from the file
335        to import.
336
337        `mode` gives the import mode to use (``'create'``,
338        ``'update'``, or ``'remove'``.
339
340        `user` is a string describing the user performing the
341        import. Normally fetched from current principal.
342
343        `logger` is the logger to use during import.
344
345        `ignore_emtpy` in update mode ignores empty fields if true.
346        """
347
348class IContactForm(IKofaObject):
349    """A contact form.
350    """
351
352    email_from = schema.ASCIILine(
353        title = _(u'Email Address:'),
354        default = None,
355        required = True,
356        constraint=validate_email,
357        )
358
359    email_to = schema.ASCIILine(
360        title = _(u'Email to:'),
361        default = None,
362        required = True,
363        constraint=validate_email,
364        )
365
366    subject = schema.TextLine(
367        title = _(u'Subject:'),
368        required = True,)
369
370    fullname = schema.TextLine(
371        title = _(u'Full Name:'),
372        required = True,)
373
374    body = schema.Text(
375        title = _(u'Text:'),
376        required = True,)
377
378class IKofaPrincipalInfo(IPrincipalInfo):
379    """Infos about principals that are users of Kofa Kofa.
380    """
381    email = Attribute("The email address of a user")
382    phone = Attribute("The phone number of a user")
383
384
385class IKofaPrincipal(IPrincipal):
386    """A principle for Kofa Kofa.
387
388    This interface extends zope.security.interfaces.IPrincipal and
389    requires also an `id` and other attributes defined there.
390    """
391
392    email = schema.TextLine(
393        title = _(u'Email Address'),
394        description = u'',
395        required=False,)
396
397    phone = PhoneNumber(
398        title = _(u'Phone'),
399        description = u'',
400        required=False,)
401
402class IUserAccount(IKofaObject):
403    """A user account.
404    """
405    name = schema.TextLine(
406        title = _(u'User Id'),
407        description = u'Login name of user',
408        required = True,)
409
410    title = schema.TextLine(
411        title = _(u'Full Name'),
412        required = False,)
413
414    description = schema.Text(
415        title = _(u'Description/Notice'),
416        required = False,)
417
418    email = schema.ASCIILine(
419        title = _(u'Email Address'),
420        default = None,
421        required = True,
422        constraint=validate_email,
423        )
424
425    phone = PhoneNumber(
426        title = _(u'Phone'),
427        default = None,
428        required = False,
429        )
430
431    roles = schema.List(
432        title = _(u'Portal roles'),
433        value_type = schema.Choice(source=RoleSource()),
434        required = False,
435        )
436
437class IPasswordValidator(Interface):
438    """A password validator utility.
439    """
440
441    def validate_password(password, password_repeat):
442        """Validates a password by comparing it with
443        control password and checking some other requirements.
444        """
445
446
447class IUsersContainer(IKofaObject):
448    """A container for users (principals).
449
450    These users are used for authentication purposes.
451    """
452
453    def addUser(name, password, title=None, description=None):
454        """Add a user.
455        """
456
457    def delUser(name):
458        """Delete a user if it exists.
459        """
460
461class ILocalRolesAssignable(Interface):
462    """The local roles assignable to an object.
463    """
464    def __call__():
465        """Returns a list of dicts.
466
467        Each dict contains a ``name`` referring to the role assignable
468        for the specified object and a `title` to describe the range
469        of users to which this role can be assigned.
470        """
471
472class IConfigurationContainer(IKofaObject):
473    """A container for session configuration objects.
474    """
475
476    name = schema.TextLine(
477        title = _(u'Name of University'),
478        default = _(u'Sample University'),
479        required = True,
480        )
481
482    acronym = schema.TextLine(
483        title = _(u'Abbreviated Title of University'),
484        default = u'WAeUP.Kofa',
485        required = True,
486        )
487
488    skin = schema.Choice(
489        title = _(u'Skin'),
490        default = u'gray waeup theme',
491        vocabulary = 'waeup.kofa.browser.theming.ThemesVocabulary',
492        required = True,
493        )
494
495    frontpage = schema.Text(
496        title = _(u'Content in reST format'),
497        required = False,
498        default = default_frontpage,
499        )
500
501    frontpage_dict = schema.Dict(
502        title = u'Content as language dictionary with values in html format',
503        required = False,
504        default = {},
505        )
506
507    accommodation_session = schema.Choice(
508        title = _(u'Accommodation Booking Session'),
509        source = academic_sessions_vocab,
510        default = datetime.now().year,
511        required = False,
512        readonly = False,
513        )
514
515    accommodation_states = schema.List(
516        title = _(u'Allowed States for Accommodation Booking'),
517        value_type = schema.Choice(
518            vocabulary = registration_states_vocab,
519            ),
520        default = [],
521        )
522
523    name_admin = schema.TextLine(
524        title = _(u'Name of Administrator'),
525        default = u'Administrator',
526        required = True,
527        )
528
529    email_admin = schema.ASCIILine(
530        title = _(u'Email Address of Administrator'),
531        default = 'contact@waeup.org',
532        required = True,
533        constraint=validate_email,
534        )
535
536    email_subject = schema.TextLine(
537        title = _(u'Subject of Email to Administrator'),
538        default = _(u'Kofa Contact'),
539        required = True,
540        )
541
542    smtp_mailer = schema.Choice(
543        title = _(u'SMTP mailer to use when sending mail'),
544        vocabulary = 'Mail Delivery Names',
545        default = 'No email service',
546        required = True,
547        )
548
549    captcha = schema.Choice(
550        title = _(u'Captcha used for public registration pages'),
551        source = CaptchaSource(),
552        default = u'No captcha',
553        required = True,
554        )
555
556    carry_over = schema.Bool(
557        title = _(u'Carry-over Course Registration'),
558        default = False,
559        )
560
561class ISessionConfiguration(IKofaObject):
562    """A session configuration object.
563    """
564
565    academic_session = schema.Choice(
566        title = _(u'Academic Session'),
567        source = academic_sessions_vocab,
568        default = None,
569        required = True,
570        readonly = True,
571        )
572
573    application_fee = schema.Float(
574        title = _(u'Application Fee'),
575        default = 0.0,
576        required = False,
577        )
578
579    clearance_fee = schema.Float(
580        title = _(u'Clearance Fee'),
581        default = 0.0,
582        required = False,
583        )
584
585    booking_fee = schema.Float(
586        title = _(u'Bed Booking Fee'),
587        default = 0.0,
588        required = False,
589        )
590
591    def getSessionString():
592        """Returns the session string from the vocabulary.
593        """
594
595
596class ISessionConfigurationAdd(ISessionConfiguration):
597    """A session configuration object in add mode.
598    """
599
600    academic_session = schema.Choice(
601        title = _(u'Academic Session'),
602        source = academic_sessions_vocab,
603        default = None,
604        required = True,
605        readonly = False,
606        )
607
608ISessionConfigurationAdd['academic_session'].order =  ISessionConfiguration[
609    'academic_session'].order
610
611class IDataCenter(IKofaObject):
612    """A data center.
613
614    TODO : declare methods, at least those needed by pages.
615    """
616    pass
617
618class IDataCenterFile(Interface):
619    """A data center file.
620    """
621
622    name = schema.TextLine(
623        title = u'Filename')
624
625    size = schema.TextLine(
626        title = u'Human readable file size')
627
628    uploaddate = schema.TextLine(
629        title = u'Human readable upload datetime')
630
631    lines = schema.Int(
632        title = u'Number of lines in file')
633
634    def getDate():
635        """Get creation timestamp from file in human readable form.
636        """
637
638    def getSize():
639        """Get human readable size of file.
640        """
641
642    def getLinesNumber():
643        """Get number of lines of file.
644        """
645
646class IDataCenterStorageMovedEvent(IObjectEvent):
647    """Emitted, when the storage of a datacenter changes.
648    """
649
650class IObjectUpgradeEvent(IObjectEvent):
651    """Can be fired, when an object shall be upgraded.
652    """
653
654class ILocalRoleSetEvent(IObjectEvent):
655    """A local role was granted/revoked for a principal on an object.
656    """
657    role_id = Attribute(
658        "The role id that was set.")
659    principal_id = Attribute(
660        "The principal id for which the role was granted/revoked.")
661    granted = Attribute(
662        "Boolean. If false, then the role was revoked.")
663
664class IQueryResultItem(Interface):
665    """An item in a search result.
666    """
667    url = schema.TextLine(
668        title = u'URL that links to the found item')
669    title = schema.TextLine(
670        title = u'Title displayed in search results.')
671    description = schema.Text(
672        title = u'Longer description of the item found.')
673
674class IKofaPluggable(Interface):
675    """A component that might be plugged into a Kofa Kofa app.
676
677    Components implementing this interface are referred to as
678    'plugins'. They are normally called when a new
679    :class:`waeup.kofa.app.University` instance is created.
680
681    Plugins can setup and update parts of the central site without the
682    site object (normally a :class:`waeup.kofa.app.University` object)
683    needing to know about that parts. The site simply collects all
684    available plugins, calls them and the plugins care for their
685    respective subarea like the applicants area or the datacenter
686    area.
687
688    Currently we have no mechanism to define an order of plugins. A
689    plugin should therefore make no assumptions about the state of the
690    site or other plugins being run before and instead do appropriate
691    checks if necessary.
692
693    Updates can be triggered for instance by the respective form in
694    the site configuration. You normally do updates when the
695    underlying software changed.
696    """
697    def setup(site, name, logger):
698        """Create an instance of the plugin.
699
700        The method is meant to be called by the central app (site)
701        when it is created.
702
703        `site`:
704           The site that requests a setup.
705
706        `name`:
707           The name under which the plugin was registered (utility name).
708
709        `logger`:
710           A standard Python logger for the plugins use.
711        """
712
713    def update(site, name, logger):
714        """Method to update an already existing plugin.
715
716        This might be called by a site when something serious
717        changes. It is a poor-man replacement for Zope generations
718        (but probably more comprehensive and better understandable).
719
720        `site`:
721           The site that requests an update.
722
723        `name`:
724           The name under which the plugin was registered (utility name).
725
726        `logger`:
727           A standard Python logger for the plugins use.
728        """
729
730class IAuthPluginUtility(Interface):
731    """A component that cares for authentication setup at site creation.
732
733    Utilities providing this interface are looked up when a Pluggable
734    Authentication Utility (PAU) for any
735    :class:`waeup.kofa.app.University` instance is created and put
736    into ZODB.
737
738    The setup-code then calls the `register` method of the utility and
739    expects a modified (or unmodified) version of the PAU back.
740
741    This allows to define any authentication setup modifications by
742    submodules or third-party modules/packages.
743    """
744
745    def register(pau):
746        """Register any plugins wanted to be in the PAU.
747        """
748
749    def unregister(pau):
750        """Unregister any plugins not wanted to be in the PAU.
751        """
752
753class IObjectConverter(Interface):
754    """Object converters are available as simple adapters, adapting
755       interfaces (not regular instances).
756
757    """
758
759    def fromStringDict(self, data_dict, context, form_fields=None):
760        """Convert values in `data_dict`.
761
762        Converts data in `data_dict` into real values based on
763        `context` and `form_fields`.
764
765        `data_dict` is a mapping (dict) from field names to values
766        represented as strings.
767
768        The fields (keys) to convert can be given in optional
769        `form_fields`. If given, form_fields should be an instance of
770        :class:`zope.formlib.form.Fields`. Suitable instances are for
771        example created by :class:`grok.AutoFields`.
772
773        If no `form_fields` are given, a default is computed from the
774        associated interface.
775
776        The `context` can be an existing object (implementing the
777        associated interface) or a factory name. If it is a string, we
778        try to create an object using
779        :func:`zope.component.createObject`.
780
781        Returns a tuple ``(<FIELD_ERRORS>, <INVARIANT_ERRORS>,
782        <DATA_DICT>)`` where
783
784        ``<FIELD_ERRORS>``
785           is a list of tuples ``(<FIELD_NAME>, <ERROR>)`` for each
786           error that happened when validating the input data in
787           `data_dict`
788
789        ``<INVARIANT_ERRORS>``
790           is a list of invariant errors concerning several fields
791
792        ``<DATA_DICT>``
793           is a dict with the values from input dict converted.
794
795        If errors happen, i.e. the error lists are not empty, always
796        an empty ``<DATA_DICT>`` is returned.
797
798        If ``<DATA_DICT>` is non-empty, there were no errors.
799        """
800
801class IFieldConverter(Interface):
802    def request_data(name, value, schema_field, prefix='', mode='create'):
803        """Create a dict with key-value mapping as created by a request.
804
805        `name` and `value` are expected to be parsed from CSV or a
806        similar input and represent an attribute to be set to a
807        representation of value.
808
809        `mode` gives the mode of import.
810
811        :meth:`update_request_data` is then requested to turn this
812        name and value into vars as they would be sent by a regular
813        form submit. This means we do not create the real values to be
814        set but we only define the values that would be sent in a
815        browser request to request the creation of those values.
816
817        The returned dict should contain names and values of a faked
818        browser request for the given `schema_field`.
819
820        Field converters are normally registered as adapters to some
821        specific zope.schema field.
822        """
823
824class IObjectHistory(Interface):
825
826    messages = schema.List(
827        title = u'List of messages stored',
828        required = True,
829        )
830
831    def addMessage(message):
832        """Add a message.
833        """
834
835class IKofaWorkflowInfo(IWorkflowInfo):
836    """A :class:`hurry.workflow.workflow.WorkflowInfo` with additional
837       methods for convenience.
838    """
839    def getManualTransitions():
840        """Get allowed manual transitions.
841
842        Get a sorted list of tuples containing the `transition_id` and
843        `title` of each allowed transition.
844        """
845
846class ISiteLoggers(Interface):
847
848    loggers = Attribute("A list or generator of registered KofaLoggers")
849
850    def register(name, filename=None, site=None, **options):
851        """Register a logger `name` which logs to `filename`.
852
853        If `filename` is not given, logfile will be `name` with
854        ``.log`` as filename extension.
855        """
856
857    def unregister(name):
858        """Unregister a once registered logger.
859        """
860
861class ILogger(Interface):
862    """A logger cares for setup, update and restarting of a Python logger.
863    """
864
865    logger = Attribute("""A :class:`logging.Logger` instance""")
866
867
868    def __init__(name, filename=None, site=None, **options):
869        """Create a Kofa logger instance.
870        """
871
872    def setup():
873        """Create a Python :class:`logging.Logger` instance.
874
875        The created logger is based on the params given by constructor.
876        """
877
878    def update(**options):
879        """Update the logger.
880
881        Updates the logger respecting modified `options` and changed
882        paths.
883        """
884
885class ILoggerCollector(Interface):
886
887    def getLoggers(site):
888        """Return all loggers registered for `site`.
889        """
890
891    def registerLogger(site, logging_component):
892        """Register a logging component residing in `site`.
893        """
894
895    def unregisterLogger(site, logging_component):
896        """Unregister a logger.
897        """
898
899#
900# External File Storage and relatives
901#
902class IFileStoreNameChooser(INameChooser):
903    """See zope.container.interfaces.INameChooser for base methods.
904    """
905    def checkName(name, attr=None):
906        """Check whether an object name is valid.
907
908        Raises a user error if the name is not valid.
909        """
910
911    def chooseName(name, attr=None):
912        """Choose a unique valid file id for the object.
913
914        The given name may be taken into account when choosing the
915        name (file id).
916
917        chooseName is expected to always choose a valid file id (that
918        would pass the checkName test) and never raise an error.
919
920        If `attr` is not ``None`` it might been taken into account as
921        well when generating the file id. Usual behaviour is to
922        interpret `attr` as a hint for what type of file for a given
923        context should be stored if there are several types
924        possible. For instance for a certain student some file could
925        be the connected passport photograph or some certificate scan
926        or whatever. Each of them has to be stored in a different
927        location so setting `attr` to a sensible value should give
928        different file ids returned.
929        """
930
931class IExtFileStore(IFileRetrieval):
932    """A file storage that stores files in filesystem (not as blobs).
933    """
934    root = schema.TextLine(
935        title = u'Root path of file store.',
936        )
937
938    def getFile(file_id):
939        """Get raw file data stored under file with `file_id`.
940
941        Returns a file descriptor open for reading or ``None`` if the
942        file cannot be found.
943        """
944
945    def getFileByContext(context, attr=None):
946        """Get raw file data stored for the given context.
947
948        Returns a file descriptor open for reading or ``None`` if no
949        such file can be found.
950
951        Both, `context` and `attr` might be used to find (`context`)
952        and feed (`attr`) an appropriate file name chooser.
953
954        This is a convenience method.
955        """
956
957    def deleteFile(file_id):
958        """Delete file stored under `file_id`.
959
960        Remove file from filestore so, that it is not available
961        anymore on next call to getFile for the same file_id.
962
963        Should not complain if no such file exists.
964        """
965
966    def deleteFileByContext(context, attr=None):
967        """Delete file for given `context` and `attr`.
968
969        Both, `context` and `attr` might be used to find (`context`)
970        and feed (`attr`) an appropriate file name chooser.
971
972        This is a convenience method.
973        """
974
975    def createFile(filename, f):
976        """Create file given by f with filename `filename`
977
978        Returns a hurry.file.File-based object.
979        """
980
981class IFileStoreHandler(Interface):
982    """Filestore handlers handle specific files for file stores.
983
984    If a file to store/get provides a specific filename, a file store
985    looks up special handlers for that type of file.
986
987    """
988    def pathFromFileID(store, root, filename):
989        """Turn file id into path to store.
990
991        Returned path should be absolute.
992        """
993
994    def createFile(store, root, filename, file_id, file):
995        """Return some hurry.file based on `store` and `file_id`.
996
997        Some kind of callback method called by file stores to create
998        file objects from file_id.
999
1000        Returns a tuple ``(raw_file, path, file_like_obj)`` where the
1001        ``file_like_obj`` should be a HurryFile, a KofaImageFile or
1002        similar. ``raw_file`` is the (maybe changed) input file and
1003        ``path`` the relative internal path to store the file at.
1004
1005        Please make sure the ``raw_file`` is opened for reading and
1006        the file descriptor set at position 0 when returned.
1007
1008        This method also gets the raw input file object that is about
1009        to be stored and is expected to raise any exceptions if some
1010        kind of validation or similar fails.
1011        """
1012
1013class IPDF(Interface):
1014    """A PDF representation of some context.
1015    """
1016
1017    def __call__(view=None, note=None):
1018        """Create a bytestream representing a PDF from context.
1019
1020        If `view` is passed in additional infos might be rendered into
1021        the document.
1022
1023        `note` is optional HTML rendered at bottom of the created
1024        PDF. Please consider the limited reportlab support for HTML,
1025        but using font-tags and friends you certainly can get the
1026        desired look.
1027        """
1028
1029class IMailService(Interface):
1030    """A mail service.
1031    """
1032
1033    def __call__():
1034        """Get the default mail delivery.
1035        """
1036
1037from zope.configuration.fields import Path
1038class IDataCenterConfig(Interface):
1039    path = Path(
1040        title = u'Path',
1041        description = u"Directory where the datacenter should store "
1042                      u"files by default (adjustable in web UI).",
1043        required = True,
1044        )
Note: See TracBrowser for help on using the repository browser.