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

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

(Re-)add an interface for CSV exporters.

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