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
RevLine 
[7193]1## $Id: interfaces.py 8202 2012-04-18 05:12:32Z 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
[8176]35from waeup.kofa.schema import PhoneNumber
[3521]36
[7811]37_ = MessageFactory = zope.i18nmessageid.MessageFactory('waeup.kofa')
[6990]38
[8202]39DELETIONMARKER = 'XXX'
40
[7673]41CREATED = 'created'
42ADMITTED = 'admitted'
43CLEARANCE = 'clearance started'
44REQUESTED = 'clearance requested'
45CLEARED = 'cleared'
46PAID = 'school fee paid'
47RETURNING = 'returning'
48REGISTERED = 'courses registered'
49VALIDATED = 'courses validated'
[7670]50
[7702]51default_frontpage = u'' + codecs.open(os.path.join(
52        os.path.dirname(__file__), 'frontpage.rst'),
53        encoding='utf-8', mode='rb').read()
[6361]54
[7819]55def SimpleKofaVocabulary(*terms):
[6915]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
[7459]64    return range(curr_year - 4, curr_year + 5)
[6915]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
[7819]71academic_sessions_vocab = SimpleKofaVocabulary(*academic_sessions())
[6915]72
[7819]73registration_states_vocab = SimpleKofaVocabulary(
[7677]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),
[6990]83    )
84
[7795]85class SubjectSource(BasicSourceFactory):
[7918]86    """A source for school subjects used in exam documentation.
87    """
[7795]88    def getValues(self):
[7841]89        subjects_dict = getUtility(IKofaUtils).EXAM_SUBJECTS_DICT
[7837]90        return sorted(subjects_dict.keys())
91
[7795]92    def getTitle(self, value):
[7841]93        subjects_dict = getUtility(IKofaUtils).EXAM_SUBJECTS_DICT
[7837]94        return "%s:" % subjects_dict[value]
[7795]95
96class GradeSource(BasicSourceFactory):
[7918]97    """A source for exam grades.
98    """
[7795]99    def getValues(self):
[7918]100        for entry in getUtility(IKofaUtils).EXAM_GRADES:
101            yield entry[0]
[7837]102
[7795]103    def getTitle(self, value):
[7918]104        return dict(getUtility(IKofaUtils).EXAM_GRADES)[value]
[7795]105
[7850]106# Define a validation method for email addresses
[7221]107class NotAnEmailAddress(schema.ValidationError):
108    __doc__ = u"Invalid email address"
109
110check_email = re.compile(
[7608]111    r"[a-zA-Z0-9._%-']+@([a-zA-Z0-9-]+.)*[a-zA-Z]{2,4}").match
[7221]112
113def validate_email(value):
114    if not check_email(value):
115        raise NotAnEmailAddress(value)
116    return True
117
[7850]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):
[7851]126    if not RE_INT_PHONE.match(value):
[7850]127        raise InvalidPhoneNumber(value)
128    return True
129
[4858]130class FatalCSVError(Exception):
131    """Some row could not be processed.
132    """
133    pass
134
[6226]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
[6143]150class RoleSource(BasicSourceFactory):
[7178]151    """A source for site roles.
[6508]152    """
[6143]153    def getValues(self):
[6157]154        # late import: in interfaces we should not import local modules
[7811]155        from waeup.kofa.permissions import get_waeup_role_names
[7186]156        return get_waeup_role_names()
[6157]157
158    def getTitle(self, value):
159        # late import: in interfaces we should not import local modules
[7811]160        from waeup.kofa.permissions import get_all_roles
[7186]161        roles = dict(get_all_roles())
[6157]162        if value in roles.keys():
163            title = roles[value].title
[6569]164            if '.' in title:
165                title = title.split('.', 2)[1]
[6157]166        return title
[6143]167
[7313]168class CaptchaSource(BasicSourceFactory):
169    """A source for captchas.
170    """
171    def getValues(self):
[7323]172        captchas = ['No captcha', 'Testing captcha', 'ReCaptcha']
[7313]173        try:
174            # we have to 'try' because IConfiguration can only handle
[7817]175            # interfaces from w.k.interface.
[7811]176            from waeup.kofa.browser.interfaces import ICaptchaManager
[7313]177        except:
178            return captchas
179        return sorted(getUtility(ICaptchaManager).getAvailCaptchas().keys())
180
181    def getTitle(self, value):
182        return value
183
[7795]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
[7819]203class IKofaUtils(Interface):
[7358]204    """A collection of methods which are subject to customization.
205    """
[7568]206
[7841]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")
[7871]215    INT_PHONE_PREFIXES = Attribute("Dict of international phone number prefixes")
[7568]216
[7404]217    def sendContactForm(
218          from_name,from_addr,rcpt_name,rcpt_addr,
219          from_username,usertype,portal,body,subject):
[7358]220        """Send an email with data provided by forms.
221        """
222
[7475]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
[7819]240class IKofaObject(Interface):
241    """A Kofa object.
[5663]242
243    This is merely a marker interface.
[4789]244    """
245
[7819]246class IUniversity(IKofaObject):
[3521]247    """Representation of a university.
248    """
[5955]249
[6065]250
[7819]251class IKofaContainer(IKofaObject):
252    """A container for Kofa objects.
[4789]253    """
254
[7819]255class IKofaContained(IKofaObject):
256    """An item contained in an IKofaContainer.
[4789]257    """
[6136]258
[7726]259class ICSVExporter(Interface):
260    """A CSV file exporter for objects.
261    """
262    fields = Attribute("""List of fieldnames in resulting CSV""")
[7907]263
264    title = schema.TextLine(
265        title = u'Title',
266        description = u'Description to be displayed in selections.',
267        )
[7726]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
[7730]274    def export(iterable, filepath=None):
275        """Export iterables as rows in a CSV file.
[7726]276
277        If `filepath` is not given, a string with the data should be returned.
[7730]278
279        What kind of iterables are acceptable depends on the specific
280        exporter implementation.
[7726]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
[7819]289class IKofaExporter(Interface):
[4789]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
[7819]301class IKofaXMLExporter(Interface):
[4789]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
[7819]313class IKofaXMLImporter(Interface):
[4789]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
[4858]322class IBatchProcessor(Interface):
323    """A batch processor that handles mass-operations.
324    """
325    name = schema.TextLine(
[7933]326        title = _(u'Processor name')
[4858]327        )
328
329    mode = schema.Choice(
[8039]330        title = _(u'Import Mode'),
[4858]331        values = ['create', 'update', 'remove']
332        )
[6136]333
[5476]334    def doImport(path, headerfields, mode='create', user='Unknown',
335                 logger=None):
[4858]336        """Read data from ``path`` and update connected object.
[5476]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.
[4858]348        """
349
[7819]350class IContactForm(IKofaObject):
[7225]351    """A contact form.
352    """
353
354    email_from = schema.ASCIILine(
[7828]355        title = _(u'Email Address:'),
[7225]356        default = None,
357        required = True,
358        constraint=validate_email,
359        )
360
361    email_to = schema.ASCIILine(
[7828]362        title = _(u'Email to:'),
[7225]363        default = None,
364        required = True,
365        constraint=validate_email,
366        )
367
368    subject = schema.TextLine(
[7828]369        title = _(u'Subject:'),
[7225]370        required = True,)
371
372    fullname = schema.TextLine(
[7828]373        title = _(u'Full Name:'),
[7225]374        required = True,)
375
376    body = schema.Text(
[7828]377        title = _(u'Text:'),
[7225]378        required = True,)
379
[7819]380class IKofaPrincipalInfo(IPrincipalInfo):
381    """Infos about principals that are users of Kofa Kofa.
[7233]382    """
383    email = Attribute("The email address of a user")
384    phone = Attribute("The phone number of a user")
[7225]385
[7233]386
[7819]387class IKofaPrincipal(IPrincipal):
388    """A principle for Kofa Kofa.
[7233]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(
[7828]395        title = _(u'Email Address'),
[7233]396        description = u'',
397        required=False,)
398
[8176]399    phone = PhoneNumber(
[7828]400        title = _(u'Phone'),
[7233]401        description = u'',
402        required=False,)
403
[7819]404class IUserAccount(IKofaObject):
[4789]405    """A user account.
406    """
407    name = schema.TextLine(
[7828]408        title = _(u'User Id'),
[6512]409        description = u'Login name of user',
[4789]410        required = True,)
[7221]411
[4789]412    title = schema.TextLine(
[7828]413        title = _(u'Full Name'),
[4789]414        required = False,)
[7221]415
[7197]416    description = schema.Text(
[7828]417        title = _(u'Description/Notice'),
[4789]418        required = False,)
[7221]419
420    email = schema.ASCIILine(
[7828]421        title = _(u'Email Address'),
[7221]422        default = None,
[7222]423        required = True,
[7221]424        constraint=validate_email,
425        )
426
[8176]427    phone = PhoneNumber(
[7828]428        title = _(u'Phone'),
[7233]429        default = None,
[8062]430        required = False,
[7233]431        )
432
[4789]433    roles = schema.List(
[7828]434        title = _(u'Portal roles'),
[8079]435        value_type = schema.Choice(source=RoleSource()),
436        required = False,
437        )
[6136]438
[7147]439class IPasswordValidator(Interface):
440    """A password validator utility.
441    """
[6136]442
[7147]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
[7819]449class IUsersContainer(IKofaObject):
[4789]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
[6141]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
[7819]474class IConfigurationContainer(IKofaObject):
[6907]475    """A container for session configuration objects.
476    """
477
478    name = schema.TextLine(
[7828]479        title = _(u'Name of University'),
480        default = _(u'Sample University'),
[6907]481        required = True,
482        )
483
[7459]484    acronym = schema.TextLine(
[7828]485        title = _(u'Abbreviated Title of University'),
[7819]486        default = u'WAeUP.Kofa',
[7459]487        required = True,
488        )
489
[6907]490    skin = schema.Choice(
[7828]491        title = _(u'Skin'),
[6907]492        default = u'gray waeup theme',
[7811]493        vocabulary = 'waeup.kofa.browser.theming.ThemesVocabulary',
[6907]494        required = True,
495        )
496
497    frontpage = schema.Text(
[7828]498        title = _(u'Content in reST format'),
[6907]499        required = False,
500        default = default_frontpage,
501        )
502
[7702]503    frontpage_dict = schema.Dict(
504        title = u'Content as language dictionary with values in html format',
[7485]505        required = False,
[7702]506        default = {},
[7485]507        )
508
[6990]509    accommodation_session = schema.Choice(
[7828]510        title = _(u'Accommodation Booking Session'),
[6990]511        source = academic_sessions_vocab,
512        default = datetime.now().year,
513        required = False,
514        readonly = False,
515        )
516
517    accommodation_states = schema.List(
[7828]518        title = _(u'Allowed States for Accommodation Booking'),
[6990]519        value_type = schema.Choice(
520            vocabulary = registration_states_vocab,
521            ),
522        default = [],
523        )
524
[7223]525    name_admin = schema.TextLine(
[7828]526        title = _(u'Name of Administrator'),
[7223]527        default = u'Administrator',
528        required = False,
529        )
530
[7221]531    email_admin = schema.ASCIILine(
[7828]532        title = _(u'Email Address of Administrator'),
[7221]533        default = 'contact@waeup.org',
534        required = False,
535        constraint=validate_email,
536        )
537
538    email_subject = schema.TextLine(
[7828]539        title = _(u'Subject of Email to Administrator'),
540        default = _(u'Kofa Contact'),
[7221]541        required = False,
542        )
543
[7470]544    smtp_mailer = schema.Choice(
[7828]545        title = _(u'SMTP mailer to use when sending mail'),
[7470]546        vocabulary = 'Mail Delivery Names',
547        default = 'No email service',
548        required = True,
549        )
550
[7313]551    captcha = schema.Choice(
[7828]552        title = _(u'Captcha used for public registration pages'),
[7313]553        source = CaptchaSource(),
554        default = u'No captcha',
555        required = True,
556        )
[7221]557
[7664]558    carry_over = schema.Bool(
[7828]559        title = _(u'Carry-over Course Registration'),
[7664]560        default = False,
561        )
562
[7819]563class ISessionConfiguration(IKofaObject):
[6915]564    """A session configuration object.
[6907]565    """
566
[6915]567    academic_session = schema.Choice(
[7828]568        title = _(u'Academic Session'),
[6915]569        source = academic_sessions_vocab,
570        default = None,
571        required = True,
572        readonly = True,
573        )
574
[7927]575    school_fee_base = schema.Float(
[7828]576        title = _(u'School Fee'),
[7927]577        default = 0.0,
[6915]578        )
579
[7927]580    surcharge_1 = schema.Float(
[7881]581        title = _(u'Surcharge Portal Provider'),
[7927]582        default = 0.0,
[7881]583        required = False,
[6929]584        )
585
[7927]586    surcharge_2 = schema.Float(
[7881]587        title = _(u'Surcharge Payment Gateway Provider'),
[7927]588        default = 0.0,
[7881]589        required = False,
[6929]590        )
591
[7927]592    surcharge_3 = schema.Float(
[7828]593        title = _(u'Surcharge 3'),
[7927]594        default = 0.0,
[7881]595        required = False,
[6929]596        )
597
[7927]598    clearance_fee = schema.Float(
[7828]599        title = _(u'Clearance Fee'),
[7927]600        default = 0.0,
[7881]601        required = False,
[6916]602        )
603
[7927]604    booking_fee = schema.Float(
[7828]605        title = _(u'Booking Fee'),
[7927]606        default = 0.0,
[7881]607        required = False,
[6993]608        )
609
[7927]610    acceptance_fee = schema.Float(
[7828]611        title = _(u'Acceptance Fee'),
[7927]612        default = 0.0,
[7881]613        required = False,
[7250]614        )
615
[6918]616    def getSessionString():
617        """Returns the session string from the vocabulary.
618        """
619
620
[6916]621class ISessionConfigurationAdd(ISessionConfiguration):
622    """A session configuration object in add mode.
623    """
624
625    academic_session = schema.Choice(
[7828]626        title = _(u'Academic Session'),
[6916]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
[7819]636class IDataCenter(IKofaObject):
[4789]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    """
[4858]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')
[6136]658
[4789]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        """
[4858]666
667    def getLinesNumber():
668        """Get number of lines of file.
669        """
[4882]670
671class IDataCenterStorageMovedEvent(IObjectEvent):
672    """Emitted, when the storage of a datacenter changes.
673    """
[5007]674
[6136]675class IObjectUpgradeEvent(IObjectEvent):
676    """Can be fired, when an object shall be upgraded.
677    """
678
[6180]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
[5007]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.')
[6136]698
[7819]699class IKofaPluggable(Interface):
700    """A component that might be plugged into a Kofa Kofa app.
[5658]701
702    Components implementing this interface are referred to as
703    'plugins'. They are normally called when a new
[7811]704    :class:`waeup.kofa.app.University` instance is created.
[5658]705
706    Plugins can setup and update parts of the central site without the
[7811]707    site object (normally a :class:`waeup.kofa.app.University` object)
[5658]708    needing to know about that parts. The site simply collects all
709    available plugins, calls them and the plugins care for their
[5676]710    respective subarea like the applicants area or the datacenter
[5658]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.
[5013]721    """
[5069]722    def setup(site, name, logger):
723        """Create an instance of the plugin.
[5013]724
[5658]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.
[5069]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
[5658]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.
[5069]753        """
[5898]754
[5899]755class IAuthPluginUtility(Interface):
[5898]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
[7811]760    :class:`waeup.kofa.app.University` instance is created and put
[5898]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        """
[6273]777
778class IObjectConverter(Interface):
779    """Object converters are available as simple adapters, adapting
780       interfaces (not regular instances).
781
782    """
783
[6277]784    def fromStringDict(self, data_dict, context, form_fields=None):
785        """Convert values in `data_dict`.
[6273]786
[6277]787        Converts data in `data_dict` into real values based on
788        `context` and `form_fields`.
[6273]789
[6277]790        `data_dict` is a mapping (dict) from field names to values
791        represented as strings.
[6273]792
[6277]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`.
[6273]797
[6277]798        If no `form_fields` are given, a default is computed from the
799        associated interface.
[6273]800
[6277]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.
[6273]824        """
[6293]825
[7932]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
[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.