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

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

Set fallback and default frontpages if frontpage attribute is an empty string.

Remove title attribute from University objects. The titke should be part of the frontpage ReST.

Tests will follow.

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