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

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

Move MessageFactory? definition to w.s.interfaces to avoid conflicting imports.

Start translation of workflow (for demonstration).

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