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

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

Empty If no value is provided in import files, attributes must not be cleared. Clear attribute only if value == DELETIONMARKER.

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