source: main/waeup.sirp/branches/ulif-schoolgrades/src/waeup/sirp/interfaces.py @ 7781

Last change on this file since 7781 was 7773, checked in by uli, 13 years ago

Move IResultEntry to central interfaces modules.

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