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

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

Separate subjects and grades with a colon.

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