Index: in/waeup.custom/trunk/src/waeup/custom/app.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/app.py	(revision 6880)
+++ 	(revision )
@@ -1,77 +1,0 @@
-import grok
-from hurry.file.interfaces import IFileRetrieval
-from zope.authentication.interfaces import IAuthentication
-from zope.component import getUtilitiesFor
-from zope.component.interfaces import ObjectEvent
-from zope.pluggableauth import PluggableAuthentication
-from waeup.sirp.authentication import setup_authentication
-from waeup.sirp.datacenter import DataCenter
-from waeup.sirp.students.container import StudentsContainer
-from waeup.sirp.imagestorage import ImageStorageFileRetrieval, ImageStorage
-from waeup.sirp.interfaces import (
-    IUniversity, IWAeUPSIRPPluggable, IObjectUpgradeEvent, )
-from waeup.sirp.users import UserContainer
-from waeup.sirp.utils.logger import Logger
-from waeup.sirp.utils.helpers import attrs_to_fields
-
-class University(grok.Application, grok.Container, Logger):
-    """A university.
-    """
-    grok.implements(IUniversity)
-
-    # Setup authentication for this app. Note: this is only
-    # initialized, when a new instance of this app is created.
-    grok.local_utility(
-        PluggableAuthentication, provides = IAuthentication,
-        setup = setup_authentication,)
-
-    grok.local_utility(
-        ImageStorageFileRetrieval, provides = IFileRetrieval)
-
-    def __init__(self, *args, **kw):
-        super(University, self).__init__(*args, **kw)
-        self.setup()
-        return
-
-    def setup(self):
-        """Setup some hard-wired components.
-
-        Create local datacenter, containers for users, students and
-        the like.
-        """
-        self['users'] = UserContainer()
-        self['datacenter'] = DataCenter()
-        self['images'] = ImageStorage()
-        self['students'] = StudentsContainer()
-        self._createPlugins()
-
-    def _createPlugins(self):
-        """Create instances of all plugins defined somewhere.
-        """
-        for name, plugin in getUtilitiesFor(IWAeUPSIRPPluggable):
-            plugin.setup(self, name, self.logger)
-        return
-
-    def updatePlugins(self):
-        """Lookup all plugins and call their `update()` method.
-        """
-        name = getattr(self, '__name__', '<Unnamed>')
-        self.logger.info('Fire upgrade event for site %s' % name)
-        grok.notify(ObjectUpgradeEvent(self))
-        self.logger.info('Done.')
-        self.logger.info('Now upgrading any plugins.')
-        for name, plugin in getUtilitiesFor(IWAeUPSIRPPluggable):
-            plugin.update(self, name, self.logger)
-        self.logger.info('Plugin update finished.')
-        return
-attrs_to_fields(University)
-
-class ObjectUpgradeEvent(ObjectEvent):
-    """An event fired, when datacenter storage moves.
-    """
-    grok.implements(IObjectUpgradeEvent)
-
-@grok.subscribe(University, grok.IObjectAddedEvent)
-def handle_university_added(app, event):
-    app.logger.info('University `%s` added.' % getattr(app, '__name__', None))
-    return
Index: in/waeup.custom/trunk/src/waeup/custom/app.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/app.txt	(revision 6880)
+++ 	(revision )
@@ -1,61 +1,0 @@
-:mod:`waeup.sirp.app` -- central components for a WAeUP portal
-**************************************************************
-
-.. :doctest:
-.. :layer: waeup.sirp.testing.WAeUPSIRPUnitTestLayer
-
-.. module:: waeup.sirp.app
-
-.. class:: University
-
-  The main WAeUP application object is given with
-  :class:`University`. It provides the main containers as faculties,
-  hostels, etc.
-
-  .. attribute:: name
-
-     A string. The name of a university.
-
-  .. attribute:: faculties
-
-     An arbitrary object containing "faculties". In the case of
-     `University` it is a container of type
-     `waeup.sirp.interfaces.IFacultyContainer`.
-
-
-Creating `University` instances
-===============================
-
-As :class:`University` instances make use of the Zope Component
-Architecture (ZCA), we have to setup the basic component registries,
-before we can create instances. We do this by simply grokking the
-whole :mod:`waeup` package. This way all interfaces, utilities and adapters
-defined in the package are looked up and registered with the global
-registries (this is done by the testlayer automatically).
-
-Now we can import the :class:`University` class and create an
-instance:
-
-    >>> from waeup.sirp.app import University
-    >>> myuniversity = University()
-    >>> myuniversity
-    <waeup.sirp.app.University object at 0x...>
-
-Instances of `University` comply with the interface
-`waeup.sirp.interfaces.IUniversity`:
-
-    >>> from zope.interface.verify import verifyClass
-    >>> from waeup.sirp.interfaces import IUniversity
-    >>> verifyClass(IUniversity, University)
-    True
-
-A freshly created instance provides the attributes promised by the
-interface:
-
-    >>> from waeup.sirp.app import University
-    >>> myuniversity = University()
-    >>> myuniversity.name
-    u'Sample University'
-
-    >>> myuniversity['faculties']
-    <waeup.sirp.university.facultycontainer.FacultyContainer object at 0x...>
Index: in/waeup.custom/trunk/src/waeup/custom/authentication.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/authentication.py	(revision 6880)
+++ 	(revision )
@@ -1,187 +1,0 @@
-"""Authentication for WAeUP portals.
-"""
-import grok
-from zope.component import getUtility, getUtilitiesFor
-from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
-from zope.pluggableauth.interfaces import (
-        ICredentialsPlugin, IAuthenticatorPlugin, IPrincipalInfo)
-from zope.password.interfaces import IPasswordManager
-from zope.securitypolicy.interfaces import IPrincipalRoleManager
-from zope.securitypolicy.principalrole import principalRoleManager
-from waeup.sirp.interfaces import IUserAccount, IAuthPluginUtility
-
-def setup_authentication(pau):
-    """Set up plugguble authentication utility.
-
-    Sets up an IAuthenticatorPlugin and
-    ICredentialsPlugin (for the authentication mechanism)
-
-    Then looks for any external utilities that want to modify the PAU.
-    """
-    pau.credentialsPlugins = ('No Challenge if Authenticated', 'credentials')
-    pau.authenticatorPlugins = ('users',)
-
-    # Give any third-party code and subpackages a chance to modify the PAU
-    auth_plugin_utilities = getUtilitiesFor(IAuthPluginUtility)
-    for name, util in auth_plugin_utilities:
-        util.register(pau)
-
-def get_principal_role_manager():
-    """Get a role manager for principals.
-
-    If we are currently 'in a site', return the role manager for the
-    portal or the global rolemanager else.
-    """
-    portal = grok.getSite()
-    if portal is not None:
-        return IPrincipalRoleManager(portal)
-    return principalRoleManager
-
-class WAeUPSessionCredentialsPlugin(grok.GlobalUtility,
-                                    SessionCredentialsPlugin):
-    grok.provides(ICredentialsPlugin)
-    grok.name('credentials')
-
-    loginpagename = 'login'
-    loginfield = 'form.login'
-    passwordfield = 'form.password'
-
-class PrincipalInfo(object):
-    grok.implements(IPrincipalInfo)
-
-    def __init__(self, id, title, description):
-        self.id = id
-        self.title = title
-        self.description = description
-        self.credentialsPlugin = None
-        self.authenticatorPlugin = None
-
-class Account(grok.Model):
-    grok.implements(IUserAccount)
-
-    _local_roles = dict()
-
-    def __init__(self, name, password, title=None, description=None,
-                 roles = []):
-        self.name = name
-        if title is None:
-            title = name
-        if description is None:
-            description = title
-        self.title = title
-        self.description = description
-        self.setPassword(password)
-        self.setRoles(roles)
-        # We don't want to share this dict with other accounts
-        self._local_roles = dict()
-
-    def setPassword(self, password):
-        passwordmanager = getUtility(IPasswordManager, 'SHA1')
-        self.password = passwordmanager.encodePassword(password)
-
-    def checkPassword(self, password):
-        passwordmanager = getUtility(IPasswordManager, 'SHA1')
-        return passwordmanager.checkPassword(self.password, password)
-
-    def getRoles(self):
-        prm = get_principal_role_manager()
-        roles = [x[0] for x in prm.getRolesForPrincipal(self.name)
-                 if x[0].startswith('waeup.')]
-        return roles
-
-    def setRoles(self, roles):
-        prm = get_principal_role_manager()
-
-        old_roles = self.getRoles()
-        for role in old_roles:
-            # Remove old roles, not to be set now...
-            if role.startswith('waeup.') and role not in roles:
-                prm.unsetRoleForPrincipal(role, self.name)
-
-        for role in roles:
-            prm.assignRoleToPrincipal(role, self.name)
-
-    roles = property(getRoles, setRoles)
-
-    def getLocalRoles(self):
-        return self._local_roles
-
-    def notifyLocalRoleChanged(self, obj, role_id, granted=True):
-        objects = self._local_roles.get(role_id, [])
-        if granted and obj not in objects:
-            objects.append(obj)
-        if not granted and obj in objects:
-            objects.remove(obj)
-        self._local_roles[role_id] = objects
-        if len(objects) == 0:
-            del self._local_roles[role_id]
-        self._p_changed = True
-        return
-
-class UserAuthenticatorPlugin(grok.GlobalUtility):
-    grok.implements(IAuthenticatorPlugin)
-    grok.provides(IAuthenticatorPlugin)
-    grok.name('users')
-
-    def authenticateCredentials(self, credentials):
-        if not isinstance(credentials, dict):
-            return None
-        if not ('login' in credentials and 'password' in credentials):
-            return None
-        account = self.getAccount(credentials['login'])
-
-        if account is None:
-            return None
-        if not account.checkPassword(credentials['password']):
-            return None
-        return PrincipalInfo(id=account.name,
-                             title=account.title,
-                             description=account.description)
-
-    def principalInfo(self, id):
-        account = self.getAccount(id)
-        if account is None:
-            return None
-        return PrincipalInfo(id=account.name,
-                             title=account.title,
-                             description=account.description)
-
-    def getAccount(self, login):
-        # ... look up the account object and return it ...
-        usercontainer = self.getUserContainer()
-        if usercontainer is None:
-            return
-        return usercontainer.get(login, None)
-
-    def addAccount(self, account):
-        usercontainer = self.getUserContainer()
-        if usercontainer is None:
-            return
-        # XXX: complain if name already exists...
-        usercontainer.addAccount(account)
-
-    def addUser(self, name, password, title=None, description=None):
-        usercontainer = self.getUserContainer()
-        if usercontainer is None:
-            return
-        usercontainer.addUser(name, password, title, description)
-
-    def getUserContainer(self):
-        site = grok.getSite()
-        return site['users']
-
-@grok.subscribe(IUserAccount, grok.IObjectRemovedEvent)
-def handle_account_removed(account, event):
-    """When an account is removed, local roles might have to be deleted.
-    """
-    local_roles = account.getLocalRoles()
-    principal = account.name
-    for role_id, object_list in local_roles.items():
-        for object in object_list:
-            try:
-                role_manager = IPrincipalRoleManager(object)
-            except TypeError:
-                # No role manager, no roles to remove
-                continue
-            role_manager.unsetRoleForPrincipal(role_id, principal)
-    return
Index: in/waeup.custom/trunk/src/waeup/custom/authentication.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/authentication.txt	(revision 6880)
+++ 	(revision )
@@ -1,203 +1,0 @@
-WAeUP portal authentication
-***************************
-
-We need to protect most pieces of our portals from unauthenticated
-access.
-
-Therefore users have to login to access main functionality and they
-are able to log out afterwards.
-
-Before we can check access we have to create an app:
-
-  >>> from zope.component.hooks import setSite # only needed in tests
-  >>> from waeup.sirp.app import University
-  >>> root = getRootFolder()
-  >>> u = University()
-  >>> root['app'] = u
-  >>> setSite(root['app'])                     # only needed in tests
-
-To make sure, we can 'watch' pages, we first have to initialize our
-test browser:
-
-  >>> from zope.testbrowser.testing import Browser
-  >>> browser = Browser()
-  >>> browser.handleErrors = False
-
-Creating users (principals)
-===========================
-
-Before we can login, we have to provide a user (``principal`` in Zope
-terms) with a password (and optional a title or description):
-
-  >>> root['app']['users'].addUser('bob', 'bobsecret',
-  ...                           title='Bob', description='A sample user')
-
-We can also add complete `Account` objects. An `Account` stores the
-user credentials and some metadata persistently:
-
-  >>> from waeup.sirp.authentication import Account
-  >>> alice = Account('alice', 'alicesecret')
-  >>> root['app']['users'].addAccount(alice)
-
-See ``users.txt`` for details about the UserContainer we use here.
-
-Users and local roles
-=====================
-
-Accounts also hold infos about local roles assigned to a user. In the
-beginning, users have no local roles at all:
-
-  >>> alice.getLocalRoles()
-  {}
-
-But we can tell an account, that Alice got some role for a certain
-object:
-
-  >>> chalet = object()
-  >>> root['app']['chalet'] = chalet
-  >>> alice.notifyLocalRoleChanged(chalet, 'BigBoss', granted=True)
-
-Now Alice is the Big Boss:
-
-  >>> alice.getLocalRoles()
-  {'BigBoss': [<object object at 0x...>]}
-
-When we do not want Alice to be the Big Boss we can tell that too:
-
-  >>> alice.notifyLocalRoleChanged(chalet, 'BigBoss', granted=False)
-  >>> alice.getLocalRoles()
-  {}
-
-We can also use events to trigger such actions. This is recommended
-because we do not neccessarily know where Alice lives:
-
-  >>> from waeup.sirp.users import LocalRoleSetEvent
-  >>> from zope.event import notify
-  >>> notify(LocalRoleSetEvent(chalet, 'BigBoss', 'alice',
-  ...                          granted=True))
-  >>> alice.getLocalRoles()
-  {'BigBoss': [<object object at 0x...>]}
-
-When objects are deleted, local roles are also deleted
-semi-magically. This happens through event subscribers listening to
-IObjectRemovedEvents. The latters are naturally only fired when ZODB
-stored objects are removed. Furthermore this subscriber reads the
-internal local roles table.
-
-We create a faculty and grant Bob a local role:
-
-   >>> from zope.securitypolicy.interfaces import IPrincipalRoleManager
-   >>> from waeup.sirp.university.faculty import Faculty
-   >>> faculty = Faculty()
-   >>> root['app']['bobs_fac'] = faculty
-   >>> role_manager = IPrincipalRoleManager(faculty)
-   >>> role_manager.assignRoleToPrincipal(
-   ...    'waeup.PortalManager', 'bob')
-
-We notify the machinery about that fact:
-
-   >>> notify(LocalRoleSetEvent(faculty, 'waeup.PortalManager', 'bob',
-   ...                          granted=True))
-   >>> bob = root['app']['users']['bob']
-   >>> bob.getLocalRoles()
-   {'waeup.PortalManager': [<waeup.sirp...Faculty object at 0x...>]}
-
-When we delete the faculty from ZODB, also Bobs roles are modified:
-
-   >>> del root['app']['bobs_fac']
-   >>> bob.getLocalRoles()
-   {}
-
-If one notifies the machinery of a local role removal for an object
-that cannot have local roles, this will cause no trouble:
-
-   >>> mycontext = None #object()
-   >>> notify(LocalRoleSetEvent(
-   ...   mycontext, 'waeup.PortalManager', 'bob', granted=False
-   ... )) is None
-   True
-
-When an account get deleted, also the local roles of the owner get
-removed. Let's setup a local role for `alice`:
-
-   >>> faculty = Faculty()
-   >>> root['app']['alice_fac'] = faculty
-   >>> role_manager = IPrincipalRoleManager(faculty)
-   >>> role_manager.assignRoleToPrincipal(
-   ...    'waeup.PortalManager', 'alice')
-   >>> notify(LocalRoleSetEvent(faculty, 'waeup.PortalManager', 'alice',
-   ...                          granted=True))
-
-The local role is set now:
-
-   >>> from zope.securitypolicy.interfaces import IPrincipalRoleMap
-   >>> IPrincipalRoleMap(faculty).getPrincipalsAndRoles()
-   [('waeup.PortalManager', 'alice', PermissionSetting: Allow)]
-
-But when we delete Alices account from ZODB:
-
-   >>> del root['app']['users']['alice']
-   >>> IPrincipalRoleMap(faculty).getPrincipalsAndRoles()
-   []
-
-the local role has gone.
-
-
-Logging in via side bar
-=======================
-
-We can access the front page without restrictions:
-
-  >>> browser.open('http://localhost/app')
-  >>> print browser.headers['Status']
-  200 Ok
-
-We have to go to one of the login pages first:
-
-  >>> browser.open('http://localhost/app')
-  >>> browser.getLink('Login').click()
-  >>> print browser.headers['Status']
-  200 Ok
-
-There is a login form on tis page:
-
-  >>> 'form.login' in browser.contents
-  True
-
-  >>> 'form.logout' in browser.contents
-  False
-
-We use this form:
-
-  >>> browser.getControl(name='form.login').value = 'bob'
-  >>> browser.getControl(name='form.password').value = 'invalidpw'
-  >>> browser.getControl('Login').click()
-  >>> 'You entered wrong credentials' in browser.contents
-  True
-
-  >>> browser.getControl(name='form.login').value = 'bob'
-  >>> browser.getControl(name='form.password').value = 'bobsecret'
-  >>> browser.getControl('Login').click()
-
-Now the login form is gone. Instead we have the opportunity to logout:
-
-  >>> 'form.login' in browser.contents
-  False
-
-  >>> logout = browser.getLink('Logout')
-  >>> logout
-  <Link text='Logout' url='http://localhost/app/@@logout'>
-
-The user title is also displayed in the sidebar:
-
-  >>> 'Bob' in browser.contents
-  True
-
-We can also log out afterwards:
-
-  >>> logout.click()
-  >>> print browser.contents
-  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"...
-  ...Login
-  ...
-
Index: in/waeup.custom/trunk/src/waeup/custom/catalog.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/catalog.py	(revision 6880)
+++ 	(revision )
@@ -1,48 +1,0 @@
-"""Components to help cataloging and searching objects.
-"""
-import grok
-from grok import index
-from hurry.query import Eq
-from hurry.query.interfaces import IQuery
-from hurry.query.query import Query
-from zope.catalog.catalog import ResultSet
-from zope.component import getUtility
-from zope.intid.interfaces import IIntIds
-
-from waeup.sirp.app import University
-from waeup.sirp.interfaces import IQueryResultItem
-
-# not yet used
-class WAeUPQuery(Query):
-    """A hurry.query-like query that supports also ``apply``.
-    """
-    grok.implements(IQuery)
-
-    def apply(self, query):
-        """Get a catalog's BTree set of intids conforming to a query.
-        """
-        return query.apply()
-
-    def searchResults(self, query):
-        """Get a set of ZODB objects conforming to a query.
-        """
-        results = self.apply(query)
-        if results is not None:
-            uidutil = getUtility(IIntIds)
-            results = ResultSet(results, uidutil)
-        return results
-
-grok.global_utility(WAeUPQuery)
-
-# not yet used
-class QueryResultItem(object):
-    grok.implements(IQueryResultItem)
-    url = None
-    title = None
-    description = None
-
-    def __init__(self, context, view):
-        self.context = context
-        self.url = view.url(context)
-        self.title = context.title
-        self.description = ''
Index: in/waeup.custom/trunk/src/waeup/custom/catalog.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/catalog.txt	(revision 6880)
+++ 	(revision )
@@ -1,235 +1,0 @@
-:mod:`waeup.sirp.catalog` -- Cataloging support for WAeUP SIRP
-**************************************************************
-
-.. module:: waeup.sirp.catalog
-
-Components that support cataloging and searching objects inside a
-WAeUP SIRP site.
-
-.. :doctest:
-.. :layer: waeup.sirp.testing.WAeUPSIRPUnitTestLayer
-
-.. contents::
-
-Classes
-=======
-
-:class:`WAeUPQuery`
--------------------
-
-.. class:: WAeUPQuery()
-
-   .. attribute:: grok.implements(hurry.query.interfaces.IQuery)
-
-   A `hurry.query.query.Query` compatible query that also supports
-   retrival of plain ``Bree`` result sets as used inside a catalog.
-
-   Like `hurry.query.query.Query` objects, `WAeUPQuery` is some kind
-   of a meta query or 'compound query' that can give the cataloged
-   objects (or their int ids) matching one or more 'subqueries'.
-
-   This way you can search for objects (or their int ids) that match
-   several criteria at the same time. See ``examples`` section below.
-
-   A singleton instance of this class is also available as global
-   utility.
-
-   .. method:: searchResults(query)
-
-     Get the cataloged objects determined by ``query``.
-
-   .. method:: apply(query)
-
-     Get the list of int ids (a `BTree` result set) for objects
-     determined by ``query``.
-
-     The list of int ids is less expensive to compute than the
-     complete search results and sufficient, for instance, when you
-     only need the number of objects that match a query and not the
-     objects themselves.
-
-Examples
-========
-
-Getting a general query object
-------------------------------
-
-We can get a WAeUPQuery object by asking for an unnamed global utility
-implementing `hurry.query.interfaces.IQuery`:
-
-    >>> from hurry.query.interfaces import IQuery
-    >>> from zope.component import getUtility
-    >>> q = getUtility(IQuery)
-    >>> q
-    <waeup.sirp.catalog.WAeUPQuery object at 0x...>
-
-This query can get 'subqueries' and delivers the objects found or
-their ids. To show this we have to setup a catalog with some entries.
-
-
-Setting up a catalog and feeding it
------------------------------------
-
-    >>> from zope.catalog.interfaces import ICatalog
-    >>> from zope.catalog.catalog import Catalog
-    >>> mycat = Catalog()
-
-We register this catalog with the component architechture as a utility
-named 'mycatalog':
-
-    >>> from zope.component import provideUtility
-    >>> provideUtility(mycat, ICatalog, 'mycatalog')
-
-We setup a special content type whose instances we will catalog later:
-
-    >>> from zope.interface import Interface, Attribute, implements
-    >>> from zope.container.contained import Contained
-    >>> class IMammoth(Interface):
-    ...   name = Attribute('name')
-    ...   age = Attribute('age')
-
-    >>> class Mammoth(Contained):
-    ...   implements(IMammoth)
-    ...   def __init__(self, name, age):
-    ...     self.name = name
-    ...     self.age = age
-    ...   def __cmp__(self, other):
-    ...     return cmp(self.name, other.name)
-
-By including the __cmp__ method we make sure search results can be
-stably sorted.
-
-We also setup a `zope.intid.interfaces.IIntIds` utility. This is not
-necessary for plain catalogs, but when we want to use WAeUPQuery (or
-`hurry.query.query.Query` objects), as to get a unique mapping from
-objects (stored in ZODB) to integer numbers (stored in catalogs),
-these query objects lookup a global IIntIds utiliy:
-
-    >>> from zope import interface
-    >>> import zope.intid.interfaces
-    >>> class DummyIntId(object):
-    ...     interface.implements(zope.intid.interfaces.IIntIds)
-    ...     MARKER = '__dummy_int_id__'
-    ...     def __init__(self):
-    ...         self.counter = 0
-    ...         self.data = {}
-    ...     def register(self, obj):
-    ...         intid = getattr(obj, self.MARKER, None)
-    ...         if intid is None:
-    ...             setattr(obj, self.MARKER, self.counter)
-    ...             self.data[self.counter] = obj
-    ...             intid = self.counter
-    ...             self.counter += 1
-    ...         return intid
-    ...     def getObject(self, intid):
-    ...         return self.data[intid]
-    ...     def __iter__(self):
-    ...         return iter(self.data)
-    >>> intid = DummyIntId()
-    >>> from zope.component import provideUtility
-    >>> provideUtility(intid, zope.intid.interfaces.IIntIds)
-
-Now we can catalog some mammoths. Here we create a herd and catalog
-each item of it:
-
-    >>> from zope.catalog.field import FieldIndex
-    >>> mycat['mammoth_name'] = FieldIndex('name', IMammoth)
-    >>> mycat['mammoth_age'] = FieldIndex('age', IMammoth)
-
-    >>> herd = [
-    ...   Mammoth(name='Fred', age=33),
-    ...   Mammoth(name='Hank', age=30),
-    ...   Mammoth(name='Wilma', age=28),
-    ... ]
-
-    >>> for mammoth in herd:
-    ...   mycat.index_doc(intid.register(mammoth), mammoth)
-
-
-Searching for result sets
--------------------------
-
-Finally we can perform queries:
-
-    >>> from hurry.query import Eq
-    >>> from zope.component import getUtility
-    >>> subquery1 = Eq(('mycatalog', 'mammoth_name'), 'Fred')
-
-The latter means: search for objects whose name is ``'Fred'`` in the
-``mammoth_name`` index of a catalog registered as a utility named
-``mycatalog``.
-
-    >>> from hurry.query import Between
-    >>> subquery2 = Between(('mycatalog', 'mammoth_age'), 30, 33)
-
-This means: ask for objects cataloged in an index named 'mammoth_age',
-whose cataloged value is between 30 and 33 (including this values).
-
-    >>> r1 = q.apply(subquery2)
-    >>> r1
-    IFSet([0, 1])
-
-Using ``apply()`` above, we get a set of values stored in an
-``IFBTree``:
-
-    >>> type(r1)
-    <type 'BTrees.IFBTree.IFSet'>
-
-``IFBTree`` objects implement a rather efficient integer to float
-mapping where also integers are allowed as values. For each object
-found (i.e. mammoths whose age is between 30 and 33), we get the
-number of its entry.
-
-To get the real object, we can use intids here, because we setup an
-appropriate IIntIds utility before:
-
-    >>> [intid.getObject(x).name for x in r1]
-    ['Fred', 'Hank']
-
-We can (and should) also use the `searchResults()` method explained
-below to do that.
-
-Retrieving BTree sets can, however, make sense, if you want to know
-only the number of results for a particular query or whether there are
-results at all in a more efficient way:
-
-    >>> len(r1)
-    2
-
-Searching for objects
----------------------
-
-Very often we don't want to know the catalog-internal 'ids' of
-searched objects but the objects themselves.
-
-This can be done by using the ``searchResults`` method of
-``WAeUPQuery``:
-
-    >>> r2 = q.searchResults(subquery1)
-    >>> r2
-    <zope.catalog.catalog.ResultSet instance at 0x...>
-
-    >>> list(r2)
-    [<Mammoth object at 0x...>]
-
-We got one result item, we can immediately ask for further infos. To
-access a result item by its index number, we have to turn the
-ResultSet into an ordinary list before:
-
-    >>> entry = list(r2)[0]
-    >>> entry.name, entry.age
-    ('Fred', 33)
-
-We can also use ``subquery2`` as above:
-
-    >>> r3 = q.searchResults(subquery2)
-    >>> [(x.name, x.age) for x in r3]
-    [('Fred', 33), ('Hank', 30)]
-
-or use both queries at once:
-
-    >>> r4 = q.searchResults(subquery1 & subquery2)
-    >>> [(x.name, x.age) for x in r4]
-    [('Fred', 33)]
-
-which will give us, of course, the same result set as with subquery1.
Index: in/waeup.custom/trunk/src/waeup/custom/datacenter.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/datacenter.py	(revision 6880)
+++ 	(revision )
@@ -1,259 +1,0 @@
-"""WAeUP data center.
-
-The waeup data center cares for management of upload data and provides
-tools for importing/exporting CSV data.
-"""
-import logging
-import os
-import shutil
-import grok
-from datetime import datetime
-from zope.component.interfaces import ObjectEvent
-from waeup.sirp.interfaces import (IDataCenter, IDataCenterFile,
-                                   IDataCenterStorageMovedEvent)
-from waeup.sirp.utils.helpers import copyFileSystemTree
-from waeup.sirp.utils.logger import Logger
-
-class DataCenter(grok.Container, Logger):
-    """A data center contains CSV files.
-    """
-    grok.implements(IDataCenter)
-    storage = os.path.join(os.path.dirname(__file__), 'files')
-
-    logger_name = 'waeup.sirp.${sitename}.datacenter'
-    logger_filename = 'datacenter.log'
-
-    def __init__(self, *args, **kw):
-        super(DataCenter, self).__init__(*args, **kw)
-        self._createSubDirs()
-
-    def _createSubDirs(self):
-        """Create standard subdirs.
-        """
-        for name in ['finished', 'unfinished', 'logs']:
-            path = os.path.join(self.storage, name)
-            if os.path.exists(path):
-                continue
-            os.mkdir(path)
-        return
-
-    def getFiles(self, sort='name'):
-        """Get a list of files stored in `storage`.
-
-        Files are sorted by basename.
-        """
-        result = []
-        if not os.path.exists(self.storage):
-            return result
-        for filename in sorted(os.listdir(self.storage)):
-            fullpath = os.path.join(self.storage, filename)
-            if not os.path.isfile(fullpath):
-                continue
-            result.append(DataCenterFile(fullpath))
-        if sort == 'date':
-            # sort results in newest-first order...
-            result = sorted(result, key=lambda x: x.getTimeStamp(),
-                            reverse=True)
-        return result
-
-    def getLogFiles(self):
-        """Get the files from logs/ subdir. Files are sorted by name.
-        """
-        result = []
-        logdir = os.path.join(self.storage, 'logs')
-        if not os.path.exists(logdir):
-            os.mkdir(logdir)
-        for name in sorted(os.listdir(logdir)):
-            if not os.path.isfile(os.path.join(logdir, name)):
-                continue
-            result.append(
-                LogFile(os.path.join(self.storage, 'logs', name)))
-        return result
-
-    def setStoragePath(self, path, move=False, overwrite=False):
-        """Set the path where to store files.
-        """
-        path = os.path.abspath(path)
-        not_copied = []
-        if not os.path.exists(path):
-            raise ValueError('The path given does not exist: %s' % path)
-        if move is True:
-
-            not_copied = copyFileSystemTree(self.storage, path,
-                                            overwrite=overwrite)
-        self.storage = path
-        self._createSubDirs()
-        grok.notify(DataCenterStorageMovedEvent(self))
-        return not_copied
-
-    def _moveFile(self, source, dest):
-        """Move file source to dest preserving ctime, mtime, etc.
-        """
-        if not os.path.exists(source):
-            self.logger.warn('No such source path: %s' % source)
-            return
-        if source == dest:
-            return
-        shutil.copyfile(source, dest)
-        shutil.copystat(source, dest)
-        os.unlink(source)
-
-    def distProcessedFiles(self, successful, source_path, finished_file,
-                           pending_file, mode='create', move_orig=True):
-        """Put processed files into final locations.
-
-        ``successful`` is a boolean that tells, whether processing was
-        successful.
-
-        ``source_path``: path to file that was processed.
-
-        ``finished_file``, ``pending_file``: paths to the respective
-        generated .pending and .finished file. The .pending file path
-        may be ``None``.
-
-        If finished file is placed in a location outside the local
-        storage dir, the complete directory is removed
-        afterwards. Regular importers should put their stuff in
-        dedicated temporary dirs.
-
-        See datacenter.txt for more info about how this works.
-        """
-        basename = os.path.basename(source_path)
-        pending_name = basename
-        pending = False
-        finished_dir = os.path.join(self.storage, 'finished')
-        unfinished_dir = os.path.join(self.storage, 'unfinished')
-
-        if basename.endswith('.pending.csv'):
-            maybe_basename = "%s.csv" % basename.rsplit('.', 3)[0]
-            maybe_src = os.path.join(unfinished_dir, maybe_basename)
-            if os.path.isfile(maybe_src):
-                basename = maybe_basename
-                pending = True
-
-        base, ext = os.path.splitext(basename)
-        finished_name = "%s.%s.finished%s" % (base, mode, ext)
-        if not pending:
-            pending_name = "%s.%s.pending%s" % (base, mode, ext)
-
-        # Put .pending and .finished file into respective places...
-        pending_dest = os.path.join(self.storage, pending_name)
-        finished_dest = os.path.join(finished_dir, finished_name)
-        self._moveFile(finished_file, finished_dest)
-        if pending_file is not None:
-            self._moveFile(pending_file, pending_dest)
-
-        # Put source file into final location...
-        finished_dest = os.path.join(finished_dir, basename)
-        unfinished_dest = os.path.join(unfinished_dir, basename)
-        if successful and not pending:
-            self._moveFile(source_path, finished_dest)
-        elif successful and pending:
-            self._moveFile(unfinished_dest, finished_dest)
-            os.unlink(source_path)
-        elif not successful and not pending:
-            self._moveFile(source_path, unfinished_dest)
-
-        # If finished and pending-file were created in a location
-        # outside datacenter storage, we remove it.
-        maybe_temp_dir = os.path.dirname(finished_file)
-        if os.path.commonprefix(
-            [self.storage, maybe_temp_dir]) != self.storage:
-            shutil.rmtree(maybe_temp_dir)
-        return
-
-
-class DataCenterFile(object):
-    """A description of a file stored in data center.
-    """
-    grok.implements(IDataCenterFile)
-
-    def __init__(self, context):
-        self.context = context
-        self.name = os.path.basename(self.context)
-        self.size = self.getSize()
-        self.uploaddate = self.getDate()
-        self.lines = self.getLinesNumber()
-
-    def getDate(self):
-        """Get a human readable datetime representation.
-        """
-        date = datetime.fromtimestamp(os.path.getctime(self.context))
-        return date.strftime("%Y-%m-%d %H:%M:%S")
-
-    def getTimeStamp(self):
-        """Get a (machine readable) timestamp.
-        """
-        return os.path.getctime(self.context)
-
-    def getSize(self):
-        """Get a human readable file size.
-        """
-        bytesize = os.path.getsize(self.context)
-        size = "%s bytes" % bytesize
-        units = ['kb', 'MB', 'GB']
-        for power, unit in reversed(list(enumerate(units))):
-            power += 1
-            if bytesize >= 1024 ** power:
-                size = "%.2f %s" % (bytesize/(1024.0**power), unit)
-                break
-        return size
-
-    def getLinesNumber(self):
-        """Get number of lines.
-        """
-        num = 0
-        for line in open(self.context, 'rb'):
-            num += 1
-        return num
-
-class LogFile(DataCenterFile):
-    """A description of a log file.
-    """
-    def __init__(self, context):
-        super(LogFile, self).__init__(context)
-        self._markers = dict()
-        self._parsed = False
-        self.userid = self.getUserId()
-        self.mode = self.getMode()
-        self.stats = self.getStats()
-        self.source = self.getSourcePath()
-
-    def _parseFile(self, maxline=10):
-        """Find markers in a file.
-        """
-        if self._parsed:
-            return
-        for line in open(self.context, 'rb'):
-            line = line.strip()
-            if not ':' in line:
-                continue
-            name, text = line.split(':', 1)
-            self._markers[name.lower()] = text
-        self._parsed = True
-        return
-
-    def _getMarker(self, marker):
-        marker = marker.lower()
-        if not self._parsed:
-            self._parseFile()
-        if marker in self._markers.keys():
-            return self._markers[marker]
-
-    def getUserId(self):
-        return self._getMarker('user') or '<UNKNOWN>'
-
-    def getMode(self):
-        return self._getMarker('mode') or '<NOT SET>'
-
-    def getStats(self):
-        return self._getMarker('processed') or '<Info not avail.>'
-
-    def getSourcePath(self):
-        return self._getMarker('source') or None
-
-
-class DataCenterStorageMovedEvent(ObjectEvent):
-    """An event fired, when datacenter storage moves.
-    """
-    grok.implements(IDataCenterStorageMovedEvent)
Index: in/waeup.custom/trunk/src/waeup/custom/datacenter.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/datacenter.txt	(revision 6880)
+++ 	(revision )
@@ -1,259 +1,0 @@
-WAeUP Data Center
-*****************
-
-The WAeUP data center cares for managing CSV files and importing then.
-
-.. :doctest:
-.. :layer: waeup.sirp.testing.WAeUPSIRPUnitTestLayer
-
-Creating a data center
-======================
-
-A data center can be created easily:
-
-    >>> from waeup.sirp.datacenter import DataCenter
-    >>> mydatacenter = DataCenter()
-    >>> mydatacenter
-    <waeup.sirp.datacenter.DataCenter object at 0x...>
-
-Each data center has a location in file system where files are stored:
-
-    >>> storagepath = mydatacenter.storage
-    >>> storagepath
-    '/.../waeup/sirp/files'
-
-
-Managing the storage path
--------------------------
-
-We can set another storage path:
-
-    >>> import os
-    >>> os.mkdir('newlocation')
-    >>> newpath = os.path.abspath('newlocation')
-    >>> mydatacenter.setStoragePath(newpath)
-    []
-
-The result here is a list of filenames, that could not be
-copied. Luckily, this list is empty.
-
-When we set a new storage path, we can tell to move all files in the
-old location to the new one. To see this feature in action, we first
-have to put a file into the old location:
-
-    >>> open(os.path.join(newpath, 'myfile.txt'), 'wb').write('hello')
-
-Now we can set a new location and the file will be copied:
-
-    >>> verynewpath = os.path.abspath('verynewlocation')
-    >>> os.mkdir(verynewpath)
-
-    >>> mydatacenter.setStoragePath(verynewpath, move=True)
-    []
-
-    >>> storagepath = mydatacenter.storage
-    >>> 'myfile.txt' in os.listdir(verynewpath)
-    True
-
-We remove the created file to have a clean testing environment for
-upcoming examples:
-
-    >>> os.unlink(os.path.join(storagepath, 'myfile.txt'))
-
-Uploading files
-===============
-
-We can get a list of files stored in that location:
-
-    >>> mydatacenter.getFiles()
-    []
-
-Let's put some file in the storage:
-
-    >>> import os
-    >>> filepath = os.path.join(storagepath, 'data.csv')
-    >>> open(filepath, 'wb').write('Some Content\n')
-
-Now we can find a file:
-
-    >>> mydatacenter.getFiles()
-    [<waeup.sirp.datacenter.DataCenterFile object at 0x...>]
-
-As we can see, the actual file is wrapped by a convenience wrapper,
-that enables us to fetch some data about the file. The data returned
-is formatted in strings, so that it can easily be put into output
-pages:
-
-    >>> datafile = mydatacenter.getFiles()[0]
-    >>> datafile.getSize()
-    '13 bytes'
-
-    >>> datafile.getDate() # Nearly current datetime...
-    '...'
-
-Clean up:
-
-    >>> import shutil
-    >>> shutil.rmtree(newpath)
-    >>> shutil.rmtree(verynewpath)
-
-
-Distributing processed files
-============================
-
-When files were processed by a batch processor, we can put the
-resulting files into desired destinations.
-
-We recreate the datacenter root in case it is missing:
-
-    >>> import os
-    >>> dc_root = mydatacenter.storage
-    >>> fin_dir = os.path.join(dc_root, 'finished')
-    >>> unfin_dir = os.path.join(dc_root, 'unfinished')
-
-    >>> def recreate_dc_storage():
-    ...   if os.path.exists(dc_root):
-    ...     shutil.rmtree(dc_root)
-    ...   os.mkdir(dc_root)
-    ...   mydatacenter.setStoragePath(mydatacenter.storage)
-    >>> recreate_dc_storage()
-
-We define a function that creates a set of faked result files:
-
-    >>> import os
-    >>> import tempfile
-    >>> def create_fake_results(source_basename, create_pending=True):
-    ...   tmp_dir = tempfile.mkdtemp()
-    ...   src = os.path.join(dc_root, source_basename)
-    ...   pending_src = None
-    ...   if create_pending:
-    ...     pending_src = os.path.join(tmp_dir, 'mypendingsource.csv')
-    ...   finished_src = os.path.join(tmp_dir, 'myfinishedsource.csv')
-    ...   for path in (src, pending_src, finished_src):
-    ...     if path is not None:
-    ...       open(path, 'wb').write('blah')
-    ...   return tmp_dir, src, finished_src, pending_src
-
-Now we can create the set of result files, that typically come after a
-successful processing of a regular source:
-
-Now we can try to distribute those files. Let's start with a source
-file, that was processed successfully:
-
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.csv', create_pending=False)
-    >>> mydatacenter.distProcessedFiles(True, src, finished_src,
-    ...                            pending_src, mode='create')
-    >>> sorted(os.listdir(dc_root))
-    ['finished', 'logs', 'unfinished']
-
-    >>> sorted(os.listdir(fin_dir))
-    ['mysource.create.finished.csv', 'mysource.csv']
-
-    >>> sorted(os.listdir(unfin_dir))
-    []
-
-The created dir will be removed for us by the datacenter. This way we
-can assured, that less temporary dirs are left hanging around:
-
-    >>> os.path.exists(tmp_dir)
-    False
-
-The root dir is empty, while the original file and the file containing
-all processed data were moved to'finished/'.
-
-Now we restart, but this time we fake an erranous action:
-
-    >>> recreate_dc_storage()
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.csv')
-    >>> mydatacenter.distProcessedFiles(False, src, finished_src,
-    ...                                 pending_src, mode='create')
-    >>> sorted(os.listdir(dc_root))
-    ['finished', 'logs', 'mysource.create.pending.csv', 'unfinished']
-
-    >>> sorted(os.listdir(fin_dir))
-    ['mysource.create.finished.csv']
-
-    >>> sorted(os.listdir(unfin_dir))
-    ['mysource.csv']
-
-While the original source was moved to the 'unfinished' dir, the
-pending file went to the root and the set of already processed items
-are stored in finished/.
-
-We fake processing the pending file and assume that everything went
-well this time:
-
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.create.pending.csv', create_pending=False)
-    >>> mydatacenter.distProcessedFiles(True, src, finished_src,
-    ...                                 pending_src, mode='create')
-
-    >>> sorted(os.listdir(dc_root))
-    ['finished', 'logs', 'unfinished']
-
-    >>> sorted(os.listdir(fin_dir))
-    ['mysource.create.finished.csv', 'mysource.csv']
-
-    >>> sorted(os.listdir(unfin_dir))
-    []
-
-The result is the same as in the first case shown above.
-
-We restart again, but this time we fake several non-working imports in
-a row.
-
-We start with a faulty start-import:
-
-    >>> recreate_dc_storage()
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.csv')
-    >>> mydatacenter.distProcessedFiles(False, src, finished_src,
-    ...                                 pending_src, mode='create')
-
-We try to process the pending file, which fails again:
-
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.create.pending.csv')
-    >>> mydatacenter.distProcessedFiles(False, src, finished_src,
-    ...                                 pending_src, mode='create')
-
-We try to process the new pending file:
-
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.create.pending.csv')
-    >>> mydatacenter.distProcessedFiles(False, src, finished_src,
-    ...                                 pending_src, mode='create')
-
-    >>> sorted(os.listdir(dc_root))
-    ['finished', 'logs', 'mysource.create.pending.csv', 'unfinished']
-
-    >>> sorted(os.listdir(fin_dir))
-    ['mysource.create.finished.csv']
-
-    >>> sorted(os.listdir(unfin_dir))
-    ['mysource.csv']
-
-Finally, we process the pending file and everything works:
-
-    >>> tmp_dir, src, finished_src, pending_src = create_fake_results(
-    ...  'mysource.create.pending.csv', create_pending=False)
-    >>> mydatacenter.distProcessedFiles(True, src, finished_src,
-    ...                                 pending_src, mode='create')
-
-    >>> sorted(os.listdir(dc_root))
-    ['finished', 'logs', 'unfinished']
-
-    >>> sorted(os.listdir(fin_dir))
-    ['mysource.create.finished.csv', 'mysource.csv']
-
-    >>> sorted(os.listdir(unfin_dir))
-    []
-
-The root dir is empty (contains no input files) and only the files in
-finished-subdirectory remain.
-
-Clean up:
-
-    >>> shutil.rmtree(verynewpath)
Index: in/waeup.custom/trunk/src/waeup/custom/frontpage.rst
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/frontpage.rst	(revision 6880)
+++ 	(revision )
@@ -1,31 +1,0 @@
-This is the default frontpage of the portal written
-in `reStructuredText (reST)
-<http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
-markup language.
-
-Some more reST examples for getting started:
-
-1. Heading
-==========
-
-Text
-
-1.2 Heading
------------
-
-Text
-
-2. Heading
-==========
-
-Text
-
-2.1 Heading
------------
-
-Text
-
-2.2 Heading
------------
-
-Text
Index: in/waeup.custom/trunk/src/waeup/custom/imagestorage.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/imagestorage.py	(revision 6880)
+++ 	(revision )
@@ -1,217 +1,0 @@
-##
-## imagestorage.py
-## Login : <uli@pu.smp.net>
-## Started on  Mon Jul  4 16:02:14 2011 Uli Fouquet
-## $Id$
-## 
-## Copyright (C) 2011 Uli Fouquet
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-## 
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-## 
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##
-"""A storage for image files.
-"""
-import grok
-import hashlib
-import os
-import transaction
-import warnings
-from StringIO import StringIO
-from ZODB.blob import Blob
-from persistent import Persistent
-from hurry.file.interfaces import IFileRetrieval
-from waeup.sirp.image import WAeUPImageFile
-from waeup.sirp.utils.helpers import cmp_files
-
-def md5digest(fd):
-    """Get an MD5 hexdigest for the file stored in `fd`.
-
-    `fd`
-      a file object open for reading.
-
-    """
-    return hashlib.md5(fd.read()).hexdigest()
-
-class Basket(grok.Container):
-    """A basket holds a set of image files with same hash.
-    """
-
-    def _del(self):
-        """Remove temporary files associated with local blobs.
-
-        A basket holds files as Blob objects. Unfortunately, if a
-        basket was not committed (put into ZODB), those blobs linger
-        around as real files in some temporary directory and won't be
-        removed.
-
-        This is a helper function to remove all those uncommitted
-        blobs that has to be called explicitly, for instance in tests.
-        """
-        key_list = self.keys()
-        for key in key_list:
-            item = self[key]
-            if getattr(item, '_p_oid', None):
-                # Don't mess around with blobs in ZODB
-                continue
-            fd = item.open('r')
-            name = getattr(fd, 'name', None)
-            fd.close()
-            if name is not None and os.path.exists(name):
-                os.unlink(name)
-            del self[key]
-        return
-
-    def getInternalId(self, fd):
-        """Get the basket-internal id for the file stored in `fd`.
-
-        `fd` must be a file open for reading. If an (byte-wise) equal
-        file can be found in the basket, its internal id (basket id)
-        is returned, ``None`` otherwise.
-        """
-        fd.seek(0)
-        for key, val in self.items():
-            fd_stored = val.open('r')
-            file_len = os.stat(fd_stored.name)[6]
-            if file_len == 0:
-                # Nasty workaround. Blobs seem to suffer from being emptied
-                # accidentally.
-                site = grok.getSite()
-                if site is not None:
-                    site.logger.warn(
-                        'Empty Blob detected: %s' % fd_stored.name)
-                warnings.warn("EMPTY BLOB DETECTED: %s" % fd_stored.name)
-                fd_stored.close()
-                val.open('w').write(fd.read())
-                return key
-            fd_stored.seek(0)
-            if cmp_files(fd, fd_stored):
-                fd_stored.close()
-                return key
-            fd_stored.close()
-        return None
-
-    @property
-    def curr_id(self):
-        """The current basket id.
-
-        An integer number which is not yet in use. If there are
-        already `maxint` entries in the basket, a :exc:`ValueError` is
-        raised. The latter is _highly_ unlikely. It would mean to have
-        more than 2**32 hash collisions, i.e. so many files with the
-        same MD5 sum.
-        """
-        num = 1
-        while True:
-            if str(num) not in self.keys():
-                return str(num)
-            num += 1
-            if num <= 0:
-                name = getattr(self, '__name__', None)
-                raise ValueError('Basket full: %s' % name)
-
-    def storeFile(self, fd, filename):
-        """Store the file in `fd` into the basket.
-
-        The file will be stored in a Blob.
-        """
-        fd.seek(0)
-        internal_id = self.getInternalId(fd) # Moves file pointer!
-        if internal_id is None:
-            internal_id = self.curr_id
-            fd.seek(0)
-            self[internal_id] = Blob()
-            transaction.commit() # Urgently needed to make the Blob
-                                 # persistent. Took me ages to find
-                                 # out that solution, which makes some
-                                 # design flaw in ZODB Blobs likely.
-            self[internal_id].open('w').write(fd.read())
-            fd.seek(0)
-            self._p_changed = True
-        return internal_id
-
-    def retrieveFile(self, basket_id):
-        """Retrieve a file open for reading with basket id `basket_id`.
-
-        If there is no such id, ``None`` is returned. It is the
-        callers responsibility to close the open file.
-        """
-        if basket_id in self.keys():
-            return self[basket_id].open('r')
-        return None
-
-class ImageStorage(grok.Container):
-    """A container for image files.
-    """
-    def _del(self):
-        for basket in self.values():
-            try:
-                basket._del()
-            except:
-                pass
-
-    def storeFile(self, fd, filename):
-        fd.seek(0)
-        digest = md5digest(fd)
-        fd.seek(0)
-        if not digest in self.keys():
-            self[digest] = Basket()
-        basket_id = self[digest].storeFile(fd, filename)
-        full_id = "%s-%s" % (digest, basket_id)
-        return full_id
-
-    def retrieveFile(self, file_id):
-        if not '-' in file_id:
-            return None
-        full_id, basket_id = file_id.split('-', 1)
-        if not full_id in self.keys():
-            return None
-        return self[full_id].retrieveFile(basket_id)
-
-class ImageStorageFileRetrieval(Persistent):
-    grok.implements(IFileRetrieval)
-
-    def getImageStorage(self):
-        site = grok.getSite()
-        if site is None:
-            return None
-        return site.get('images', None)
-
-    def isImageStorageEnabled(self):
-        site = grok.getSite()
-        if site is None:
-            return False
-        if site.get('images', None) is None:
-            return False
-        return True
-
-    def getFile(self, data):
-        # ImageStorage is disabled, so give fall-back behaviour for
-        # testing without ImageStorage
-        if not self.isImageStorageEnabled():
-            return StringIO(data)
-        storage = self.getImageStorage()
-        if storage is None:
-            raise ValueError('Cannot find an image storage')
-        result = storage.retrieveFile(data)
-        if result is None:
-            return StringIO(data)
-        return storage.retrieveFile(data)
-
-    def createFile(self, filename, f):
-        if not self.isImageStorageEnabled():
-            return WAeUPImageFile(filename, f.read())
-        storage = self.getImageStorage()
-        if storage is None:
-            raise ValueError('Cannot find an image storage')
-        file_id = storage.storeFile(f, filename)
-        return WAeUPImageFile(filename, file_id)
Index: in/waeup.custom/trunk/src/waeup/custom/index.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/index.txt	(revision 6880)
+++ 	(revision )
@@ -1,30 +1,0 @@
-Welcome to waeup documentation!
-*******************************
-
-Contents:
-
-.. toctree::
-   :maxdepth: 2
-
-   README
-   doc/developernotes
-
-API documentation
-=================
-
-.. toctree::
-   :maxdepth: 1
-
-   app
-   catalog
-   accesscodes/api.txt
-   jambtables/api.txt
-   university/api.txt
-   utils/api.txt
-
-Indices and tables
-==================
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
Index: in/waeup.custom/trunk/src/waeup/custom/interfaces.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/interfaces.py	(revision 6880)
+++ 	(revision )
@@ -1,499 +1,0 @@
-##
-## interfaces.py
-import os
-from hurry.workflow.interfaces import IWorkflow, IWorkflowInfo
-from zc.sourcefactory.basic import BasicSourceFactory
-from zope import schema
-from zope.component import getUtility
-from zope.component.interfaces import IObjectEvent
-from zope.interface import Interface, Attribute, implements
-from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
-
-default_frontpage = u'' + open(os.path.join(
-        os.path.dirname(__file__), 'frontpage.rst'), 'rb').read()
-
-class FatalCSVError(Exception):
-    """Some row could not be processed.
-    """
-    pass
-
-class DuplicationError(Exception):
-    """An exception that can be raised when duplicates are found.
-
-    When raising :exc:`DuplicationError` you can, beside the usual
-    message, specify a list of objects which are duplicates. These
-    values can be used by catching code to print something helpful or
-    similar.
-    """
-    def __init__(self, msg, entries=[]):
-        self.msg = msg
-        self.entries = entries
-
-    def __str__(self):
-        return '%r' % self.msg
-
-def SimpleWAeUPVocabulary(*terms):
-    """A well-buildt vocabulary provides terms with a value, token and
-       title for each term
-    """
-    return SimpleVocabulary([
-            SimpleTerm(value, value, title) for title, value in terms])
-
-class RoleSource(BasicSourceFactory):
-    """A source for global roles.
-    """
-    def getValues(self):
-        # late import: in interfaces we should not import local modules
-        from waeup.sirp.permissions import getWAeUPRoleNames
-        return getWAeUPRoleNames()
-
-    def getTitle(self, value):
-        # late import: in interfaces we should not import local modules
-        from waeup.sirp.permissions import getRoles
-        roles = dict(getRoles())
-        if value in roles.keys():
-            title = roles[value].title
-            if '.' in title:
-                title = title.split('.', 2)[1]
-        return title
-
-class IWAeUPObject(Interface):
-    """A WAeUP object.
-
-    This is merely a marker interface.
-    """
-
-class IUniversity(IWAeUPObject):
-    """Representation of a university.
-    """
-    name = schema.TextLine(
-        title = u'Name of University',
-        default = u'Sample University',
-        required = True,
-        )
-
-    title = schema.TextLine(
-        title = u'Title of frontpage',
-        default = u'Welcome to the Student Information and Registration ' +
-                  u'Portal of Sample University',
-        required = False,
-        )
-
-    skin = schema.Choice(
-        title = u'Skin',
-        default = u'waeuptheme-gray1.css',
-        vocabulary = 'waeup.sirp.browser.theming.ThemesVocabulary',
-        required = True,
-        )
-
-    frontpage = schema.Text(
-        title = u'Content in reST format',
-        required = False,
-        default = default_frontpage,
-        )
-
-
-class IWAeUPContainer(IWAeUPObject):
-    """A container for WAeUP objects.
-    """
-
-class IWAeUPContained(IWAeUPObject):
-    """An item contained in an IWAeUPContainer.
-    """
-
-class IStudentContainer(IWAeUPContainer):
-    """A container for StudentObjects.
-    """
-
-
-class IHostelContainer(IWAeUPContainer):
-    """A container for hostels.
-    """
-    def addHostel(hostel):
-        """Add an IHostel object.
-
-        Returns the key, under which the object was stored.
-        """
-
-class IHostel(IWAeUPObject):
-    """Representation of a hostel.
-    """
-    name = schema.TextLine(
-        title = u'Name of Hostel',
-        default = u'Nobody',
-        required = True,
-        )
-
-
-class IWAeUPExporter(Interface):
-    """An exporter for objects.
-    """
-    def export(obj, filepath=None):
-        """Export by pickling.
-
-        Returns a file-like object containing a representation of `obj`.
-
-        This is done using `pickle`. If `filepath` is ``None``, a
-        `cStringIO` object is returned, that contains the saved data.
-        """
-
-class IWAeUPXMLExporter(Interface):
-    """An XML exporter for objects.
-    """
-    def export(obj, filepath=None):
-        """Export as XML.
-
-        Returns an XML representation of `obj`.
-
-        If `filepath` is ``None``, a StringIO` object is returned,
-        that contains the transformed data.
-        """
-
-class IWAeUPXMLImporter(Interface):
-    """An XML import for objects.
-    """
-    def doImport(filepath):
-        """Create Python object from XML.
-
-        Returns a Python object.
-        """
-
-class IBatchProcessor(Interface):
-    """A batch processor that handles mass-operations.
-    """
-    name = schema.TextLine(
-        title = u'Importer name'
-        )
-
-    mode = schema.Choice(
-        title = u'Import mode',
-        values = ['create', 'update', 'remove']
-        )
-
-    def doImport(path, headerfields, mode='create', user='Unknown',
-                 logger=None):
-        """Read data from ``path`` and update connected object.
-
-        `headerfields` is a list of headerfields as read from the file
-        to import.
-
-        `mode` gives the import mode to use (``'create'``,
-        ``'update'``, or ``'remove'``.
-
-        `user` is a string describing the user performing the
-        import. Normally fetched from current principal.
-
-        `logger` is the logger to use during import.
-        """
-
-class IUserAccount(IWAeUPObject):
-    """A user account.
-    """
-    name = schema.TextLine(
-        title = u'User ID',
-        description = u'Login name of user',
-        required = True,)
-    title = schema.TextLine(
-        title = u'Name',
-        description = u'Real name of user',
-        required = False,)
-    description = schema.TextLine(
-        title = u'Description',
-        required = False,)
-    password = schema.Password(
-        title = u'Password',
-        required = True,)
-    roles = schema.List(
-        title = u'Global roles',
-        value_type = schema.Choice(source=RoleSource()))
-
-
-class IUserContainer(IWAeUPObject):
-    """A container for users (principals).
-
-    These users are used for authentication purposes.
-    """
-
-    def addUser(name, password, title=None, description=None):
-        """Add a user.
-        """
-
-    def delUser(name):
-        """Delete a user if it exists.
-        """
-
-class ILocalRolesAssignable(Interface):
-    """The local roles assignable to an object.
-    """
-    def __call__():
-        """Returns a list of dicts.
-
-        Each dict contains a ``name`` referring to the role assignable
-        for the specified object and a `title` to describe the range
-        of users to which this role can be assigned.
-        """
-
-class IDataCenter(IWAeUPObject):
-    """A data center.
-
-    TODO : declare methods, at least those needed by pages.
-    """
-    pass
-
-class IDataCenterFile(Interface):
-    """A data center file.
-    """
-
-    name = schema.TextLine(
-        title = u'Filename')
-
-    size = schema.TextLine(
-        title = u'Human readable file size')
-
-    uploaddate = schema.TextLine(
-        title = u'Human readable upload datetime')
-
-    lines = schema.Int(
-        title = u'Number of lines in file')
-
-    def getDate():
-        """Get creation timestamp from file in human readable form.
-        """
-
-    def getSize():
-        """Get human readable size of file.
-        """
-
-    def getLinesNumber():
-        """Get number of lines of file.
-        """
-
-class IDataCenterStorageMovedEvent(IObjectEvent):
-    """Emitted, when the storage of a datacenter changes.
-    """
-
-class IObjectUpgradeEvent(IObjectEvent):
-    """Can be fired, when an object shall be upgraded.
-    """
-
-class ILocalRoleSetEvent(IObjectEvent):
-    """A local role was granted/revoked for a principal on an object.
-    """
-    role_id = Attribute(
-        "The role id that was set.")
-    principal_id = Attribute(
-        "The principal id for which the role was granted/revoked.")
-    granted = Attribute(
-        "Boolean. If false, then the role was revoked.")
-
-class IQueryResultItem(Interface):
-    """An item in a search result.
-    """
-    url = schema.TextLine(
-        title = u'URL that links to the found item')
-    title = schema.TextLine(
-        title = u'Title displayed in search results.')
-    description = schema.Text(
-        title = u'Longer description of the item found.')
-
-class IWAeUPSIRPPluggable(Interface):
-    """A component that might be plugged into a WAeUP SIRP app.
-
-    Components implementing this interface are referred to as
-    'plugins'. They are normally called when a new
-    :class:`waeup.sirp.app.University` instance is created.
-
-    Plugins can setup and update parts of the central site without the
-    site object (normally a :class:`waeup.sirp.app.University` object)
-    needing to know about that parts. The site simply collects all
-    available plugins, calls them and the plugins care for their
-    respective subarea like the applicants area or the datacenter
-    area.
-
-    Currently we have no mechanism to define an order of plugins. A
-    plugin should therefore make no assumptions about the state of the
-    site or other plugins being run before and instead do appropriate
-    checks if necessary.
-
-    Updates can be triggered for instance by the respective form in
-    the site configuration. You normally do updates when the
-    underlying software changed.
-    """
-    def setup(site, name, logger):
-        """Create an instance of the plugin.
-
-        The method is meant to be called by the central app (site)
-        when it is created.
-
-        `site`:
-           The site that requests a setup.
-
-        `name`:
-           The name under which the plugin was registered (utility name).
-
-        `logger`:
-           A standard Python logger for the plugins use.
-        """
-
-    def update(site, name, logger):
-        """Method to update an already existing plugin.
-
-        This might be called by a site when something serious
-        changes. It is a poor-man replacement for Zope generations
-        (but probably more comprehensive and better understandable).
-
-        `site`:
-           The site that requests an update.
-
-        `name`:
-           The name under which the plugin was registered (utility name).
-
-        `logger`:
-           A standard Python logger for the plugins use.
-        """
-
-class IAuthPluginUtility(Interface):
-    """A component that cares for authentication setup at site creation.
-
-    Utilities providing this interface are looked up when a Pluggable
-    Authentication Utility (PAU) for any
-    :class:`waeup.sirp.app.University` instance is created and put
-    into ZODB.
-
-    The setup-code then calls the `register` method of the utility and
-    expects a modified (or unmodified) version of the PAU back.
-
-    This allows to define any authentication setup modifications by
-    submodules or third-party modules/packages.
-    """
-
-    def register(pau):
-        """Register any plugins wanted to be in the PAU.
-        """
-
-    def unregister(pau):
-        """Unregister any plugins not wanted to be in the PAU.
-        """
-
-class IObjectConverter(Interface):
-    """Object converters are available as simple adapters, adapting
-       interfaces (not regular instances).
-
-    """
-
-    def fromStringDict(self, data_dict, context, form_fields=None):
-        """Convert values in `data_dict`.
-
-        Converts data in `data_dict` into real values based on
-        `context` and `form_fields`.
-
-        `data_dict` is a mapping (dict) from field names to values
-        represented as strings.
-
-        The fields (keys) to convert can be given in optional
-        `form_fields`. If given, form_fields should be an instance of
-        :class:`zope.formlib.form.Fields`. Suitable instances are for
-        example created by :class:`grok.AutoFields`.
-
-        If no `form_fields` are given, a default is computed from the
-        associated interface.
-
-        The `context` can be an existing object (implementing the
-        associated interface) or a factory name. If it is a string, we
-        try to create an object using
-        :func:`zope.component.createObject`.
-
-        Returns a tuple ``(<FIELD_ERRORS>, <INVARIANT_ERRORS>,
-        <DATA_DICT>)`` where
-
-        ``<FIELD_ERRORS>``
-           is a list of tuples ``(<FIELD_NAME>, <ERROR>)`` for each
-           error that happened when validating the input data in
-           `data_dict`
-
-        ``<INVARIANT_ERRORS>``
-           is a list of invariant errors concerning several fields
-
-        ``<DATA_DICT>``
-           is a dict with the values from input dict converted.
-
-        If errors happen, i.e. the error lists are not empty, always
-        an empty ``<DATA_DICT>`` is returned.
-
-        If ``<DATA_DICT>` is non-empty, there were no errors.
-        """
-
-class IObjectHistory(Interface):
-
-    messages = schema.List(
-        title = u'List of messages stored',
-        required = True,
-        )
-
-    def addMessage(message):
-        """Add a message.
-        """
-
-class IWAeUPWorkflowInfo(IWorkflowInfo):
-    """A :class:`hurry.workflow.workflow.WorkflowInfo` with additional
-       methods for convenience.
-    """
-    def getManualTransitions():
-        """Get allowed manual transitions.
-
-        Get a sorted list of tuples containing the `transition_id` and
-        `title` of each allowed transition.
-        """
-
-class ISiteLoggers(Interface):
-
-    loggers = Attribute("A list or generator of registered WAeUPLoggers")
-
-    def register(name, filename=None, site=None, **options):
-        """Register a logger `name` which logs to `filename`.
-
-        If `filename` is not given, logfile will be `name` with
-        ``.log`` as filename extension.
-        """
-
-    def unregister(name):
-        """Unregister a once registered logger.
-        """
-
-class ILogger(Interface):
-    """A logger cares for setup, update and restarting of a Python logger.
-    """
-
-    logger = Attribute("""A :class:`logging.Logger` instance""")
-
-
-    def __init__(name, filename=None, site=None, **options):
-        """Create a WAeUP logger instance.
-        """
-
-    def setup():
-        """Create a Python :class:`logging.Logger` instance.
-
-        The created logger is based on the params given by constructor.
-        """
-
-    def update(**options):
-        """Update the logger.
-
-        Updates the logger respecting modified `options` and changed
-        paths.
-        """
-
-class ILoggerCollector(Interface):
-
-    def getLoggers(site):
-        """Return all loggers registered for `site`.
-        """
-
-    def registerLogger(site, logging_component):
-        """Register a logging component residing in `site`.
-        """
-
-    def unregisterLogger(site, logging_component):
-        """Unregister a logger.
-        """
Index: in/waeup.custom/trunk/src/waeup/custom/meta.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/meta.py	(revision 6880)
+++ 	(revision )
@@ -1,111 +1,0 @@
-##
-## meta.py
-## Login : <uli@pu.smp.net>
-## Started on  Wed May 18 23:38:13 2011 Uli Fouquet
-## $Id$
-## 
-## Copyright (C) 2011 Uli Fouquet
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-## 
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-## 
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##
-"""Grokkers for WAeUP components.
-
-Stuff in here is mainly taken from grok.meta, with some modifications
-to provide a possibility to update catalogs in a running site. This is
-to solve the very common problem of already running sites for which
-the software changes and adds catalogs. These catalogs will not be
-automatically added in a running site.
-
-With the following Grokker and the upgrade helper class we can fire
-IObjectUpgradedEvents for any existing site and all catalogs
-registered will be really created.
-
-Please note that yet these catalogs are not filled automatically! That
-means the catalogs will exist but are empty in the beginning.
-
-We might solve this second problem by firing extra events like some
-ICatalogUpdatedEvent (which still do not exist) or similar.
-"""
-import grok
-import martian
-from grok import components
-from grok.meta import IndexesSetupSubscriber
-from martian.error import GrokError
-from zope import component
-from waeup.sirp.interfaces import IObjectUpgradeEvent
-
-class IndexesGrokker(martian.InstanceGrokker):
-    """Grokker for Grok index bundles."""
-    martian.component(components.IndexesClass)
-
-    def grok(self, name, factory, module_info, config, **kw):
-        site = grok.site.bind().get(factory)
-        context = grok.context.bind().get(factory, module_info.getModule())
-        catalog_name = grok.name.bind().get(factory)
-
-        if site is None:
-            raise GrokError("No site specified for grok.Indexes "
-                            "subclass in module %r. "
-                            "Use grok.site() to specify."
-                            % module_info.getModule(),
-                            factory)
-        indexes = getattr(factory, '__grok_indexes__', None)
-        if indexes is None:
-            return False
-
-        subscriber = WAeUPIndexesUpgradeSubscriber(
-            catalog_name, indexes, context, module_info)
-        subscribed = (site, IObjectUpgradeEvent)
-        config.action(
-            discriminator=None,
-            callable=component.provideHandler,
-            args=(subscriber, subscribed),
-            )
-        return True
-
-
-class WAeUPIndexesUpgradeSubscriber(IndexesSetupSubscriber):
-    """Helper that sets up indexes when their Grok site is upgraded.
-
-    Each `grok.Indexes` class serves as an assertion that, whenever an
-    instance of its `grok.site()` is upgraded, the given list of
-    indexes should be generated if not already created as well.  But a
-    long period of time could elapse between when the application
-    starts (and its indexes are grokked), and the moment, maybe days
-    or weeks later, when a new instance of that `grok.Site` is
-    created.  Hence this `IndexesSetupSubscriber`: it can be
-    instantiated at grokking time with the index information, and then
-    registered with the Component Architecture as an event that should
-    be fired later, whenever the right kind of `grok.Site` is
-    instantiated.  At that point its `__call__` method is kicked off
-    and it makes sure the index catalogs get created properly.
-
-    """
-    def __call__(self, site, event):
-        site.logger.info('Create catalog `%s` if not installed yet.'  % (
-                self.catalog_name,))
-        # make sure we have an intids
-        self._createIntIds(site)
-        # get the catalog
-        catalog = self._createCatalog(site)
-        # now install indexes
-        for name, index in self.indexes.items():
-            try:
-                site.logger.info('Create index `%s` in catalog' % name)
-                index.setup(catalog, name, self.context, self.module_info)
-                site.logger.info('index created.')
-            except KeyError: #, DuplicationError:
-                site.logger.info('index `%s` already in catalog' % name)
-                pass
-        site.logger.info('Catalog `%s` ready.' % self.catalog_name)
Index: in/waeup.custom/trunk/src/waeup/custom/objecthistory.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/objecthistory.py	(revision 6880)
+++ 	(revision )
@@ -1,73 +1,0 @@
-##
-## objecthistory.py
-## Login : <uli@pu.smp.net>
-## Started on  Fri Jun 10 16:06:02 2011 Uli Fouquet
-## $Id$
-## 
-## Copyright (C) 2011 Uli Fouquet
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-## 
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-## 
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##
-import grok
-from datetime import datetime
-from persistent.list import PersistentList
-from zope.annotation.interfaces import IAnnotations
-from waeup.sirp.interfaces import IObjectHistory, IWAeUPObject
-from waeup.sirp.utils.helpers import get_current_principal
-
-class ObjectHistory(grok.Adapter):
-    """A history for objects.
-
-    For any object implementing `IWAeUPObject` which is annotatable,
-    we provide histories. A history for such an object can be obtained
-    by adapting it to `IObjectHistory`.
-    """
-    grok.context(IWAeUPObject)
-    grok.implements(IObjectHistory)
-
-    history_key = 'waeup.history'
-
-    def __init__(self, context):
-        from zope.security.proxy import removeSecurityProxy
-        self.context = removeSecurityProxy(context)
-        self._annotations = IAnnotations(self.context)
-
-    def _getMessages(self):
-        return self._annotations.get(self.history_key, PersistentList())
-
-    @property
-    def messages(self):
-        """Get all messages as a persistent list of strings.
-        """
-        return self._getMessages()
-
-    def addMessage(self, msg):
-        """Add the message (history entry) in msg.
-
-        Any message will be stored with a timestamp and the current
-        user (principal).
-        """
-        msgs = self._getMessages()
-        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
-        user = get_current_principal()
-        if user is None:
-            user = 'system'
-        elif user.title == 'Applicant':
-            user = 'applicant'
-        else:
-            user = user.id
-        msg = '%s - %s by %s' % (timestamp, msg, user)
-        msgs.append(msg)
-        self._annotations[self.history_key] = msgs
-        return
Index: in/waeup.custom/trunk/src/waeup/custom/permissions.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/permissions.py	(revision 6880)
+++ 	(revision )
@@ -1,172 +1,0 @@
-import grok
-from zope.component import getUtilitiesFor
-from zope.interface import Interface
-from zope.securitypolicy.interfaces import IRole, IPrincipalRoleMap
-from waeup.sirp.interfaces import ILocalRolesAssignable
-
-class Public(grok.Permission):
-    """Everyone-can-do-this-permission.
-
-    This permission is meant to be applied to objects/views/pages
-    etc., that should be usable/readable by everyone.
-
-    We need this to be able to tune default permissions more
-    restrictive and open up some dedicated objects like the front
-    page.
-    """
-    grok.name('waeup.Public')
-
-class Anonymous(grok.Permission):
-    """Only-anonymous-can-do-this-permission.
-    """
-    grok.name('waeup.Anonymous')
-
-class ViewPermission(grok.Permission):
-    grok.name('waeup.View')
-
-class ManageUniversity(grok.Permission):
-    grok.name('waeup.manageUniversity')
-
-class ManageUsers(grok.Permission):
-    grok.name('waeup.manageUsers')
-
-class ManageDataCenter(grok.Permission):
-    grok.name('waeup.manageDataCenter')
-
-class ManagePortalSettings(grok.Permission):
-    grok.name('waeup.managePortalSettings')
-
-# Local Roles
-class DepartmentOfficer(grok.Role):
-    grok.name('waeup.local.DepartmentOfficer')
-    grok.title(u'Department Officer')
-    grok.permissions('waeup.manageUniversity','waeup.View', 'waeup.Public')
-
-class ClearanceOfficer(grok.Role):
-    grok.name('waeup.local.ClearanceOfficer')
-    grok.title(u'Clearance Officer')
-    # to be further defined
-    grok.permissions('waeup.View', 'waeup.Public')
-
-class CourseAdviser(grok.Role):
-    grok.name('waeup.local.CourseAdviser')
-    grok.title(u'Course Adviser')
-    # to be further defined
-    grok.permissions('waeup.View', 'waeup.Public')
-
-# Global Roles
-class PortalUser(grok.Role):
-    grok.name('waeup.PortalUser')
-    grok.title(u'Portal User')
-    grok.permissions('waeup.View', 'waeup.Public')
-
-class PortalManager(grok.Role):
-    grok.name('waeup.PortalManager')
-    grok.title(u'Portal Manager')
-    grok.permissions('waeup.manageUniversity', 'waeup.manageUsers',
-                     'waeup.View', 'waeup.Public','waeup.manageACBatches',
-                     'waeup.manageDataCenter','waeup.managePortalSettings',
-                     'waeup.manageApplications', 'waeup.handleApplication',
-                     'waeup.viewStudents', 'waeup.manageStudents')
-
-def getRoles():
-    """Return a list of tuples ``<ROLE-NAME>, <ROLE>``.
-    """
-    return getUtilitiesFor(IRole)
-
-def getWAeUPRoles(also_local=False):
-    """Get all WAeUP roles.
-
-    WAeUP roles are ordinary roles whose id by convention starts with
-    a ``waeup.`` prefix.
-
-    If `also_local` is ``True`` (``False`` by default), also local
-    roles are returned. Local WAeUP roles are such whose id starts
-    with ``waeup.local.`` prefix (this is also a convention).
-
-    Returns a generator of the found roles.
-    """
-    for name, item in getRoles():
-        if not name.startswith('waeup.'):
-            # Ignore non-WAeUP roles...
-            continue
-        if not also_local and name.startswith('waeup.local.'):
-            # Ignore local roles...
-            continue
-        yield item
-
-def getWAeUPRoleNames():
-    """Get the ids of all WAeUP roles.
-
-    See :func:`getWAeUPRoles` for what a 'WAeUPRole' is.
-
-    This function returns a sorted list of WAeUP role names.
-    """
-    return sorted([x.id for x in getWAeUPRoles()])
-
-
-class LocalRolesAssignable(grok.Adapter):
-    """Default implementation for `ILocalRolesAssignable`.
-
-    This adapter returns a list for dictionaries for objects for which
-    we want to know the roles assignable to them locally.
-
-    The returned dicts contain a ``name`` and a ``title`` entry which
-    give a role (``name``) and a description, for which kind of users
-    the permission is meant to be used (``title``).
-
-    Having this adapter registered we make sure, that for each normal
-    object we get a valid `ILocalRolesAssignable` adapter.
-
-    Objects that want to offer certain local roles, can do so by
-    setting a (preferably class-) attribute to a list of role ids.
-
-    You can also define different adapters for different contexts to
-    have different role lookup mechanisms become available. But in
-    normal cases it should be sufficient to use this basic adapter.
-    """
-    grok.context(Interface)
-    grok.provides(ILocalRolesAssignable)
-
-    _roles = []
-
-    def __init__(self, context):
-        self.context = context
-        role_ids = getattr(context, 'local_roles', self._roles)
-        self._roles = [(name, role) for name, role in getRoles()
-                       if name in role_ids]
-        return
-
-    def __call__(self):
-        """Get a list of dictionaries containing ``names`` (the roles to
-        assign) and ``titles`` (some description of the type of user
-        to assign each role to).
-        """
-        return [
-            dict(
-                name=name,
-                title=role.title,
-                description=role.description)
-            for name, role in self._roles]
-
-def get_users_with_local_roles(context):
-    """Get a list of dicts representing the local roles set for `context`.
-
-    Each dict returns `user_name`, `user_title`, `local_role`,
-    `local_role_title`, and `setting` for each entry in the local
-    roles map of the `context` object.
-    """
-    try:
-        role_map = IPrincipalRoleMap(context)
-    except TypeError:
-        # no map no roles.
-        raise StopIteration
-    for local_role, user_name, setting in role_map.getPrincipalsAndRoles():
-        user = grok.getSite()['users'].get(user_name,None)
-        user_title = getattr(user, 'description', user_name)
-        local_role_title = dict(getRoles())[local_role].title
-        yield dict(user_name = user_name,
-                   user_title = user_title,
-                   local_role = local_role,
-                   local_role_title = local_role_title,
-                   setting = setting)
Index: in/waeup.custom/trunk/src/waeup/custom/permissions.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/permissions.txt	(revision 6880)
+++ 	(revision )
@@ -1,75 +1,0 @@
-WAeUP permissions and roles
-***************************
-
-Permissions and roles used in a WAeUP portal.
-
-.. :doctest:
-.. :layer: waeup.sirp.testing.WAeUPSIRPUnitTestLayer
-
-Convenience functions
-=====================
-
-:mod:`waeup.sirp` offers some convenience functions to handle security
-roles.
-
-:func:`getRoles`
-----------------
-
-Gives us all roles defined in a WAeUP SIRP portal. We get tuples of
-kind
-
-  ``(<ROLE-NAME>, <ROLE>)``
-
-where ``<ROLE-NAME>`` is the name under which a role was registered
-with the ZCA (a string) and ``<ROLE>`` is the real role object.
-
-    >>> from waeup.sirp.permissions import getRoles
-    >>> getRoles()
-    <generator object...at 0x...>
-
-    >>> sorted(list(getRoles()))
-    [(u'waeup.ApplicationsOfficer', <waeup.sirp.applicants.permissions.ApplicationsOfficer object at 0x...>), ...]
-
-:func:`getWAeUPRoles`
----------------------
-
-Gives us all roles, except the WAeUP specific roles. We can get a list
-with or without local roles:
-
-    >>> from waeup.sirp.permissions import getWAeUPRoles
-    >>> len(list(getWAeUPRoles()))
-    5
-
-    >>> len(list(getWAeUPRoles(also_local=True)))
-    10
-
-
-:func:`getRoleNames`
---------------------
-
-We can get all role names defined in a WAeUP portal (except 'local'
-roles that are meant not to be assigned globally):
-
-    >>> from waeup.sirp.permissions import getWAeUPRoleNames
-    >>> list(getWAeUPRoleNames())
-    [u'waeup.ApplicationsOfficer', u'waeup.PortalManager',
-     u'waeup.PortalUser', u'waeup.Student', u'waeup.StudentsOfficer']
-
-:func:`get_users_with_local_roles`
-----------------------------------
-
-We can get all users and their roles for a certain context
-object. This even works for objects that cannot have local roles as
-they are not stored in the ZODB:
-
-    >>> from waeup.sirp.permissions import get_users_with_local_roles
-    >>> mycontext = object()
-    >>> people_and_roles = get_users_with_local_roles(mycontext)
-    >>> people_and_roles
-    <generator object...at 0x...>
-
-In this case, the result is empty:
-
-    >>> people_and_roles = list(people_and_roles)
-    >>> people_and_roles
-    []
Index: in/waeup.custom/trunk/src/waeup/custom/testing.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/testing.py	(revision 6880)
+++ 	(revision )
@@ -1,384 +1,0 @@
-"""Testing support for :mod:`waeup.sirp`.
-"""
-import grok
-import doctest
-import logging
-import os.path
-import re
-import unittest
-import warnings
-import zope.component
-import waeup.sirp
-from zope.app.testing.functional import (
-    ZCMLLayer, FunctionalTestSetup, getRootFolder, sync, FunctionalTestCase)
-from zope.component import getGlobalSiteManager
-from zope.security.testing import addCheckerPublic
-from zope.testing import renormalizing
-from zope.testing.cleanup import cleanUp
-
-ftesting_zcml = os.path.join(
-    os.path.dirname(waeup.sirp.__file__), 'ftesting.zcml')
-FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer',
-                            allow_teardown=True)
-
-def get_all_loggers():
-    """Get the keys of all logger defined globally.
-    """
-    result = logging.root.manager.loggerDict.keys()
-    ws_loggers = [x for x in result if 'waeup.sirp' in x]
-    if ws_loggers:
-        # For debugging: show any remaining loggers from w.s. namespace
-        print "\nLOGGERS: ", ws_loggers
-    return result
-
-def remove_new_loggers(old_loggers):
-    """Remove the loggers except `old_loggers`.
-
-    `old_loggers` is a list of logger keys as returned by
-    :func:`get_all_loggers`. All globally registered loggers whose
-    name is not in `old_loggers` is removed.
-    """
-    new_loggers = [key for key in logging.root.manager.loggerDict
-                   if key not in old_loggers]
-    for key in new_loggers:
-        logger = logging.getLogger(key)
-        for handler in logger.handlers:
-            handler.close()
-        del logger
-        del logging.root.manager.loggerDict[key]
-    return
-
-def remove_logger(name):
-    """Remove logger with name `name`.
-
-    Use is safe. If the logger does not exist nothing happens.
-    """
-    if name in logging.root.manager.loggerDict.keys():
-        del logging.root.manager.loggerDict[name]
-    return
-
-
-def setUpZope(test=None):
-    """Initialize a Zope-compatible environment.
-
-    Currently, we only initialize the event machinery.
-    """
-    zope.component.eventtesting.setUp(test)
-
-def cleanUpZope(test=None):
-    """Clean up Zope-related registrations.
-
-    Cleans up all registrations and the like.
-    """
-    cleanUp()
-
-def maybe_grok():
-    """Try to grok the :mod:`waeup.sirp` package.
-
-    For many tests, even simple ones, we want the components defined
-    somewhere in the :mod:`waeup.sirp` package being registered. While
-    grokking the complete package can become expensive when done many
-    times, we only want to grok if it did not happen
-    before. Furthermore regrokking the whole package makes no sense if
-    done already.
-
-    :func:`maybe_grok` checks whether any eventhandlers are already
-    registered and does nothing in that case.
-
-    The grokking of :mod:`waeup.sirp` is done with warnings disabled.
-
-    Returns ``True`` if grokking was done, ``False`` else.
-
-    .. The following samples should go into Sphinx docs directly....
-
-    Sample
-    ******
-
-    Usage with plain Python testrunners
-    -----------------------------------
-
-    Together with the :func:`setUpZope` and :func:`cleanUpZope`
-    functions we then can do unittests with all components registered
-    and the event dispatcher in place like this::
-
-      import unittest2 as unittest # Want Python 2.7 features
-      from waeup.sirp.testing import (
-        maybe_grok, setUpZope, cleanUpZope,
-        )
-      from waeup.sirp.app import University
-
-      class MyTestCase(unittest.TestCase):
-
-          @classmethod
-          def setUpClass(cls):
-              grokked = maybe_grok()
-              if grokked:
-                  setUpZope(None)
-              return
-
-          @classmethod
-          def tearDownClass(cls):
-              cleanUpZope(None)
-
-          def setUp(self):
-              pass
-
-          def tearDown(self):
-              pass
-
-          def test_jambdata_in_site(self):
-              u = University()
-              self.assertTrue('jambdata' in u.keys())
-              return
-
-    Here the component registration is done only once for the whole
-    :class:`unittest.TestCase` and no ZODB is needed. That means
-    inside the tests you can expect to have all :mod:`waeup.sirp`
-    components (utilities, adapter, events) registered but as objects
-    have here still have no place inside a ZODB things like 'browsing'
-    won't work out of the box. The benefit is the faster test
-    setup/teardown.
-
-    .. note:: This works only with the default Python testrunners.
-
-         If you use the Zope testrunner (from :mod:`zope.testing`)
-         then you have to use appropriate layers like the
-         :class:`waeup.sirp.testing.WAeUPSIRPUnitTestLayer`.
-
-    Usage with :mod:`zope.testing` testrunners
-    ------------------------------------------
-
-    If you use the standard Zope testrunner, classmethods like
-    `setUpClass` are not executed. Instead you have to use a layer
-    like the one defined in this module.
-
-    .. seealso:: :class:`waeup.sirp.testing.WAeUPSIRPUnitTestLayer`
-
-    """
-    gsm =  getGlobalSiteManager()
-    # If there are any event handlers registered already, we assume
-    # that waeup.sirp was grokked already. There might be a batter
-    # check, though.
-    if len(list(gsm.registeredHandlers())) > 0:
-        return False
-    # Register the zope.Public permission, normally done via ZCML setup.
-    addCheckerPublic()
-    warnings.simplefilter('ignore') # disable (erraneous) warnings
-    grok.testing.grok('waeup.sirp')
-    warnings.simplefilter('default') # reenable warnings
-    return True
-
-
-class WAeUPSIRPUnitTestLayer(object):
-    """A layer for tests that groks `waeup.sirp`.
-
-    A Zope test layer that registers all :mod:`waeup.sirp` components
-    before attached tests are run and cleans this registrations up
-    afterwards. Also basic (non-waeup.sirp) components like the event
-    dispatcher machinery are registered, set up and cleaned up.
-
-    This layer does not provide a complete ZODB setup (and is
-    therefore much faster than complete functional setups) but does
-    only the registrations (which also takes some time, so running
-    this layer is slower than test cases that need none or only a
-    few registrations).
-
-    The registrations are done for all tests the layer is attached to
-    once before all these tests are run (and torn down once
-    afterwards).
-
-    To make use of this layer, you have to write a
-    :mod:`unittest.TestCase` class that provides an attribute called
-    ``layer`` with this class as value like this::
-
-      import unittest
-      from waeup.sirp.testing import WAeUPSIRPUnitTestLayer
-
-      class MyTestCase(unittest.TestCase):
-
-          layer = WAeUPSIRPUnitTestLayer
-
-          # per-test setups and real tests go here...
-          def test_foo(self):
-              self.assertEqual(1, 1)
-              return
-
-    """
-    @classmethod
-    def setUp(cls):
-        #setUpZope(None)
-        grokked = maybe_grok()
-        if grokked:
-            pass
-            #setUpZope(None)
-        return
-
-    @classmethod
-    def tearDown(cls):
-        cleanUpZope(None)
-
-#: This extended :class:`doctest.OutputChecker` allows the following
-#: additional matches when looking for output diffs:
-#:
-#: `N.NNN seconds`
-#:    matches strings like ``12.123 seconds``
-#:
-#: `HTTPError:`
-#:    matches ``httperror_seek_wrapper:``. This string is output by some
-#:    virtual browsers you might use in functional browser tests to signal
-#:    HTTP error state.
-#:
-#: `1034h`
-#:    is ignored. This sequence of control chars is output by some
-#:    (buggy) testrunners at beginning of output.
-#:
-#: `<10-DIGITS>`
-#:    matches a sequence of 10 digits. Useful when checking accesscode
-#:    numbers if you don't know the exact (random) code.
-#:
-#: `<YYYY-MM-DD hh:mm:ss>`
-#:    matches any date and time like `2011-05-01 12:01:32`.
-#:
-#: `<DATE-AND-TIME>`
-#:    same like ``<YYYY-MM-DD hh:mm:ss>`` but shorter.
-checker = renormalizing.RENormalizing([
-    # Relevant normalizers from zope.testing.testrunner.tests:
-    (re.compile(r'\d+[.]\d\d\d seconds'), 'N.NNN seconds'),
-    # Our own one to work around
-    # http://reinout.vanrees.org/weblog/2009/07/16/invisible-test-diff.html:
-    (re.compile(r'.*1034h'), ''),
-    (re.compile(r'httperror_seek_wrapper:'), 'HTTPError:' ),
-    (re.compile('[\d]{10}'), '<10-DIGITS>'),
-    (re.compile('\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d'), '<YYYY-MM-DD hh:mm:ss>'),
-    (re.compile('\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d'), '<DATETIME>'),
-    ])
-
-old_loggers = []
-def setUp(test):
-    old_loggers = get_all_loggers()
-    FunctionalTestSetup().setUp()
-
-def tearDown(test):
-    FunctionalTestSetup().tearDown()
-    remove_new_loggers(old_loggers)
-
-def doctestsuite_for_module(dotted_path):
-    """Create a doctest suite for the module at `dotted_path`.
-    """
-    test = doctest.DocTestSuite(
-        dotted_path,
-        setUp = setUp,
-        tearDown = tearDown,
-        checker = checker,
-        extraglobs = dict(
-            getRootFolder=getRootFolder,
-            sync=sync,),
-        optionflags = (doctest.ELLIPSIS +
-                       doctest.NORMALIZE_WHITESPACE +
-                       doctest.REPORT_NDIFF),
-        )
-    test.layer = FunctionalLayer
-    return test
-
-optionflags = (
-    doctest.REPORT_NDIFF + doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE)
-
-def clear_logger_collector():
-    from zope.component import queryUtility, getGlobalSiteManager
-    from waeup.sirp.interfaces import ILoggerCollector
-    collector = queryUtility(ILoggerCollector)
-    if collector is None:
-        return
-    keys = collector.keys()
-    for key in keys:
-        del collector[key]
-    return
-
-class FunctionalTestCase(FunctionalTestCase):
-    """A test case that supports checking output diffs in doctest style.
-    """
-
-    def setUp(self):
-        super(FunctionalTestCase, self).setUp()
-        self.functional_old_loggers = get_all_loggers()
-        return
-
-    def tearDown(self):
-        super(FunctionalTestCase, self).tearDown()
-        remove_new_loggers(self.functional_old_loggers)
-        clear_logger_collector()
-        return
-
-    def assertMatches(self, want, got, checker=checker,
-                      optionflags=optionflags):
-        """Assert that the multiline string `want` matches `got`.
-
-        In `want` you can use shortcuts like ``...`` as in regular doctests.
-
-        If no special `checker` is passed, we use an extended
-        :class:`doctest.OutputChecker` as defined in
-        :mod:`waeup.sirp.testing`.
-
-        If optional `optionflags` are not given, use ``REPORT_NDIFF``,
-        ``ELLIPSIS``, and ``NORMALIZE_WHITESPACE``.
-
-        .. seealso:: :data:`waeup.sirp.testing.optionflags`
-
-        .. seealso:: :data:`waeup.sirp.testing.checker`
-        """
-        if checker.check_output(want, got, optionflags):
-            return
-        diff = checker.output_difference(
-            doctest.Example('', want), got, optionflags)
-        self.fail(diff)
-
-class FunctionalTestSetup(FunctionalTestSetup):
-    """A replacement for the zope.app.testing class.
-
-    Removes also loggers.
-    """
-
-    def setUp(self):
-        self.old_loggers = get_all_loggers()
-        super(FunctionalTestSetup, self).setUp()
-        return
-
-    def tearDown(self):
-        super(FunctionalTestSetup, self).tearDown()
-        remove_new_loggers(self.old_loggers)
-        return
-
-def get_doctest_suite(filename_list=[]):
-    """Helper function to create doctest suites for doctests.
-
-    The `filename_list` is a list of filenames relative to the
-    w.s. dir.  So, to get a doctest suite for ``browser.txt`` and
-    ``blah.txt`` in the ``browser/`` subpackage you have to pass
-    ``filename_list=['browser/browser.txt','browser/blah.txt']`` and
-    so on.
-
-    The returned test suite must be registered somewhere locally for
-    instance by something like:
-
-      from waeup.sirp.testing import get_doctest_suite
-      def test_suite():
-        suite = get_doctest_suite(['mypkg/foo.txt', 'mypkg/bar.txt'])
-        return suite
-
-    and that's it.
-    """
-    suite = unittest.TestSuite()
-    for filename in filename_list:
-        path = os.path.join(
-            os.path.dirname(__file__), filename)
-        test = doctest.DocFileSuite(
-            path,
-            module_relative=False,
-            setUp=setUp, tearDown=tearDown,
-            globs = dict(getRootFolder = getRootFolder),
-            optionflags = doctest.ELLIPSIS + doctest.NORMALIZE_WHITESPACE,
-            checker = checker,
-            )
-        test.layer = FunctionalLayer
-        suite.addTest(test)
-    return suite
Index: in/waeup.custom/trunk/src/waeup/custom/users.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/users.py	(revision 6880)
+++ 	(revision )
@@ -1,75 +1,0 @@
-"""Users (principals) for the WAeUP portal.
-"""
-import grok
-from zope.event import notify
-from zope.interface import Interface
-from zope.securitypolicy.interfaces import IPrincipalRoleMap
-from waeup.sirp.authentication import Account
-from waeup.sirp.interfaces import IUserContainer, ILocalRoleSetEvent
-
-class UserContainer(grok.Container):
-    """A container for principals.
-
-    See interfaces.py and users.txt for extensive description.
-    """
-    grok.implements(IUserContainer)
-    grok.require('waeup.manageUsers')
-
-    def addUser(self, name, password, title=None, description=None, roles=[]):
-        """Add a new Account instance, created from parameters.
-        """
-        if title is None:
-            title = name
-        if description is None:
-            description = title
-        self[name] = Account(name, password, title, description, roles)
-
-    def addAccount(self, account):
-        """Add the account passed.
-        """
-        self[account.name] = account
-
-    def delUser(self, name):
-        """Delete user, if an account with the given name exists.
-
-        Do not complain, if the name does not exist.
-        """
-        if name in self.keys():
-            del self[name]
-
-class LocalRoleSetEvent(object):
-
-    grok.implements(ILocalRoleSetEvent)
-
-    def __init__(self, object, role_id, principal_id, granted=True):
-        self.object = object
-        self.role_id = role_id
-        self.principal_id = principal_id
-        self.granted = granted
-
-@grok.subscribe(Interface, ILocalRoleSetEvent)
-def handle_local_role_changed(obj, event):
-    site = grok.getSite()
-    if site is None:
-        return
-    users = site.get('users', None)
-    if users is None:
-        return
-    role_id = event.role_id
-    if event.principal_id not in users.keys():
-        return
-    user = users[event.principal_id]
-    user.notifyLocalRoleChanged(event.object, event.role_id, event.granted)
-    return
-
-@grok.subscribe(Interface, grok.IObjectRemovedEvent)
-def handle_local_roles_on_obj_removed(obj, event):
-    try:
-        role_map = IPrincipalRoleMap(obj)
-    except TypeError:
-        # no map, no roles to remove
-        return
-    for local_role, user_name, setting in role_map.getPrincipalsAndRoles():
-        notify(LocalRoleSetEvent(
-                obj, local_role, user_name, granted=False))
-    return
Index: in/waeup.custom/trunk/src/waeup/custom/users.txt
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/users.txt	(revision 6880)
+++ 	(revision )
@@ -1,68 +1,0 @@
-User for the WAeUP portal
-*************************
-
-.. :doctest:
-.. :layer: waeup.sirp.testing.WAeUPSIRPUnitTestLayer
-
-Before we can start, we need some password managers available:
-
-    >>> from zope.app.authentication.placelesssetup import (
-    ...   PlacelessSetup)
-    >>> PlacelessSetup().setUp()
-
-User Containers
-===============
-
-We can create a user container which will hold the useraccounts for
-us:
-
-    >>> from waeup.sirp.users import UserContainer
-    >>> myusers = UserContainer()
-
-We can add users, just by passing a name, a password, and (optionally)
-a title and a description:
-
-    >>> myusers.addUser('bob', 'bobssecret')
-
-Now, Bob is in the container:
-
-    >>> list(myusers)
-    [u'bob']
-
-We can get Bob's account:
-
-    >>> bob = myusers['bob']
-    >>> bob
-    <waeup.sirp.authentication.Account object at 0x...>
-
-    >>> bob.name
-    'bob'
-
-    >>> bob.title
-    'bob'
-
-    >>> bob.description
-    'bob'
-
-As we did not give a title nor description, the name was taken instead
-for these values. The password, however, is stored encoded:
-
-    >>> bob.password
-    '...15aca8166'
-
-Remark: that we can tell the last chars of the 'encrypted' password,
-means, that the encryption is broken or at least waeker as it should
-be.
-
-XXX: We could provide a stronger (correct) SHA encryption.
-
-We can delete users:
-
-    >>> myusers.delUser('alice')
-
-The container won't complain, although there is no ``alice`` stored
-yet. But we can really delete users:
-
-    >>> myusers.delUser('bob')
-    >>> list(myusers)
-    []
Index: in/waeup.custom/trunk/src/waeup/custom/workflow.py
===================================================================
--- /main/waeup.custom/trunk/src/waeup/custom/workflow.py	(revision 6880)
+++ 	(revision )
@@ -1,96 +1,0 @@
-##
-## workflow.py
-## Login : <uli@pu.smp.net>
-## Started on  Sat Jun 11 19:52:12 2011 Uli Fouquet
-## $Id$
-## 
-## Copyright (C) 2011 Uli Fouquet
-## This program is free software; you can redistribute it and/or modify
-## it under the terms of the GNU General Public License as published by
-## the Free Software Foundation; either version 2 of the License, or
-## (at your option) any later version.
-## 
-## This program is distributed in the hope that it will be useful,
-## but WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-## GNU General Public License for more details.
-## 
-## You should have received a copy of the GNU General Public License
-## along with this program; if not, write to the Free Software
-## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-##
-"""Workflow components of general use.
-"""
-import grok
-from hurry.workflow.interfaces import IWorkflow, MANUAL, InvalidTransitionError
-from hurry.workflow.workflow import (
-    Transition, Workflow, WorkflowVersions, WorkflowInfo,
-    NullCondition, nullCheckPermission)
-from zope.security.interfaces import NoInteraction
-from zope.security.management import getInteraction
-from waeup.sirp.interfaces import IWAeUPWorkflowInfo
-
-class WAeUPWorkflow(Workflow):
-    """A :mod:`hurry.workflow` workflow with more appropriate error
-       messages.
-    """
-    grok.provides(IWorkflow)
-
-    def getTransition(self, source, transition_id):
-        transition = self._id_transitions[transition_id]
-        if transition.source != source:
-            raise InvalidTransitionError(
-                "Transition '%s' requires '%s' as source state (is: '%s')" % (
-                    transition_id, transition.source, source))
-        return transition
-
-
-class WorkflowNullVersions(WorkflowVersions):
-    """A workflow versions manager that does not handle versions.
-
-    Sounds odd, but the default implementation of
-    :class:`hurry.workflow.workflow.WorkflowVersions` is a base
-    implementation that raises :exc:`NotImplemented` exceptions for
-    most of the methods defined below.
-
-    If we want to register a versionless workflow, an utility
-    implementing IWorkflowVersions is looked up nevertheless by
-    WorkflowInfo and WorkflowState components so we **have** to
-    provide workflow versions, even if we do not support versioned
-    workflows.
-
-    This implementation returns empty result sets for any requests,
-    but does not raise :exc:`NotImplemented`.
-    """
-    def getVersions(self, state, id):
-        return []
-
-    def getVersionsWithAutomaticTransitions(self):
-        return []
-
-    def hasVersion(self, id, state):
-        return False
-
-    def hasVersionId(self, id):
-        return False
-
-class WAeUPWorkflowInfo(WorkflowInfo):
-    """A workflow info that provides a convenience transition getter.
-    """
-
-    grok.provides(IWAeUPWorkflowInfo)
-
-    def getManualTransitions(self):
-        """Get allowed manual transitions.
-
-        Get a sorted list of tuples containing the `transition_id` and
-        `title` of each allowed transition.
-        """
-        try:
-            checkPermission = getInteraction().checkPermission
-        except NoInteraction:
-            checkPermission = nullCheckPermission
-        return [(transition.transition_id, transition.title)
-                for transition in sorted(self._getTransitions(MANUAL))
-                if transition.condition(self, self.context) and
-                checkPermission(transition.permission, self.context)]
