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

Last change on this file since 7727 was 7726, checked in by uli, 13 years ago

(Re-)add an interface for CSV exporters.

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