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

Last change on this file since 5955 was 5955, checked in by uli, 14 years ago

Add a source for themes (aka skins) and show how to make use of the
ZCA to make things extendible in third-party packages.

This is the first step in an effort to provide clean and extendible
themes with waeup.sirp.

'clean' means: it was not clean yet to hardcode CSS file names (which
should be business of the browser subpackage) in the central
interfaces definitions file waeup.sirp.interfaces.

It was also not too clean, that we

It was also impossible for extension packages to define new own themes
yet or extend existing themes by adding some CSS file.

'extendible' means: with the new theme-source and theme-provider we
define clearly, what interface we expect from another package (for
instance the browser subpackage or any third-party package) to
retrieve a list of available themes at all. This list is then used by
the manage-view of University instances to provide a list of themes to
select for all pages.

The browser subpackage will also provide a theme-provider that looks
up all themes defined somewhere (in waeup.sirp _and_ other packags) at
runtime.

  • Property svn:eol-style set to native
File size: 11.2 KB
Line 
1##
2## interfaces.py
3from zc.sourcefactory.basic import BasicSourceFactory
4from zope.component import getUtility
5from zope.component.interfaces import IObjectEvent
6try:
7    from zope.catalog.interfaces import ICatalog
8except ImportError:
9    # BBB
10    from zope.app.catalog.interfaces import ICatalog
11from zope.interface import Interface, Attribute, implements
12from zope import schema
13from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
14from waeup.sirp.permissions import RoleSource
15
16class IThemeProvider(Interface):
17    """A component that delivers all themes defined.
18
19    We normally do not deal with browser-related stuff in `waeup.sirp`
20    but leave that to the `browser` subpackage. With themes (aka
21    skins) we cannot follow that path because we need a theme as an
22    attribute of each `University` instance.
23
24    Therefore we must tell the browser subpackage how we expect themes
25    to be announced code-wise.
26
27    What we tell here is that we might ask for a utility providing
28    IThemeProvider and that this component then should be callable to
29    give us a list of themes and their respective internal names.
30    """
31    def __call__():
32        """Get a list of all themes available.
33
34        Returns a list of ``(<NAME>, <THEME>)`` tuples where
35        ``<NAME>`` is the internal name under which a theme was
36        registered and ``<THEME>`` is the real theme.
37        """
38
39class ThemeSource(BasicSourceFactory):
40    """A source for themes.
41    """
42    def getValues(self):
43        """Get names of themes.
44        """
45        theme_provider = getUtility(IThemeProvider, name="default")
46        return [x for x, y in theme_provider()]
47   
48    def getTitle(self, value):
49        """Get a user-presentable description for a theme.
50        """
51        theme_provider = getUtility(IThemeProvider, name="default")
52        for name, theme in theme_provider():
53            if name == value:
54                return theme.description
55        return u'unnamed'
56
57class ThemeSourceBinder(object):
58    """A source binder for the `ThemeSource`.
59
60    Normally, we can pass instances of a source (like `ThemeSource`)
61    directly to fields in interfaces (writing something like ``source
62    = ThemeSource()``. With `ThemeSource` we cannot do this, because
63    the set of available themes is not available before the whole
64    `waeup.sirp` package was grokked (and parsed).
65
66    We bypass that problem by defining this trivial source-binder,
67    which is asked for themes only when the values of the source are
68    really needed and after the process of grokking and parsing
69    everything on startup.
70
71    So, although this binder binds to some context (`IUniversity` is
72    currently the only interface making use of this source, so
73    `University` instances are the only context used), the context
74    does not really matter.
75    """
76    implements(schema.interfaces.IContextSourceBinder)
77
78    def __call__(self, context):
79        return ThemeSource()
80
81class FatalCSVError(Exception):
82    """Some row could not be processed.
83    """
84    pass
85
86def SimpleWAeUPVocabulary(*terms):
87    """A well-buildt vocabulary provides terms with a value, token and
88       title for each term
89    """
90    return SimpleVocabulary([
91            SimpleTerm(value, value, title) for title, value in terms])
92
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    name = schema.TextLine(
104        title = u'Name of University',
105        default = u'Unnamed',
106        required = True,
107        )
108
109       
110    skin = schema.Choice(
111        title = u'Skin',
112        default = u'waeuptheme-gray1.css',
113        source = ThemeSourceBinder(),
114        required = True,
115        )
116
117    faculties = Attribute("A container for faculties.")
118    students = Attribute("A container for students.")
119    hostels = Attribute("A container for hostels.")
120   
121class IWAeUPContainer(IWAeUPObject):
122    """A container for WAeUP objects.
123    """
124
125class IWAeUPContained(IWAeUPObject):
126    """An item contained in an IWAeUPContainer.
127    """
128   
129class IStudentContainer(IWAeUPContainer):
130    """A container for StudentObjects.
131    """
132
133
134class IHostelContainer(IWAeUPContainer):
135    """A container for hostels.
136    """
137    def addHostel(hostel):
138        """Add an IHostel object.
139
140        Returns the key, under which the object was stored.
141        """
142
143class IHostel(IWAeUPObject):
144    """Representation of a hostel.
145    """
146    name = schema.TextLine(
147        title = u'Name of Hostel',
148        default = u'Nobody',
149        required = True,
150        )
151
152       
153class IWAeUPExporter(Interface):
154    """An exporter for objects.
155    """
156    def export(obj, filepath=None):
157        """Export by pickling.
158
159        Returns a file-like object containing a representation of `obj`.
160
161        This is done using `pickle`. If `filepath` is ``None``, a
162        `cStringIO` object is returned, that contains the saved data.
163        """
164
165class IWAeUPXMLExporter(Interface):
166    """An XML exporter for objects.
167    """
168    def export(obj, filepath=None):
169        """Export as XML.
170
171        Returns an XML representation of `obj`.
172
173        If `filepath` is ``None``, a StringIO` object is returned,
174        that contains the transformed data.
175        """
176
177class IWAeUPXMLImporter(Interface):
178    """An XML import for objects.
179    """
180    def doImport(filepath):
181        """Create Python object from XML.
182
183        Returns a Python object.
184        """
185
186class IBatchProcessor(Interface):
187    """A batch processor that handles mass-operations.
188    """
189    name = schema.TextLine(
190        title = u'Importer name'
191        )
192
193    mode = schema.Choice(
194        title = u'Import mode',
195        values = ['create', 'update', 'remove']
196        )
197   
198    def doImport(path, headerfields, mode='create', user='Unknown',
199                 logger=None):
200        """Read data from ``path`` and update connected object.
201
202        `headerfields` is a list of headerfields as read from the file
203        to import.
204
205        `mode` gives the import mode to use (``'create'``,
206        ``'update'``, or ``'remove'``.
207
208        `user` is a string describing the user performing the
209        import. Normally fetched from current principal.
210
211        `logger` is the logger to use during import.
212        """
213
214class ISchemaTypeConverter(Interface):
215    """A converter for zope.schema.types.
216    """
217    def convert(string):
218        """Convert string to certain schema type.
219        """
220
221   
222class IUserAccount(IWAeUPObject):
223    """A user account.
224    """
225    name = schema.TextLine(
226        title = u'User ID',
227        description = u'Loginname',
228        required = True,)
229    title = schema.TextLine(
230        title = u'Username',
231        description = u'Real name',
232        required = False,)
233    description = schema.TextLine(
234        title = u'User description',
235        required = False,)
236    password = schema.Password(
237        title = u'Password',
238        required = True,)
239    roles = schema.List(
240        title = u'Roles',
241        value_type = schema.Choice(source=RoleSource()))
242   
243   
244class IUserContainer(IWAeUPObject):
245    """A container for users (principals).
246
247    These users are used for authentication purposes.
248    """
249
250    def addUser(name, password, title=None, description=None):
251        """Add a user.
252        """
253
254    def delUser(name):
255        """Delete a user if it exists.
256        """
257
258class IDataCenter(IWAeUPObject):
259    """A data center.
260
261    TODO : declare methods, at least those needed by pages.
262    """
263    pass
264
265class IDataCenterFile(Interface):
266    """A data center file.
267    """
268
269    name = schema.TextLine(
270        title = u'Filename')
271
272    size = schema.TextLine(
273        title = u'Human readable file size')
274
275    uploaddate = schema.TextLine(
276        title = u'Human readable upload datetime')
277
278    lines = schema.Int(
279        title = u'Number of lines in file')
280       
281    def getDate():
282        """Get creation timestamp from file in human readable form.
283        """
284
285    def getSize():
286        """Get human readable size of file.
287        """
288
289    def getLinesNumber():
290        """Get number of lines of file.
291        """
292
293class IDataCenterStorageMovedEvent(IObjectEvent):
294    """Emitted, when the storage of a datacenter changes.
295    """
296
297class IQueryResultItem(Interface):
298    """An item in a search result.
299    """
300    url = schema.TextLine(
301        title = u'URL that links to the found item')
302    title = schema.TextLine(
303        title = u'Title displayed in search results.')
304    description = schema.Text(
305        title = u'Longer description of the item found.')
306     
307class IWAeUPSIRPPluggable(Interface):
308    """A component that might be plugged into a WAeUP SIRP app.
309
310    Components implementing this interface are referred to as
311    'plugins'. They are normally called when a new
312    :class:`waeup.sirp.app.University` instance is created.
313
314    Plugins can setup and update parts of the central site without the
315    site object (normally a :class:`waeup.sirp.app.University` object)
316    needing to know about that parts. The site simply collects all
317    available plugins, calls them and the plugins care for their
318    respective subarea like the applicants area or the datacenter
319    area.
320
321    Currently we have no mechanism to define an order of plugins. A
322    plugin should therefore make no assumptions about the state of the
323    site or other plugins being run before and instead do appropriate
324    checks if necessary.
325
326    Updates can be triggered for instance by the respective form in
327    the site configuration. You normally do updates when the
328    underlying software changed.
329    """
330    def setup(site, name, logger):
331        """Create an instance of the plugin.
332
333        The method is meant to be called by the central app (site)
334        when it is created.
335
336        `site`:
337           The site that requests a setup.
338
339        `name`:
340           The name under which the plugin was registered (utility name).
341
342        `logger`:
343           A standard Python logger for the plugins use.
344        """
345
346    def update(site, name, logger):
347        """Method to update an already existing plugin.
348
349        This might be called by a site when something serious
350        changes. It is a poor-man replacement for Zope generations
351        (but probably more comprehensive and better understandable).
352
353        `site`:
354           The site that requests an update.
355
356        `name`:
357           The name under which the plugin was registered (utility name).
358
359        `logger`:
360           A standard Python logger for the plugins use.
361        """
362
363class IAuthPluginUtility(Interface):
364    """A component that cares for authentication setup at site creation.
365
366    Utilities providing this interface are looked up when a Pluggable
367    Authentication Utility (PAU) for any
368    :class:`waeup.sirp.app.University` instance is created and put
369    into ZODB.
370
371    The setup-code then calls the `register` method of the utility and
372    expects a modified (or unmodified) version of the PAU back.
373
374    This allows to define any authentication setup modifications by
375    submodules or third-party modules/packages.
376    """
377
378    def register(pau):
379        """Register any plugins wanted to be in the PAU.
380        """
381
382    def unregister(pau):
383        """Unregister any plugins not wanted to be in the PAU.
384        """
Note: See TracBrowser for help on using the repository browser.