source: main/waeup.sirp/trunk/src/waeup/sirp/interfaces.py @ 7738

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

Require iterables as input to exporter. This will ease things with
exporting data of certain subareas (i.e. the departments of a certain
faculty only, etc.) and we could use catalog lookups more easily.

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