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

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

Extend ISessionConfiguration and fix utils.py.

  • Property svn:eol-style set to native
File size: 16.7 KB
Line 
1##
2## interfaces.py
3import os
4from datetime import datetime
5from hurry.workflow.interfaces import IWorkflow, IWorkflowInfo
6from zc.sourcefactory.basic import BasicSourceFactory
7from zope import schema
8from zope.component import getUtility
9from zope.component.interfaces import IObjectEvent
10from zope.interface import Interface, Attribute, implements
11from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
12
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
23default_frontpage = u'' + open(os.path.join(
24        os.path.dirname(__file__), 'frontpage.rst'), 'rb').read()
25
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
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
56class FatalCSVError(Exception):
57    """Some row could not be processed.
58    """
59    pass
60
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
76class RoleSource(BasicSourceFactory):
77    """A source for global roles.
78    """
79    def getValues(self):
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
86        from waeup.sirp.permissions import getRoles
87        roles = dict(getRoles())
88        if value in roles.keys():
89            title = roles[value].title
90            if '.' in title:
91                title = title.split('.', 2)[1]
92        return title
93
94class IWAeUPObject(Interface):
95    """A WAeUP object.
96
97    This is merely a marker interface.
98    """
99
100class IUniversity(IWAeUPObject):
101    """Representation of a university.
102    """
103
104
105class IWAeUPContainer(IWAeUPObject):
106    """A container for WAeUP objects.
107    """
108
109class IWAeUPContained(IWAeUPObject):
110    """An item contained in an IWAeUPContainer.
111    """
112
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
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        )
157
158    def doImport(path, headerfields, mode='create', user='Unknown',
159                 logger=None):
160        """Read data from ``path`` and update connected object.
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.
172        """
173
174class IUserAccount(IWAeUPObject):
175    """A user account.
176    """
177    name = schema.TextLine(
178        title = u'User ID',
179        description = u'Login name of user',
180        required = True,)
181    title = schema.TextLine(
182        title = u'Name',
183        description = u'Real name of user',
184        required = False,)
185    description = schema.TextLine(
186        title = u'Description',
187        required = False,)
188    password = schema.Password(
189        title = u'Password',
190        required = True,)
191    roles = schema.List(
192        title = u'Global roles',
193        value_type = schema.Choice(source=RoleSource()))
194
195
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
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
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(
232        title = u'Title of Frontpage',
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
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
267class ISessionConfiguration(IWAeUPObject):
268    """A session configuration object.
269    """
270
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
279    fee_1 = schema.Int(
280        title = u'School Fee',
281        default = 0,
282        )
283
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
299    fee_2 = schema.Int(
300        title = u'Clearance Fee',
301        default = 0,
302        )
303
304    booking_fee = schema.Int(
305        title = u'Booking Fee',
306        default = 0,
307        )
308
309    maint_fee = schema.Int(
310        title = u'Maintenance Fee',
311        default = 0,
312        )
313
314    def getSessionString():
315        """Returns the session string from the vocabulary.
316        """
317
318
319class ISessionConfigurationAdd(ISessionConfiguration):
320    """A session configuration object in add mode.
321    """
322
323    academic_session = schema.Choice(
324        title = u'Academic Session',
325        source = academic_sessions_vocab,
326        default = None,
327        required = True,
328        readonly = False,
329        )
330
331ISessionConfigurationAdd['academic_session'].order =  ISessionConfiguration[
332    'academic_session'].order
333
334class IDataCenter(IWAeUPObject):
335    """A data center.
336
337    TODO : declare methods, at least those needed by pages.
338    """
339    pass
340
341class IDataCenterFile(Interface):
342    """A data center file.
343    """
344
345    name = schema.TextLine(
346        title = u'Filename')
347
348    size = schema.TextLine(
349        title = u'Human readable file size')
350
351    uploaddate = schema.TextLine(
352        title = u'Human readable upload datetime')
353
354    lines = schema.Int(
355        title = u'Number of lines in file')
356
357    def getDate():
358        """Get creation timestamp from file in human readable form.
359        """
360
361    def getSize():
362        """Get human readable size of file.
363        """
364
365    def getLinesNumber():
366        """Get number of lines of file.
367        """
368
369class IDataCenterStorageMovedEvent(IObjectEvent):
370    """Emitted, when the storage of a datacenter changes.
371    """
372
373class IObjectUpgradeEvent(IObjectEvent):
374    """Can be fired, when an object shall be upgraded.
375    """
376
377class ILocalRoleSetEvent(IObjectEvent):
378    """A local role was granted/revoked for a principal on an object.
379    """
380    role_id = Attribute(
381        "The role id that was set.")
382    principal_id = Attribute(
383        "The principal id for which the role was granted/revoked.")
384    granted = Attribute(
385        "Boolean. If false, then the role was revoked.")
386
387class IQueryResultItem(Interface):
388    """An item in a search result.
389    """
390    url = schema.TextLine(
391        title = u'URL that links to the found item')
392    title = schema.TextLine(
393        title = u'Title displayed in search results.')
394    description = schema.Text(
395        title = u'Longer description of the item found.')
396
397class IWAeUPSIRPPluggable(Interface):
398    """A component that might be plugged into a WAeUP SIRP app.
399
400    Components implementing this interface are referred to as
401    'plugins'. They are normally called when a new
402    :class:`waeup.sirp.app.University` instance is created.
403
404    Plugins can setup and update parts of the central site without the
405    site object (normally a :class:`waeup.sirp.app.University` object)
406    needing to know about that parts. The site simply collects all
407    available plugins, calls them and the plugins care for their
408    respective subarea like the applicants area or the datacenter
409    area.
410
411    Currently we have no mechanism to define an order of plugins. A
412    plugin should therefore make no assumptions about the state of the
413    site or other plugins being run before and instead do appropriate
414    checks if necessary.
415
416    Updates can be triggered for instance by the respective form in
417    the site configuration. You normally do updates when the
418    underlying software changed.
419    """
420    def setup(site, name, logger):
421        """Create an instance of the plugin.
422
423        The method is meant to be called by the central app (site)
424        when it is created.
425
426        `site`:
427           The site that requests a setup.
428
429        `name`:
430           The name under which the plugin was registered (utility name).
431
432        `logger`:
433           A standard Python logger for the plugins use.
434        """
435
436    def update(site, name, logger):
437        """Method to update an already existing plugin.
438
439        This might be called by a site when something serious
440        changes. It is a poor-man replacement for Zope generations
441        (but probably more comprehensive and better understandable).
442
443        `site`:
444           The site that requests an update.
445
446        `name`:
447           The name under which the plugin was registered (utility name).
448
449        `logger`:
450           A standard Python logger for the plugins use.
451        """
452
453class IAuthPluginUtility(Interface):
454    """A component that cares for authentication setup at site creation.
455
456    Utilities providing this interface are looked up when a Pluggable
457    Authentication Utility (PAU) for any
458    :class:`waeup.sirp.app.University` instance is created and put
459    into ZODB.
460
461    The setup-code then calls the `register` method of the utility and
462    expects a modified (or unmodified) version of the PAU back.
463
464    This allows to define any authentication setup modifications by
465    submodules or third-party modules/packages.
466    """
467
468    def register(pau):
469        """Register any plugins wanted to be in the PAU.
470        """
471
472    def unregister(pau):
473        """Unregister any plugins not wanted to be in the PAU.
474        """
475
476class IObjectConverter(Interface):
477    """Object converters are available as simple adapters, adapting
478       interfaces (not regular instances).
479
480    """
481
482    def fromStringDict(self, data_dict, context, form_fields=None):
483        """Convert values in `data_dict`.
484
485        Converts data in `data_dict` into real values based on
486        `context` and `form_fields`.
487
488        `data_dict` is a mapping (dict) from field names to values
489        represented as strings.
490
491        The fields (keys) to convert can be given in optional
492        `form_fields`. If given, form_fields should be an instance of
493        :class:`zope.formlib.form.Fields`. Suitable instances are for
494        example created by :class:`grok.AutoFields`.
495
496        If no `form_fields` are given, a default is computed from the
497        associated interface.
498
499        The `context` can be an existing object (implementing the
500        associated interface) or a factory name. If it is a string, we
501        try to create an object using
502        :func:`zope.component.createObject`.
503
504        Returns a tuple ``(<FIELD_ERRORS>, <INVARIANT_ERRORS>,
505        <DATA_DICT>)`` where
506
507        ``<FIELD_ERRORS>``
508           is a list of tuples ``(<FIELD_NAME>, <ERROR>)`` for each
509           error that happened when validating the input data in
510           `data_dict`
511
512        ``<INVARIANT_ERRORS>``
513           is a list of invariant errors concerning several fields
514
515        ``<DATA_DICT>``
516           is a dict with the values from input dict converted.
517
518        If errors happen, i.e. the error lists are not empty, always
519        an empty ``<DATA_DICT>`` is returned.
520
521        If ``<DATA_DICT>` is non-empty, there were no errors.
522        """
523
524class IObjectHistory(Interface):
525
526    messages = schema.List(
527        title = u'List of messages stored',
528        required = True,
529        )
530
531    def addMessage(message):
532        """Add a message.
533        """
534
535class IWAeUPWorkflowInfo(IWorkflowInfo):
536    """A :class:`hurry.workflow.workflow.WorkflowInfo` with additional
537       methods for convenience.
538    """
539    def getManualTransitions():
540        """Get allowed manual transitions.
541
542        Get a sorted list of tuples containing the `transition_id` and
543        `title` of each allowed transition.
544        """
545
546class ISiteLoggers(Interface):
547
548    loggers = Attribute("A list or generator of registered WAeUPLoggers")
549
550    def register(name, filename=None, site=None, **options):
551        """Register a logger `name` which logs to `filename`.
552
553        If `filename` is not given, logfile will be `name` with
554        ``.log`` as filename extension.
555        """
556
557    def unregister(name):
558        """Unregister a once registered logger.
559        """
560
561class ILogger(Interface):
562    """A logger cares for setup, update and restarting of a Python logger.
563    """
564
565    logger = Attribute("""A :class:`logging.Logger` instance""")
566
567
568    def __init__(name, filename=None, site=None, **options):
569        """Create a WAeUP logger instance.
570        """
571
572    def setup():
573        """Create a Python :class:`logging.Logger` instance.
574
575        The created logger is based on the params given by constructor.
576        """
577
578    def update(**options):
579        """Update the logger.
580
581        Updates the logger respecting modified `options` and changed
582        paths.
583        """
584
585class ILoggerCollector(Interface):
586
587    def getLoggers(site):
588        """Return all loggers registered for `site`.
589        """
590
591    def registerLogger(site, logging_component):
592        """Register a logging component residing in `site`.
593        """
594
595    def unregisterLogger(site, logging_component):
596        """Unregister a logger.
597        """
Note: See TracBrowser for help on using the repository browser.