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

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

BatchProcessors? apparently make no use of any mode attribute. But they
might have use for an explicit hint whether to handle empty fields as
ones to ignore (if people are not able or too lazy to set IGNORE
markers manually).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.2 KB
RevLine 
[7193]1## $Id: interfaces.py 8218 2012-04-19 14:15:51Z uli $
[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
[8176]35from waeup.kofa.schema import PhoneNumber
[3521]36
[7811]37_ = MessageFactory = zope.i18nmessageid.MessageFactory('waeup.kofa')
[6990]38
[8214]39DELETION_MARKER = 'XXX'
40IGNORE_MARKER = '<IGNORE>'
[8202]41
[7673]42CREATED = 'created'
43ADMITTED = 'admitted'
44CLEARANCE = 'clearance started'
45REQUESTED = 'clearance requested'
46CLEARED = 'cleared'
47PAID = 'school fee paid'
48RETURNING = 'returning'
49REGISTERED = 'courses registered'
50VALIDATED = 'courses validated'
[7670]51
[7702]52default_frontpage = u'' + codecs.open(os.path.join(
53        os.path.dirname(__file__), 'frontpage.rst'),
54        encoding='utf-8', mode='rb').read()
[6361]55
[7819]56def SimpleKofaVocabulary(*terms):
[6915]57    """A well-buildt vocabulary provides terms with a value, token and
58       title for each term
59    """
60    return SimpleVocabulary([
61            SimpleTerm(value, value, title) for title, value in terms])
62
63def year_range():
64    curr_year = datetime.now().year
[7459]65    return range(curr_year - 4, curr_year + 5)
[6915]66
67def academic_sessions():
68    curr_year = datetime.now().year
69    year_range = range(curr_year - 10, curr_year + 2)
70    return [('%s/%s' % (year,year+1), year) for year in year_range]
71
[7819]72academic_sessions_vocab = SimpleKofaVocabulary(*academic_sessions())
[6915]73
[7819]74registration_states_vocab = SimpleKofaVocabulary(
[7677]75    (_('created'), CREATED),
76    (_('admitted'), ADMITTED),
77    (_('clearance started'), CLEARANCE),
78    (_('clearance requested'), REQUESTED),
79    (_('cleared'), CLEARED),
80    (_('school fee paid'), PAID),
81    (_('returning'), RETURNING),
82    (_('courses registered'), REGISTERED),
83    (_('courses validated'), VALIDATED),
[6990]84    )
85
[7795]86class SubjectSource(BasicSourceFactory):
[7918]87    """A source for school subjects used in exam documentation.
88    """
[7795]89    def getValues(self):
[7841]90        subjects_dict = getUtility(IKofaUtils).EXAM_SUBJECTS_DICT
[7837]91        return sorted(subjects_dict.keys())
92
[7795]93    def getTitle(self, value):
[7841]94        subjects_dict = getUtility(IKofaUtils).EXAM_SUBJECTS_DICT
[7837]95        return "%s:" % subjects_dict[value]
[7795]96
97class GradeSource(BasicSourceFactory):
[7918]98    """A source for exam grades.
99    """
[7795]100    def getValues(self):
[7918]101        for entry in getUtility(IKofaUtils).EXAM_GRADES:
102            yield entry[0]
[7837]103
[7795]104    def getTitle(self, value):
[7918]105        return dict(getUtility(IKofaUtils).EXAM_GRADES)[value]
[7795]106
[7850]107# Define a validation method for email addresses
[7221]108class NotAnEmailAddress(schema.ValidationError):
109    __doc__ = u"Invalid email address"
110
111check_email = re.compile(
[7608]112    r"[a-zA-Z0-9._%-']+@([a-zA-Z0-9-]+.)*[a-zA-Z]{2,4}").match
[7221]113
114def validate_email(value):
115    if not check_email(value):
116        raise NotAnEmailAddress(value)
117    return True
118
[7850]119# Define a validation method for international phone numbers
120class InvalidPhoneNumber(schema.ValidationError):
121    __doc__ = u"Invalid phone number"
122
123# represent format +NNN-NNNN-NNNN
124RE_INT_PHONE = re.compile(r"^\+?\d+\-\d+\-[\d\-]+$")
125
126def validate_phone(value):
[7851]127    if not RE_INT_PHONE.match(value):
[7850]128        raise InvalidPhoneNumber(value)
129    return True
130
[4858]131class FatalCSVError(Exception):
132    """Some row could not be processed.
133    """
134    pass
135
[6226]136class DuplicationError(Exception):
137    """An exception that can be raised when duplicates are found.
138
139    When raising :exc:`DuplicationError` you can, beside the usual
140    message, specify a list of objects which are duplicates. These
141    values can be used by catching code to print something helpful or
142    similar.
143    """
144    def __init__(self, msg, entries=[]):
145        self.msg = msg
146        self.entries = entries
147
148    def __str__(self):
149        return '%r' % self.msg
150
[6143]151class RoleSource(BasicSourceFactory):
[7178]152    """A source for site roles.
[6508]153    """
[6143]154    def getValues(self):
[6157]155        # late import: in interfaces we should not import local modules
[7811]156        from waeup.kofa.permissions import get_waeup_role_names
[7186]157        return get_waeup_role_names()
[6157]158
159    def getTitle(self, value):
160        # late import: in interfaces we should not import local modules
[7811]161        from waeup.kofa.permissions import get_all_roles
[7186]162        roles = dict(get_all_roles())
[6157]163        if value in roles.keys():
164            title = roles[value].title
[6569]165            if '.' in title:
166                title = title.split('.', 2)[1]
[6157]167        return title
[6143]168
[7313]169class CaptchaSource(BasicSourceFactory):
170    """A source for captchas.
171    """
172    def getValues(self):
[7323]173        captchas = ['No captcha', 'Testing captcha', 'ReCaptcha']
[7313]174        try:
175            # we have to 'try' because IConfiguration can only handle
[7817]176            # interfaces from w.k.interface.
[7811]177            from waeup.kofa.browser.interfaces import ICaptchaManager
[7313]178        except:
179            return captchas
180        return sorted(getUtility(ICaptchaManager).getAvailCaptchas().keys())
181
182    def getTitle(self, value):
183        return value
184
[7795]185class IResultEntry(Interface):
186    """A school grade entry.
187    """
188    subject = schema.Choice(
189        title = _(u'Subject'),
190        source = SubjectSource(),
191        )
192    grade = schema.Choice(
193        title = _(u'Grade'),
194        source = GradeSource(),
195        )
196
197class IResultEntryField(IObject):
198    """A zope.schema-like field for usage in interfaces.
199
200    Marker interface to distuingish result entries from ordinary
201    object fields. Needed for registration of widgets.
202    """
203
[7819]204class IKofaUtils(Interface):
[7358]205    """A collection of methods which are subject to customization.
206    """
[7568]207
[7841]208    PORTAL_LANGUAGE = Attribute("Dict of global language setting")
209    PREFERRED_LANGUAGES_DICT = Attribute("Dict of preferred languages")
210    EXAM_SUBJECTS_DICT = Attribute("Dict of examination subjects")
211    EXAM_GRADES_DICT = Attribute("Dict of examination grades")
212    INST_TYPES_DICT = Attribute("Dict if institution types")
213    STUDY_MODES_DICT = Attribute("Dict of study modes")
214    APP_CATS_DICT = Attribute("Dict of application categories")
215    SEMESTER_DICT = Attribute("Dict of semesters or trimesters")
[7871]216    INT_PHONE_PREFIXES = Attribute("Dict of international phone number prefixes")
[7568]217
[7404]218    def sendContactForm(
219          from_name,from_addr,rcpt_name,rcpt_addr,
220          from_username,usertype,portal,body,subject):
[7358]221        """Send an email with data provided by forms.
222        """
223
[7475]224    def fullname(firstname,lastname,middlename):
225        """Full name constructor.
226        """
227
228    def sendCredentials(user, password, login_url, msg):
229        """Send credentials as email.
230
231        Input is the applicant for which credentials are sent and the
232        password.
233
234        Returns True or False to indicate successful operation.
235        """
236
237    def genPassword(length, chars):
238        """Generate a random password.
239        """
240
[7819]241class IKofaObject(Interface):
242    """A Kofa object.
[5663]243
244    This is merely a marker interface.
[4789]245    """
246
[7819]247class IUniversity(IKofaObject):
[3521]248    """Representation of a university.
249    """
[5955]250
[6065]251
[7819]252class IKofaContainer(IKofaObject):
253    """A container for Kofa objects.
[4789]254    """
255
[7819]256class IKofaContained(IKofaObject):
257    """An item contained in an IKofaContainer.
[4789]258    """
[6136]259
[7726]260class ICSVExporter(Interface):
261    """A CSV file exporter for objects.
262    """
263    fields = Attribute("""List of fieldnames in resulting CSV""")
[7907]264
265    title = schema.TextLine(
266        title = u'Title',
267        description = u'Description to be displayed in selections.',
268        )
[7726]269    def mangle_value(value, name, obj):
270        """Mangle `value` extracted from `obj` or suobjects thereof.
271
272        This is called by export before actually writing to the result file.
273        """
274
[7730]275    def export(iterable, filepath=None):
276        """Export iterables as rows in a CSV file.
[7726]277
278        If `filepath` is not given, a string with the data should be returned.
[7730]279
280        What kind of iterables are acceptable depends on the specific
281        exporter implementation.
[7726]282        """
283
284    def export_all(site, filapath=None):
285        """Export all items in `site` as CSV file.
286
287        if `filepath` is not given, a string with the data should be returned.
288        """
289
[7819]290class IKofaExporter(Interface):
[4789]291    """An exporter for objects.
292    """
293    def export(obj, filepath=None):
294        """Export by pickling.
295
296        Returns a file-like object containing a representation of `obj`.
297
298        This is done using `pickle`. If `filepath` is ``None``, a
299        `cStringIO` object is returned, that contains the saved data.
300        """
301
[7819]302class IKofaXMLExporter(Interface):
[4789]303    """An XML exporter for objects.
304    """
305    def export(obj, filepath=None):
306        """Export as XML.
307
308        Returns an XML representation of `obj`.
309
310        If `filepath` is ``None``, a StringIO` object is returned,
311        that contains the transformed data.
312        """
313
[7819]314class IKofaXMLImporter(Interface):
[4789]315    """An XML import for objects.
316    """
317    def doImport(filepath):
318        """Create Python object from XML.
319
320        Returns a Python object.
321        """
322
[4858]323class IBatchProcessor(Interface):
324    """A batch processor that handles mass-operations.
325    """
326    name = schema.TextLine(
[7933]327        title = _(u'Processor name')
[4858]328        )
329
[5476]330    def doImport(path, headerfields, mode='create', user='Unknown',
[8218]331                 logger=None, ignore_empty=True):
[4858]332        """Read data from ``path`` and update connected object.
[5476]333
334        `headerfields` is a list of headerfields as read from the file
335        to import.
336
337        `mode` gives the import mode to use (``'create'``,
338        ``'update'``, or ``'remove'``.
339
340        `user` is a string describing the user performing the
341        import. Normally fetched from current principal.
342
343        `logger` is the logger to use during import.
[8218]344
345        `ignore_emtpy` in update mode ignores empty fields if true.
[4858]346        """
347
[7819]348class IContactForm(IKofaObject):
[7225]349    """A contact form.
350    """
351
352    email_from = schema.ASCIILine(
[7828]353        title = _(u'Email Address:'),
[7225]354        default = None,
355        required = True,
356        constraint=validate_email,
357        )
358
359    email_to = schema.ASCIILine(
[7828]360        title = _(u'Email to:'),
[7225]361        default = None,
362        required = True,
363        constraint=validate_email,
364        )
365
366    subject = schema.TextLine(
[7828]367        title = _(u'Subject:'),
[7225]368        required = True,)
369
370    fullname = schema.TextLine(
[7828]371        title = _(u'Full Name:'),
[7225]372        required = True,)
373
374    body = schema.Text(
[7828]375        title = _(u'Text:'),
[7225]376        required = True,)
377
[7819]378class IKofaPrincipalInfo(IPrincipalInfo):
379    """Infos about principals that are users of Kofa Kofa.
[7233]380    """
381    email = Attribute("The email address of a user")
382    phone = Attribute("The phone number of a user")
[7225]383
[7233]384
[7819]385class IKofaPrincipal(IPrincipal):
386    """A principle for Kofa Kofa.
[7233]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(
[7828]393        title = _(u'Email Address'),
[7233]394        description = u'',
395        required=False,)
396
[8176]397    phone = PhoneNumber(
[7828]398        title = _(u'Phone'),
[7233]399        description = u'',
400        required=False,)
401
[7819]402class IUserAccount(IKofaObject):
[4789]403    """A user account.
404    """
405    name = schema.TextLine(
[7828]406        title = _(u'User Id'),
[6512]407        description = u'Login name of user',
[4789]408        required = True,)
[7221]409
[4789]410    title = schema.TextLine(
[7828]411        title = _(u'Full Name'),
[4789]412        required = False,)
[7221]413
[7197]414    description = schema.Text(
[7828]415        title = _(u'Description/Notice'),
[4789]416        required = False,)
[7221]417
418    email = schema.ASCIILine(
[7828]419        title = _(u'Email Address'),
[7221]420        default = None,
[7222]421        required = True,
[7221]422        constraint=validate_email,
423        )
424
[8176]425    phone = PhoneNumber(
[7828]426        title = _(u'Phone'),
[7233]427        default = None,
[8062]428        required = False,
[7233]429        )
430
[4789]431    roles = schema.List(
[7828]432        title = _(u'Portal roles'),
[8079]433        value_type = schema.Choice(source=RoleSource()),
434        required = False,
435        )
[6136]436
[7147]437class IPasswordValidator(Interface):
438    """A password validator utility.
439    """
[6136]440
[7147]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
[7819]447class IUsersContainer(IKofaObject):
[4789]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
[6141]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
[7819]472class IConfigurationContainer(IKofaObject):
[6907]473    """A container for session configuration objects.
474    """
475
476    name = schema.TextLine(
[7828]477        title = _(u'Name of University'),
478        default = _(u'Sample University'),
[6907]479        required = True,
480        )
481
[7459]482    acronym = schema.TextLine(
[7828]483        title = _(u'Abbreviated Title of University'),
[7819]484        default = u'WAeUP.Kofa',
[7459]485        required = True,
486        )
487
[6907]488    skin = schema.Choice(
[7828]489        title = _(u'Skin'),
[6907]490        default = u'gray waeup theme',
[7811]491        vocabulary = 'waeup.kofa.browser.theming.ThemesVocabulary',
[6907]492        required = True,
493        )
494
495    frontpage = schema.Text(
[7828]496        title = _(u'Content in reST format'),
[6907]497        required = False,
498        default = default_frontpage,
499        )
500
[7702]501    frontpage_dict = schema.Dict(
502        title = u'Content as language dictionary with values in html format',
[7485]503        required = False,
[7702]504        default = {},
[7485]505        )
506
[6990]507    accommodation_session = schema.Choice(
[7828]508        title = _(u'Accommodation Booking Session'),
[6990]509        source = academic_sessions_vocab,
510        default = datetime.now().year,
511        required = False,
512        readonly = False,
513        )
514
515    accommodation_states = schema.List(
[7828]516        title = _(u'Allowed States for Accommodation Booking'),
[6990]517        value_type = schema.Choice(
518            vocabulary = registration_states_vocab,
519            ),
520        default = [],
521        )
522
[7223]523    name_admin = schema.TextLine(
[7828]524        title = _(u'Name of Administrator'),
[7223]525        default = u'Administrator',
526        required = False,
527        )
528
[7221]529    email_admin = schema.ASCIILine(
[7828]530        title = _(u'Email Address of Administrator'),
[7221]531        default = 'contact@waeup.org',
532        required = False,
533        constraint=validate_email,
534        )
535
536    email_subject = schema.TextLine(
[7828]537        title = _(u'Subject of Email to Administrator'),
538        default = _(u'Kofa Contact'),
[7221]539        required = False,
540        )
541
[7470]542    smtp_mailer = schema.Choice(
[7828]543        title = _(u'SMTP mailer to use when sending mail'),
[7470]544        vocabulary = 'Mail Delivery Names',
545        default = 'No email service',
546        required = True,
547        )
548
[7313]549    captcha = schema.Choice(
[7828]550        title = _(u'Captcha used for public registration pages'),
[7313]551        source = CaptchaSource(),
552        default = u'No captcha',
553        required = True,
554        )
[7221]555
[7664]556    carry_over = schema.Bool(
[7828]557        title = _(u'Carry-over Course Registration'),
[7664]558        default = False,
559        )
560
[7819]561class ISessionConfiguration(IKofaObject):
[6915]562    """A session configuration object.
[6907]563    """
564
[6915]565    academic_session = schema.Choice(
[7828]566        title = _(u'Academic Session'),
[6915]567        source = academic_sessions_vocab,
568        default = None,
569        required = True,
570        readonly = True,
571        )
572
[7927]573    school_fee_base = schema.Float(
[7828]574        title = _(u'School Fee'),
[7927]575        default = 0.0,
[6915]576        )
577
[7927]578    surcharge_1 = schema.Float(
[7881]579        title = _(u'Surcharge Portal Provider'),
[7927]580        default = 0.0,
[7881]581        required = False,
[6929]582        )
583
[7927]584    surcharge_2 = schema.Float(
[7881]585        title = _(u'Surcharge Payment Gateway Provider'),
[7927]586        default = 0.0,
[7881]587        required = False,
[6929]588        )
589
[7927]590    surcharge_3 = schema.Float(
[7828]591        title = _(u'Surcharge 3'),
[7927]592        default = 0.0,
[7881]593        required = False,
[6929]594        )
595
[7927]596    clearance_fee = schema.Float(
[7828]597        title = _(u'Clearance Fee'),
[7927]598        default = 0.0,
[7881]599        required = False,
[6916]600        )
601
[7927]602    booking_fee = schema.Float(
[7828]603        title = _(u'Booking Fee'),
[7927]604        default = 0.0,
[7881]605        required = False,
[6993]606        )
607
[7927]608    acceptance_fee = schema.Float(
[7828]609        title = _(u'Acceptance Fee'),
[7927]610        default = 0.0,
[7881]611        required = False,
[7250]612        )
613
[6918]614    def getSessionString():
615        """Returns the session string from the vocabulary.
616        """
617
618
[6916]619class ISessionConfigurationAdd(ISessionConfiguration):
620    """A session configuration object in add mode.
621    """
622
623    academic_session = schema.Choice(
[7828]624        title = _(u'Academic Session'),
[6916]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
[7819]634class IDataCenter(IKofaObject):
[4789]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    """
[4858]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')
[6136]656
[4789]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        """
[4858]664
665    def getLinesNumber():
666        """Get number of lines of file.
667        """
[4882]668
669class IDataCenterStorageMovedEvent(IObjectEvent):
670    """Emitted, when the storage of a datacenter changes.
671    """
[5007]672
[6136]673class IObjectUpgradeEvent(IObjectEvent):
674    """Can be fired, when an object shall be upgraded.
675    """
676
[6180]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
[5007]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.')
[6136]696
[7819]697class IKofaPluggable(Interface):
698    """A component that might be plugged into a Kofa Kofa app.
[5658]699
700    Components implementing this interface are referred to as
701    'plugins'. They are normally called when a new
[7811]702    :class:`waeup.kofa.app.University` instance is created.
[5658]703
704    Plugins can setup and update parts of the central site without the
[7811]705    site object (normally a :class:`waeup.kofa.app.University` object)
[5658]706    needing to know about that parts. The site simply collects all
707    available plugins, calls them and the plugins care for their
[5676]708    respective subarea like the applicants area or the datacenter
[5658]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.
[5013]719    """
[5069]720    def setup(site, name, logger):
721        """Create an instance of the plugin.
[5013]722
[5658]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.
[5069]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
[5658]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.
[5069]751        """
[5898]752
[5899]753class IAuthPluginUtility(Interface):
[5898]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
[7811]758    :class:`waeup.kofa.app.University` instance is created and put
[5898]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        """
[6273]775
776class IObjectConverter(Interface):
777    """Object converters are available as simple adapters, adapting
778       interfaces (not regular instances).
779
780    """
781
[6277]782    def fromStringDict(self, data_dict, context, form_fields=None):
783        """Convert values in `data_dict`.
[6273]784
[6277]785        Converts data in `data_dict` into real values based on
786        `context` and `form_fields`.
[6273]787
[6277]788        `data_dict` is a mapping (dict) from field names to values
789        represented as strings.
[6273]790
[6277]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`.
[6273]795
[6277]796        If no `form_fields` are given, a default is computed from the
797        associated interface.
[6273]798
[6277]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.
[6273]822        """
[6293]823
[7932]824class IFieldConverter(Interface):
[8214]825    def request_data(name, value, schema_field, prefix='', mode='create'):
[7932]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
[8214]832        `mode` gives the mode of import.
833
[7932]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
[6338]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        """
[6353]857
[7819]858class IKofaWorkflowInfo(IWorkflowInfo):
[6353]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        """
[6481]868
869class ISiteLoggers(Interface):
870
[7819]871    loggers = Attribute("A list or generator of registered KofaLoggers")
[6481]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):
[7819]892        """Create a Kofa logger instance.
[6481]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        """
[6754]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        """
[7063]921
922#
923# External File Storage and relatives
924#
925class IFileStoreNameChooser(INameChooser):
926    """See zope.container.interfaces.INameChooser for base methods.
927    """
[7066]928    def checkName(name, attr=None):
[7063]929        """Check whether an object name is valid.
930
931        Raises a user error if the name is not valid.
932        """
933
[7066]934    def chooseName(name, attr=None):
935        """Choose a unique valid file id for the object.
[7063]936
[7066]937        The given name may be taken into account when choosing the
938        name (file id).
[7063]939
[7066]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.
[7063]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
[7071]968    def getFileByContext(context, attr=None):
[7063]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
[7071]974        Both, `context` and `attr` might be used to find (`context`)
975        and feed (`attr`) an appropriate file name chooser.
976
[7063]977        This is a convenience method.
978        """
979
[7090]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
[7063]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
[7819]1024        ``file_like_obj`` should be a HurryFile, a KofaImageFile or
[7063]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        """
[7389]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        """
[7473]1046
1047class IMailService(Interface):
1048    """A mail service.
1049    """
1050
1051    def __call__():
1052        """Get the default mail delivery.
1053        """
[7576]1054
1055from zope.configuration.fields import Path
1056class IDataCenterConfig(Interface):
1057    path = Path(
1058        title = u'Path',
[7828]1059        description = u"Directory where the datacenter should store "
1060                      u"files by default (adjustable in web UI).",
[7576]1061        required = True,
1062        )
Note: See TracBrowser for help on using the repository browser.