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

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

Rename importers to processors.

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