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

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

It should be clearance_fee not clearance, like in the custom package.

  • Property svn:eol-style set to native
File size: 16.6 KB
RevLine 
[3521]1##
2## interfaces.py
[6361]3import os
[6915]4from datetime import datetime
[6353]5from hurry.workflow.interfaces import IWorkflow, IWorkflowInfo
[4789]6from zc.sourcefactory.basic import BasicSourceFactory
[6147]7from zope import schema
[4789]8from zope.component import getUtility
[4882]9from zope.component.interfaces import IObjectEvent
[5955]10from zope.interface import Interface, Attribute, implements
[4789]11from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
[3521]12
[6990]13CREATED = 'created'
14ADMITTED = 'admitted'
15CLEARANCE = 'clearance started'
16REQUESTED = 'clearance requested'
17CLEARED = 'cleared'
18PAID = 'school fee paid'
19RETURNING = 'returning'
20REGISTERED = 'courses registered'
21VALIDATED = 'courses validated'
22
[6361]23default_frontpage = u'' + open(os.path.join(
24        os.path.dirname(__file__), 'frontpage.rst'), 'rb').read()
25
[6915]26def SimpleWAeUPVocabulary(*terms):
27    """A well-buildt vocabulary provides terms with a value, token and
28       title for each term
29    """
30    return SimpleVocabulary([
31            SimpleTerm(value, value, title) for title, value in terms])
32
33def year_range():
34    curr_year = datetime.now().year
35    return range(curr_year - 2, curr_year + 5)
36
37def academic_sessions():
38    curr_year = datetime.now().year
39    year_range = range(curr_year - 10, curr_year + 2)
40    return [('%s/%s' % (year,year+1), year) for year in year_range]
41
42academic_sessions_vocab = SimpleWAeUPVocabulary(*academic_sessions())
43
[6990]44registration_states_vocab = SimpleWAeUPVocabulary(
45    ('created', CREATED),
46    ('admitted', ADMITTED),
47    ('clearance started', CLEARANCE),
48    ('clearance requested', REQUESTED),
49    ('cleared', CLEARED),
50    ('school fee paid', PAID),
51    ('returning', RETURNING),
52    ('courses registered', REGISTERED),
53    ('courses validated', VALIDATED),
54    )
55
[4858]56class FatalCSVError(Exception):
57    """Some row could not be processed.
58    """
59    pass
60
[6226]61class DuplicationError(Exception):
62    """An exception that can be raised when duplicates are found.
63
64    When raising :exc:`DuplicationError` you can, beside the usual
65    message, specify a list of objects which are duplicates. These
66    values can be used by catching code to print something helpful or
67    similar.
68    """
69    def __init__(self, msg, entries=[]):
70        self.msg = msg
71        self.entries = entries
72
73    def __str__(self):
74        return '%r' % self.msg
75
[6143]76class RoleSource(BasicSourceFactory):
[6508]77    """A source for global roles.
78    """
[6143]79    def getValues(self):
[6157]80        # late import: in interfaces we should not import local modules
81        from waeup.sirp.permissions import getWAeUPRoleNames
82        return getWAeUPRoleNames()
83
84    def getTitle(self, value):
85        # late import: in interfaces we should not import local modules
[6143]86        from waeup.sirp.permissions import getRoles
[6157]87        roles = dict(getRoles())
88        if value in roles.keys():
89            title = roles[value].title
[6569]90            if '.' in title:
91                title = title.split('.', 2)[1]
[6157]92        return title
[6143]93
[4789]94class IWAeUPObject(Interface):
95    """A WAeUP object.
[5663]96
97    This is merely a marker interface.
[4789]98    """
99
100class IUniversity(IWAeUPObject):
[3521]101    """Representation of a university.
102    """
[5955]103
[6065]104
[4789]105class IWAeUPContainer(IWAeUPObject):
106    """A container for WAeUP objects.
107    """
108
109class IWAeUPContained(IWAeUPObject):
110    """An item contained in an IWAeUPContainer.
111    """
[6136]112
[4789]113class IWAeUPExporter(Interface):
114    """An exporter for objects.
115    """
116    def export(obj, filepath=None):
117        """Export by pickling.
118
119        Returns a file-like object containing a representation of `obj`.
120
121        This is done using `pickle`. If `filepath` is ``None``, a
122        `cStringIO` object is returned, that contains the saved data.
123        """
124
125class IWAeUPXMLExporter(Interface):
126    """An XML exporter for objects.
127    """
128    def export(obj, filepath=None):
129        """Export as XML.
130
131        Returns an XML representation of `obj`.
132
133        If `filepath` is ``None``, a StringIO` object is returned,
134        that contains the transformed data.
135        """
136
137class IWAeUPXMLImporter(Interface):
138    """An XML import for objects.
139    """
140    def doImport(filepath):
141        """Create Python object from XML.
142
143        Returns a Python object.
144        """
145
[4858]146class IBatchProcessor(Interface):
147    """A batch processor that handles mass-operations.
148    """
149    name = schema.TextLine(
150        title = u'Importer name'
151        )
152
153    mode = schema.Choice(
154        title = u'Import mode',
155        values = ['create', 'update', 'remove']
156        )
[6136]157
[5476]158    def doImport(path, headerfields, mode='create', user='Unknown',
159                 logger=None):
[4858]160        """Read data from ``path`` and update connected object.
[5476]161
162        `headerfields` is a list of headerfields as read from the file
163        to import.
164
165        `mode` gives the import mode to use (``'create'``,
166        ``'update'``, or ``'remove'``.
167
168        `user` is a string describing the user performing the
169        import. Normally fetched from current principal.
170
171        `logger` is the logger to use during import.
[4858]172        """
173
[4789]174class IUserAccount(IWAeUPObject):
175    """A user account.
176    """
177    name = schema.TextLine(
178        title = u'User ID',
[6512]179        description = u'Login name of user',
[4789]180        required = True,)
181    title = schema.TextLine(
[6512]182        title = u'Name',
183        description = u'Real name of user',
[4789]184        required = False,)
185    description = schema.TextLine(
[6512]186        title = u'Description',
[4789]187        required = False,)
188    password = schema.Password(
189        title = u'Password',
190        required = True,)
191    roles = schema.List(
[6508]192        title = u'Global roles',
[4789]193        value_type = schema.Choice(source=RoleSource()))
[6136]194
195
[4789]196class IUserContainer(IWAeUPObject):
197    """A container for users (principals).
198
199    These users are used for authentication purposes.
200    """
201
202    def addUser(name, password, title=None, description=None):
203        """Add a user.
204        """
205
206    def delUser(name):
207        """Delete a user if it exists.
208        """
209
[6141]210class ILocalRolesAssignable(Interface):
211    """The local roles assignable to an object.
212    """
213    def __call__():
214        """Returns a list of dicts.
215
216        Each dict contains a ``name`` referring to the role assignable
217        for the specified object and a `title` to describe the range
218        of users to which this role can be assigned.
219        """
220
[6907]221class IConfigurationContainer(IWAeUPObject):
222    """A container for session configuration objects.
223    """
224
225    name = schema.TextLine(
226        title = u'Name of University',
227        default = u'Sample University',
228        required = True,
229        )
230
231    title = schema.TextLine(
[6990]232        title = u'Title of Frontpage',
[6907]233        default = u'Welcome to the Student Information and Registration ' +
234                  u'Portal of Sample University',
235        required = False,
236        )
237
238    skin = schema.Choice(
239        title = u'Skin',
240        default = u'gray waeup theme',
241        vocabulary = 'waeup.sirp.browser.theming.ThemesVocabulary',
242        required = True,
243        )
244
245    frontpage = schema.Text(
246        title = u'Content in reST format',
247        required = False,
248        default = default_frontpage,
249        )
250
[6990]251    accommodation_session = schema.Choice(
252        title = u'Accommodation Booking Session',
253        source = academic_sessions_vocab,
254        default = datetime.now().year,
255        required = False,
256        readonly = False,
257        )
258
259    accommodation_states = schema.List(
260        title = u'Allowed States for Accommodation Booking',
261        value_type = schema.Choice(
262            vocabulary = registration_states_vocab,
263            ),
264        default = [],
265        )
266
[6907]267class ISessionConfiguration(IWAeUPObject):
[6915]268    """A session configuration object.
[6907]269    """
270
[6915]271    academic_session = schema.Choice(
272        title = u'Academic Session',
273        source = academic_sessions_vocab,
274        default = None,
275        required = True,
276        readonly = True,
277        )
278
[7021]279    school_fee_base = schema.Int(
[6915]280        title = u'School Fee',
281        default = 0,
282        )
283
[6929]284    surcharge_1 = schema.Int(
285        title = u'Surcharge 1',
286        default = 0,
287        )
288
289    surcharge_2 = schema.Int(
290        title = u'Surcharge 2',
291        default = 0,
292        )
293
294    surcharge_3 = schema.Int(
295        title = u'Surcharge 3',
296        default = 0,
297        )
298
[7022]299    clearance_fee = schema.Int(
[6929]300        title = u'Clearance Fee',
[6916]301        default = 0,
302        )
303
[6993]304    booking_fee = schema.Int(
305        title = u'Booking Fee',
306        default = 0,
307        )
308
[6918]309    def getSessionString():
310        """Returns the session string from the vocabulary.
311        """
312
313
[6916]314class ISessionConfigurationAdd(ISessionConfiguration):
315    """A session configuration object in add mode.
316    """
317
318    academic_session = schema.Choice(
319        title = u'Academic Session',
320        source = academic_sessions_vocab,
321        default = None,
322        required = True,
323        readonly = False,
324        )
325
326ISessionConfigurationAdd['academic_session'].order =  ISessionConfiguration[
327    'academic_session'].order
328
[4789]329class IDataCenter(IWAeUPObject):
330    """A data center.
331
332    TODO : declare methods, at least those needed by pages.
333    """
334    pass
335
336class IDataCenterFile(Interface):
337    """A data center file.
338    """
[4858]339
340    name = schema.TextLine(
341        title = u'Filename')
342
343    size = schema.TextLine(
344        title = u'Human readable file size')
345
346    uploaddate = schema.TextLine(
347        title = u'Human readable upload datetime')
348
349    lines = schema.Int(
350        title = u'Number of lines in file')
[6136]351
[4789]352    def getDate():
353        """Get creation timestamp from file in human readable form.
354        """
355
356    def getSize():
357        """Get human readable size of file.
358        """
[4858]359
360    def getLinesNumber():
361        """Get number of lines of file.
362        """
[4882]363
364class IDataCenterStorageMovedEvent(IObjectEvent):
365    """Emitted, when the storage of a datacenter changes.
366    """
[5007]367
[6136]368class IObjectUpgradeEvent(IObjectEvent):
369    """Can be fired, when an object shall be upgraded.
370    """
371
[6180]372class ILocalRoleSetEvent(IObjectEvent):
373    """A local role was granted/revoked for a principal on an object.
374    """
375    role_id = Attribute(
376        "The role id that was set.")
377    principal_id = Attribute(
378        "The principal id for which the role was granted/revoked.")
379    granted = Attribute(
380        "Boolean. If false, then the role was revoked.")
381
[5007]382class IQueryResultItem(Interface):
383    """An item in a search result.
384    """
385    url = schema.TextLine(
386        title = u'URL that links to the found item')
387    title = schema.TextLine(
388        title = u'Title displayed in search results.')
389    description = schema.Text(
390        title = u'Longer description of the item found.')
[6136]391
[5013]392class IWAeUPSIRPPluggable(Interface):
393    """A component that might be plugged into a WAeUP SIRP app.
[5658]394
395    Components implementing this interface are referred to as
396    'plugins'. They are normally called when a new
397    :class:`waeup.sirp.app.University` instance is created.
398
399    Plugins can setup and update parts of the central site without the
400    site object (normally a :class:`waeup.sirp.app.University` object)
401    needing to know about that parts. The site simply collects all
402    available plugins, calls them and the plugins care for their
[5676]403    respective subarea like the applicants area or the datacenter
[5658]404    area.
405
406    Currently we have no mechanism to define an order of plugins. A
407    plugin should therefore make no assumptions about the state of the
408    site or other plugins being run before and instead do appropriate
409    checks if necessary.
410
411    Updates can be triggered for instance by the respective form in
412    the site configuration. You normally do updates when the
413    underlying software changed.
[5013]414    """
[5069]415    def setup(site, name, logger):
416        """Create an instance of the plugin.
[5013]417
[5658]418        The method is meant to be called by the central app (site)
419        when it is created.
420
421        `site`:
422           The site that requests a setup.
423
424        `name`:
425           The name under which the plugin was registered (utility name).
426
427        `logger`:
428           A standard Python logger for the plugins use.
[5069]429        """
430
431    def update(site, name, logger):
432        """Method to update an already existing plugin.
433
434        This might be called by a site when something serious
[5658]435        changes. It is a poor-man replacement for Zope generations
436        (but probably more comprehensive and better understandable).
437
438        `site`:
439           The site that requests an update.
440
441        `name`:
442           The name under which the plugin was registered (utility name).
443
444        `logger`:
445           A standard Python logger for the plugins use.
[5069]446        """
[5898]447
[5899]448class IAuthPluginUtility(Interface):
[5898]449    """A component that cares for authentication setup at site creation.
450
451    Utilities providing this interface are looked up when a Pluggable
452    Authentication Utility (PAU) for any
453    :class:`waeup.sirp.app.University` instance is created and put
454    into ZODB.
455
456    The setup-code then calls the `register` method of the utility and
457    expects a modified (or unmodified) version of the PAU back.
458
459    This allows to define any authentication setup modifications by
460    submodules or third-party modules/packages.
461    """
462
463    def register(pau):
464        """Register any plugins wanted to be in the PAU.
465        """
466
467    def unregister(pau):
468        """Unregister any plugins not wanted to be in the PAU.
469        """
[6273]470
471class IObjectConverter(Interface):
472    """Object converters are available as simple adapters, adapting
473       interfaces (not regular instances).
474
475    """
476
[6277]477    def fromStringDict(self, data_dict, context, form_fields=None):
478        """Convert values in `data_dict`.
[6273]479
[6277]480        Converts data in `data_dict` into real values based on
481        `context` and `form_fields`.
[6273]482
[6277]483        `data_dict` is a mapping (dict) from field names to values
484        represented as strings.
[6273]485
[6277]486        The fields (keys) to convert can be given in optional
487        `form_fields`. If given, form_fields should be an instance of
488        :class:`zope.formlib.form.Fields`. Suitable instances are for
489        example created by :class:`grok.AutoFields`.
[6273]490
[6277]491        If no `form_fields` are given, a default is computed from the
492        associated interface.
[6273]493
[6277]494        The `context` can be an existing object (implementing the
495        associated interface) or a factory name. If it is a string, we
496        try to create an object using
497        :func:`zope.component.createObject`.
498
499        Returns a tuple ``(<FIELD_ERRORS>, <INVARIANT_ERRORS>,
500        <DATA_DICT>)`` where
501
502        ``<FIELD_ERRORS>``
503           is a list of tuples ``(<FIELD_NAME>, <ERROR>)`` for each
504           error that happened when validating the input data in
505           `data_dict`
506
507        ``<INVARIANT_ERRORS>``
508           is a list of invariant errors concerning several fields
509
510        ``<DATA_DICT>``
511           is a dict with the values from input dict converted.
512
513        If errors happen, i.e. the error lists are not empty, always
514        an empty ``<DATA_DICT>`` is returned.
515
516        If ``<DATA_DICT>` is non-empty, there were no errors.
[6273]517        """
[6293]518
[6338]519class IObjectHistory(Interface):
520
521    messages = schema.List(
522        title = u'List of messages stored',
523        required = True,
524        )
525
526    def addMessage(message):
527        """Add a message.
528        """
[6353]529
530class IWAeUPWorkflowInfo(IWorkflowInfo):
531    """A :class:`hurry.workflow.workflow.WorkflowInfo` with additional
532       methods for convenience.
533    """
534    def getManualTransitions():
535        """Get allowed manual transitions.
536
537        Get a sorted list of tuples containing the `transition_id` and
538        `title` of each allowed transition.
539        """
[6481]540
541class ISiteLoggers(Interface):
542
543    loggers = Attribute("A list or generator of registered WAeUPLoggers")
544
545    def register(name, filename=None, site=None, **options):
546        """Register a logger `name` which logs to `filename`.
547
548        If `filename` is not given, logfile will be `name` with
549        ``.log`` as filename extension.
550        """
551
552    def unregister(name):
553        """Unregister a once registered logger.
554        """
555
556class ILogger(Interface):
557    """A logger cares for setup, update and restarting of a Python logger.
558    """
559
560    logger = Attribute("""A :class:`logging.Logger` instance""")
561
562
563    def __init__(name, filename=None, site=None, **options):
564        """Create a WAeUP logger instance.
565        """
566
567    def setup():
568        """Create a Python :class:`logging.Logger` instance.
569
570        The created logger is based on the params given by constructor.
571        """
572
573    def update(**options):
574        """Update the logger.
575
576        Updates the logger respecting modified `options` and changed
577        paths.
578        """
[6754]579
580class ILoggerCollector(Interface):
581
582    def getLoggers(site):
583        """Return all loggers registered for `site`.
584        """
585
586    def registerLogger(site, logging_component):
587        """Register a logging component residing in `site`.
588        """
589
590    def unregisterLogger(site, logging_component):
591        """Unregister a logger.
592        """
Note: See TracBrowser for help on using the repository browser.