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

Last change on this file since 8176 was 8176, checked in by uli, 13 years ago

Use PhoneNumber?.

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