[Checkins] SVN: grokui.admin/trunk/ Merged trunk with branch fancy-layout

Souheil CHELFOUH souheil at chelfouh.com
Fri Jan 29 10:59:55 EST 2010


Log message for revision 108639:
  Merged trunk with branch fancy-layout
  

Changed:
  _U  grokui.admin/trunk/
  U   grokui.admin/trunk/CHANGES.txt
  U   grokui.admin/trunk/buildout.cfg
  U   grokui.admin/trunk/setup.py
  U   grokui.admin/trunk/src/grokui/admin/__init__.py
  A   grokui.admin/trunk/src/grokui/admin/applications.py
  U   grokui.admin/trunk/src/grokui/admin/configure.zcml
  U   grokui.admin/trunk/src/grokui/admin/ftesting.zcml
  D   grokui.admin/trunk/src/grokui/admin/messages.py
  A   grokui.admin/trunk/src/grokui/admin/providers.py
  A   grokui.admin/trunk/src/grokui/admin/representation.py
  U   grokui.admin/trunk/src/grokui/admin/security.py
  A   grokui.admin/trunk/src/grokui/admin/server.py
  D   grokui.admin/trunk/src/grokui/admin/static/
  A   grokui.admin/trunk/src/grokui/admin/templates/
  U   grokui.admin/trunk/src/grokui/admin/tests/apps.py
  U   grokui.admin/trunk/src/grokui/admin/tests/brokenobjs.py
  U   grokui.admin/trunk/src/grokui/admin/tests/events.py
  U   grokui.admin/trunk/src/grokui/admin/tests/infoviews.py
  D   grokui.admin/trunk/src/grokui/admin/tests/macros.py
  U   grokui.admin/trunk/src/grokui/admin/tests/packdatabase.py
  U   grokui.admin/trunk/src/grokui/admin/tests/security.py
  U   grokui.admin/trunk/src/grokui/admin/tests/server.py
  U   grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin.py
  U   grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin_functional.py
  U   grokui.admin/trunk/src/grokui/admin/utilities.py
  U   grokui.admin/trunk/src/grokui/admin/view.py
  A   grokui.admin/trunk/versions.cfg

-=-

Property changes on: grokui.admin/trunk
___________________________________________________________________
Deleted: svn:mergeinfo
   - 

Modified: grokui.admin/trunk/CHANGES.txt
===================================================================
--- grokui.admin/trunk/CHANGES.txt	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/CHANGES.txt	2010-01-29 15:59:54 UTC (rev 108639)
@@ -4,7 +4,9 @@
 0.6 (unreleased)
 ================
 
+* Reflect the changes in grokcore.view 1.12 where View and CodeView become a single View again.
 
+
 0.5 (2009-09-15)
 ================
 

Modified: grokui.admin/trunk/buildout.cfg
===================================================================
--- grokui.admin/trunk/buildout.cfg	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/buildout.cfg	2010-01-29 15:59:54 UTC (rev 108639)
@@ -1,23 +1,30 @@
 [buildout]
 develop = .
-parts = test data zopectl app
+parts = svn test data zopectl app 
 find-links = http://download.zope.org/distribution/
-extends = http://grok.zope.org/releaseinfo/grok-1.1a2.cfg
+extends = http://svn.zope.org/*checkout*/groktoolkit/trunk/grok.cfg
 versions = versions
 
 [data]
 recipe = zc.recipe.filestorage
 
+[svn]
+recipe = infrae.subversion
+as_eggs = True
+urls = svn://svn.zope.org/repos/main/grokui.base/trunk grokui.base
+
 [versions]
 grokui.admin = 
+grokui.base = 
 
 [app]
 recipe = zc.zope3recipes>=0.5.3:application
 eggs = grokui.admin
 site.zcml =<configure xmlns='http://namespaces.zope.org/zope'
            xmlns:meta="http://namespaces.zope.org/meta"
-           i18n_domain="zope"
-           >
+           i18n_domain="zope">
+
+            <include package="grokui.base" />
             <include package="grokui.admin" />
             <include package="zope.app.twisted" />
 
@@ -40,11 +47,13 @@
                        password="grok"
                        />
 
+            <!-- Replace the following directive if you don't want
+                 public access -->
             <grant permission="zope.View"
-                   principal="zope.Anybody" />
+                   principal="zope.Everybody" />
 
             <grant permission="zope.app.dublincore.view"
-                   principal="zope.Anybody" />
+                   principal="zope.Everybody" />
 
             <role id="zope.Manager" title="Site Manager" />
             <role id="zope.Member" title="Site Member" />
@@ -61,5 +70,5 @@
 
 [test]
 recipe = zc.recipe.testrunner
-eggs = grokui.admin [test,]
+eggs = grokui.admin [test]
 defaults = ['--tests-pattern', '^f?tests$', '-v']

Modified: grokui.admin/trunk/setup.py
===================================================================
--- grokui.admin/trunk/setup.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/setup.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -2,10 +2,11 @@
 from setuptools import setup, find_packages
 
 tests_require = [
-    'z3c.testsetup',
+    'zope.app.testing',
     'zope.testbrowser',
     'zope.testing',
-    'zope.app.testing',
+    'zope.security',
+    'zope.securitypolicy'
     ]
 
 def read(*rnames):
@@ -19,7 +20,6 @@
           '\n\n' +
           read('CHANGES.txt')
         ),
-      # Get strings from http://www.python.org/pypi?%3Aaction=list_classifiers
       classifiers=[
         'Development Status :: 3 - Alpha',
         'Environment :: Web Environment',
@@ -39,21 +39,27 @@
       packages=find_packages('src'),
       include_package_data=True,
       zip_safe=False,
-      namespace_packages = ['grokui'],
-      install_requires=['setuptools',
-                        'ZODB3',
-                        'grok',
-			'grokcore.view',
-                        'martian',
-                        'z3c.flashmessage',
-                        'zope.app.applicationcontrol',
-                        'zope.app.appsetup',
-                        'zope.component',
-                        'zope.exceptions',
-                        'zope.interface',
-                        'zope.schema',
-                        'zope.security',
-                        ],
+      namespace_packages=['grokui'],
+      install_requires=[
+          'ZODB3',
+          'grok',
+          'grokui.base',
+          'setuptools',
+          'z3c.flashmessage',
+          'zope.applicationcontrol',
+          'zope.component',
+          'zope.configuration',
+          'zope.contentprovider',
+          'zope.exceptions',
+          'zope.i18nmessageid',
+          'zope.interface',
+          'zope.location',
+          'zope.login',
+          'zope.schema',
+          'zope.site',
+          'zope.size',
+          'zope.traversing',
+          ],
       tests_require = tests_require,
       extras_require = dict(test=tests_require),
       entry_points="""

Modified: grokui.admin/trunk/src/grokui/admin/__init__.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/__init__.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/__init__.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -12,4 +12,3 @@
 #
 ##############################################################################
 # a package
-

Copied: grokui.admin/trunk/src/grokui/admin/applications.py (from rev 108638, grokui.admin/branches/fancy-layout/src/grokui/admin/applications.py)
===================================================================
--- grokui.admin/trunk/src/grokui/admin/applications.py	                        (rev 0)
+++ grokui.admin/trunk/src/grokui/admin/applications.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+
+import grok
+from ZODB.broken import Broken
+from grokui.admin import representation
+from zope.traversing.browser import absoluteURL
+from zope.contentprovider.interfaces import IContentProvider
+from zope.component import getMultiAdapter, getAllUtilitiesRegisteredFor
+from grokui.base.layout import GrokUIView
+from grokui.base.namespace import GrokUILayer
+
+grok.templatedir("templates")
+
+
+class InstalledApplication(object):
+    grok.implements(representation.IInstalledApplication)
+   
+    def __init__(self, obj, request):
+        self.__name__ = obj.__name__
+        self.url = absoluteURL(obj, request)
+        self.description = obj.__doc__
+        self.__parent__ = obj.__parent__
+        self.classname = ".".join((obj.__class__.__module__,
+                                   obj.__class__.__name__))
+
+    def __cmp__(self, other):
+        return cmp(self.__name__, other.__name__)
+
+
+class BrokenApplication(object):
+    grok.implements(representation.IApplicationRepresentation)
+
+    def __init__(self, name, obj):
+        self.__name__ = name
+        self.classname = ".".join((obj.__class__.__module__,
+                                   obj.__class__.__name__))
+
+    def __cmp__(self, other):
+        return cmp(self.__name__, other.__name__)
+
+
+class InstallableApplication(object):
+    grok.implements(representation.IInstallableApplication)
+    
+    def __init__(self, klass):
+        self.__name__ = klass.__name__
+        self.classname = ".".join((klass.__module__, klass.__name__))
+        self.description = unicode(klass.__doc__)
+
+    
+class ApplicationInfo(grok.View):
+    grok.name('info')
+    grok.context(representation.IApplicationRepresentation)
+
+    def render(self):
+        info = getMultiAdapter(
+            (self.context, self.request, self),
+            IContentProvider,
+            name='grokui_admin_appinfo')
+        info.update()
+        return info.render()
+
+
+class Applications(GrokUIView):
+    """View for application management.
+    """
+    grok.layer(GrokUILayer)
+    grok.name('applications')
+    grok.title('Applications')
+    grok.require('grok.ManageApplications')
+
+    def update(self):
+        # Available apps...
+        apps = getAllUtilitiesRegisteredFor(grok.interfaces.IApplication)
+        self.installable = (InstallableApplication(x) for x in apps)
+
+        # Installed apps...
+        self.broken = []
+        self.installed = []
+
+        for name, app in self.context.root.items():
+            is_broken = isinstance(app, Broken)
+            if is_broken:
+                self.broken.append(BrokenApplication(name, app))
+            else:
+                self.installed.append(InstalledApplication(app, self.request))
+
+        self.broken.sort()
+        self.installed.sort()
+        self.has_apps = bool(len(self.installed) + len(self.broken))

Modified: grokui.admin/trunk/src/grokui/admin/configure.zcml
===================================================================
--- grokui.admin/trunk/src/grokui/admin/configure.zcml	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/configure.zcml	2010-01-29 15:59:54 UTC (rev 108639)
@@ -1,5 +1,7 @@
 <configure xmlns="http://namespaces.zope.org/zope"
            xmlns:grok="http://namespaces.zope.org/grok">
   <include package="grok" />
+  <include package="zope.applicationcontrol" />
+  <include package="zope.login" />
   <grok:grok package="." />
 </configure>

Modified: grokui.admin/trunk/src/grokui/admin/ftesting.zcml
===================================================================
--- grokui.admin/trunk/src/grokui/admin/ftesting.zcml	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/ftesting.zcml	2010-01-29 15:59:54 UTC (rev 108639)
@@ -2,9 +2,9 @@
    xmlns="http://namespaces.zope.org/zope"
    xmlns:grok="http://namespaces.zope.org/grok"
    i18n_domain="grok"
-   package="grokui.admin"
-   >
+   package="grokui.admin">
 
+  <include package="grokui.base" />
   <include package="grokui.admin" />
   <grok:grok package="grokui.admin.tests" />
 

Deleted: grokui.admin/trunk/src/grokui/admin/messages.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/messages.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/messages.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -1,31 +0,0 @@
-# -*- coding: latin-1 -*-
-# Copyright (c) 2007 gocept gmbh & co. kg
-# See also LICENSE.txt
-# $Id$
-"""Support for flash-messages in the grok admin UI."""
-
-import zope.interface
-import zope.component
-
-import grok
-
-import z3c.flashmessage.interfaces
-import z3c.flashmessage.sources
-import z3c.flashmessage.receiver
-
-
-class Messages(grok.View):
-
-    grok.context(zope.interface.Interface)
-
-    @property
-    def messages(self):
-        receiver = zope.component.getUtility(
-            z3c.flashmessage.interfaces.IMessageReceiver)
-        return receiver.receive()
-
-
-
-grok.global_utility(z3c.flashmessage.sources.SessionMessageSource,
-                    name='session')
-grok.global_utility(z3c.flashmessage.receiver.GlobalMessageReceiver)

Copied: grokui.admin/trunk/src/grokui/admin/providers.py (from rev 108638, grokui.admin/branches/fancy-layout/src/grokui/admin/providers.py)
===================================================================
--- grokui.admin/trunk/src/grokui/admin/providers.py	                        (rev 0)
+++ grokui.admin/trunk/src/grokui/admin/providers.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+import grok
+from grokui.admin import representation
+
+
+class ApplicationInformation(grok.ViewletManager):
+    grok.name('grokui_admin_appinfo')
+    grok.context(representation.IApplicationRepresentation)

Copied: grokui.admin/trunk/src/grokui/admin/representation.py (from rev 108638, grokui.admin/branches/fancy-layout/src/grokui/admin/representation.py)
===================================================================
--- grokui.admin/trunk/src/grokui/admin/representation.py	                        (rev 0)
+++ grokui.admin/trunk/src/grokui/admin/representation.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+
+from zope import schema
+from zope.location import ILocation
+from zope.interface import Interface
+from zope.configuration.fields import PythonIdentifier
+from zope.contentprovider.interfaces import IContentProvider
+
+
+class IApplicationRepresentation(Interface):
+    """Defines an Grok application 
+    """
+    __name__ = schema.TextLine(
+        title = u"Name",
+        required = True)
+    
+    classname = PythonIdentifier(
+        title = u"Dotted name of the Application class",
+        required = True)
+    
+    description = schema.Text(
+        title = u"Description of the Application",
+        default = u"",
+        required = False)
+
+
+class IInstallableApplication(IApplicationRepresentation):
+    """Defines an installable application.
+    """
+
+
+class IInstalledApplication(IApplicationRepresentation, ILocation):
+    """Defines an application that is installed in our system.
+    """
+    url = schema.URI(
+        title = u"Absolute URL of the application",
+        required = True)
+
+
+class IApplicationInformation(IContentProvider):
+    """Marker interface for the Application information content provider.
+    """

Modified: grokui.admin/trunk/src/grokui/admin/security.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/security.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/security.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -10,23 +10,19 @@
 
 from persistent import Persistent
 from zope.component import adapter, provideHandler
-from zope.site.interfaces import IRootFolder
-from zope.app.appsetup.interfaces import IDatabaseOpenedWithRootEvent
 from grokui.admin.interfaces import ISecurityNotifier
 from grokui.admin.utilities import getVersion, TimeoutableHTTPHandler
+from grokui.base import Header, Messages, IGrokUIRealm
 
+MSG_DISABLED = u'Security notifications are disabled.'
 
-class SecurityScreen(grok.ViewletManager):
-    """A viewlet manager that keeps security related notifications.
-    """
-    grok.name('grokadmin_security')
-    grok.context(IRootFolder)
 
-
 class SecurityNotificationViewlet(grok.Viewlet):
     """Viewlet displaying notifications from a local `SecurityNotifier`.
     """
-    grok.context(IRootFolder)
+    grok.order(40)
+    grok.context(IGrokUIRealm)
+    grok.viewletmanager(Messages)
 
     @property
     def security_notifier(self):
@@ -40,7 +36,11 @@
         return site_manager.queryUtility(ISecurityNotifier, default=None)
 
     def render(self):
-        return self.security_notifier.getNotification()
+        notifier = self.security_notifier
+        if notifier is None:
+            return u""
+        return '''<div class="grokui-security message">%s</div>''' % (
+            self.security_notifier.getNotification())
 
 
 class SecurityNotifier(Persistent):
@@ -49,11 +49,9 @@
     It can be placed in a site to store notification dates and other
     data persistently.
     """
-
     grok.implements(ISecurityNotifier)
 
     VERSION = 1 # for possibly updates/downgrades
-    MSG_DISABLED = u'Security notifications are disabled.'
     DEFAULT_URL = 'http://grok.zope.org/releaseinfo/'
     
     lookup_url = DEFAULT_URL
@@ -82,7 +80,7 @@
         """Get the current security notification.
         """
         if self.enabled is False:
-            return self.MSG_DISABLED
+            return MSG_DISABLED
         self.updateMessage()
         return self._message
 
@@ -127,7 +125,7 @@
         except:
             # An unexpected problem occured...
             pass
-        if self._message == self.MSG_DISABLED:
+        if self._message == MSG_DISABLED:
             self._message = u''
         self.last_lookup = time.time()
         return
@@ -146,38 +144,3 @@
         """
         self.last_display = time.time()
         return
-
-
-def setupSecurityNotification(site):
-    """Setup a SecurityNotifier as persistent utility.
-
-    The utility is installed as a local and persistent utility. It is
-    local to `site` and installed under the name
-    ``grokadmin_security`` in the site manager of `site`.
-
-    It can be retrieved with a call like::
-
-      site.getSiteManager().getUtiliy(ISecurityNotifier)
-
-    See also ``security.py`` in ``tests``.
-    """
-    site_manager = site.getSiteManager()
-    if 'grokadmin_security' not in site_manager:
-        site_manager['grokadmin_security'] = SecurityNotifier()
-    utility = site_manager['grokadmin_security']
-    site_manager.registerUtility(utility, ISecurityNotifier, name=u'')
-    return
-
-    
- at adapter(IDatabaseOpenedWithRootEvent)
-def securitySetupHandler(event):
-    """Call security notification setup as soon as DB is ready.
-    """
-    from zope.app.appsetup.bootstrap import getInformationFromEvent
-    
-    db, connection, root, root_folder = getInformationFromEvent(event)
-    setupSecurityNotification(root_folder)
-
-
-# ...then install the event handler:
-provideHandler(securitySetupHandler)

Copied: grokui.admin/trunk/src/grokui/admin/server.py (from rev 108638, grokui.admin/branches/fancy-layout/src/grokui/admin/server.py)
===================================================================
--- grokui.admin/trunk/src/grokui/admin/server.py	                        (rev 0)
+++ grokui.admin/trunk/src/grokui/admin/server.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -0,0 +1,234 @@
+# -*- coding: utf-8 -*-
+
+import grok
+import z3c.flashmessage.interfaces
+
+from grokui.base.layout import GrokUIView
+from grokui.admin.interfaces import ISecurityNotifier
+from grokui.admin.utilities import getVersion
+from grokui.admin.security import SecurityNotifier
+
+from ZODB.interfaces import IDatabase
+from ZODB.FileStorage.FileStorage import FileStorageError
+
+from zope.size import byteDisplay
+from zope.applicationcontrol.interfaces import IServerControl, IRuntimeInfo
+from zope.applicationcontrol.applicationcontrol import applicationController
+from zope.component import getUtility, queryUtility, getUtilitiesFor
+from zope.i18nmessageid import MessageFactory
+
+_ = MessageFactory('grokui')
+grok.templatedir("templates")
+
+
+class Server(GrokUIView):
+    """Zope3 management screen.
+    """
+    grok.title('Server Control')
+    grok.require('grok.ManageApplications')
+
+    _fields = (
+        "ZopeVersion",
+        "PythonVersion",
+        "PythonPath",
+        "SystemPlatform",
+        "PreferredEncoding",
+        "FileSystemEncoding",
+        "CommandLine",
+        "ProcessId",
+        "DeveloperMode",
+        )
+    
+    _unavailable = _("Unavailable")
+
+    @property
+    def grok_version(self):
+        return getVersion('grok')
+
+    @property
+    def grokuiadmin_version(self):
+        return getVersion('grokui.admin')
+
+    def root_url(self, name=None):
+        obj = self.context
+        result = ""
+        while obj is not None:
+            if IRootFolder.providedBy(obj):
+                return self.url(obj, name)
+            obj = obj.__parent__
+        raise ValueError("No application nor root element found.")
+
+    @property
+    def security_notifier_url(self):
+        """Get the URL to look up for security warnings.
+        """
+        return self.security_notifier.lookup_url
+    
+    @property
+    def security_notifier(self):
+        """Get a local security notifier.
+
+        The security notifier is installed as a local utility by an
+        event handler in the security module.
+        """
+        site = grok.getSite()
+        site_manager = site.getSiteManager()
+        return site_manager.queryUtility(ISecurityNotifier, default=None)
+    
+    @property
+    def secnotes_enabled(self):
+        if self.security_notifier is None:
+            return False
+        return self.security_notifier.enabled
+
+    @property
+    def secnotes_message(self):
+        if self.security_notifier is None:
+            return u'Security notifier is not installed.'
+        return self.security_notifier.getNotification()
+    
+    @property
+    def server_control(self):
+        return queryUtility(IServerControl)
+
+    @property
+    def runtime_info(self):
+        try:
+            ri = IRuntimeInfo(applicationController)
+        except TypeError:
+            formatted = dict.fromkeys(self._fields, self._unavailable)
+            formatted["Uptime"] = self._unavailable
+        else:
+            formatted = self._getInfo(ri)
+            
+        return formatted
+
+    def _getInfo(self, ri):
+        formatted = {}
+        for name in self._fields:
+            try:
+                value = getattr(ri, "get" + name)()
+            except ValueError:
+                value = self._unavailable
+            formatted[name] = value
+        formatted["Uptime"] = self._getUptime(ri)
+        return formatted
+
+    def _getUptime(self, ri):
+        # make a unix "uptime" uptime format
+        uptime = long(ri.getUptime())
+        minutes, seconds = divmod(uptime, 60)
+        hours, minutes = divmod(minutes, 60)
+        days, hours = divmod(hours, 24)
+
+        return _('${days} day(s) ${hours}:${minutes}:${seconds}',
+                 mapping = {'days': '%d' % days,
+                            'hours': '%02d' % hours,
+                            'minutes': '%02d' % minutes,
+                            'seconds': '%02d' % seconds})
+
+
+    @property
+    def current_message(self):
+        source = getUtility(
+          z3c.flashmessage.interfaces.IMessageSource, name='admin')
+        messages = list(source.list())
+        if messages:
+            return messages[0]
+
+    def updateSecurityNotifier(self, setsecnotes=None, setsecnotesource=None,
+                               secnotesource=None):
+        if self.security_notifier is None:
+            site = grok.getSite()
+            site_manager = site.getSiteManager()
+            if 'grokadmin_security' not in site_manager:
+                site_manager['grokadmin_security'] = SecurityNotifier()
+                utility = site_manager['grokadmin_security']
+                site_manager.registerUtility(
+                    utility, ISecurityNotifier, name=u'')
+                
+        if setsecnotesource is not None:
+            self.security_notifier.setLookupURL(secnotesource)
+        if setsecnotes is not None:
+            if self.security_notifier.enabled is True:
+                self.security_notifier.disable()
+            else:
+                self.security_notifier.enable()
+        if self.secnotes_enabled is False:
+            return
+        return
+        
+    def update(self, time=None, restart=None, shutdown=None,
+               setsecnotes=None, secnotesource=None, setsecnotesource=None,
+               admin_message=None, submitted=False, dbName="", pack=None,
+               days=0):
+
+        # Packing control
+        if pack is not None:
+            return self.pack(dbName, days)
+
+        # Security notification control
+        self.updateSecurityNotifier(setsecnotes, setsecnotesource,
+                                    secnotesource)
+
+        
+        if not submitted:
+            return
+
+        # Admin message control
+        source = getUtility(
+          z3c.flashmessage.interfaces.IMessageSource, name='admin')
+        if admin_message is not None:
+            source.send(admin_message)
+        elif getattr(source, 'current_message', False):
+            source.delete(source.current_message)
+
+        # Restart control
+        if time is not None:
+            try:
+                time = int(time)
+            except:
+                time = 0
+        else:
+            time = 0
+
+        if restart is not None:
+            self.server_control.restart(time)
+        elif shutdown is not None:
+            self.server_control.shutdown(time)
+
+        self.redirect(self.url())
+
+    @property
+    def databases(self):
+        res = []
+        for name, db in getUtilitiesFor(IDatabase):
+            d = dict(dbName = db.getName(),
+                     utilName = str(name),
+                     size = self._getSize(db),
+                     )
+            res.append(d)
+        return res
+            
+    def _getSize(self, db):
+        """Get the database size in a human readable format."""
+        size = db.getSize()        
+        if not isinstance(size, (int, long, float)):
+            return str(size)
+        return byteDisplay(size)
+
+    def pack(self, dbName, days):
+        try:
+            days = int(days)
+        except ValueError:
+            flash('Error: Invalid Number')
+            return
+        db = getUtility(IDatabase, name=dbName)
+        print "DB: ", db, days
+        db.pack(days=days)
+        return
+        try:
+            db.pack(days=days)
+            flash('ZODB `%s` successfully packed.' % (dbName))
+        except FileStorageError, err:
+            flash('ERROR packing ZODB `%s`: %s' % (dbName, err))

Modified: grokui.admin/trunk/src/grokui/admin/tests/apps.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/apps.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/apps.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -33,13 +33,13 @@
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ... <p ...>Currently no working...applications are installed.</p>
+  ... Currently no working...applications are installed.
   ...
 
 We are able to add a mammoth manager...
 
-  >>> subform = browser.getForm(name='MammothManager')
-  >>> subform.getControl('Name your new app:').value = 'my-mammoth-manager'
+  >>> subform = browser.getForm(name='grokui.admin.tests.apps.MammothManager')
+  >>> subform.getControl(name='name').value = 'my-mammoth-manager'
   >>> subform.getControl('Create').click()
 
   >>> print browser.contents
@@ -62,7 +62,7 @@
 We can also rename applications. For this we choose the application we
 installed and click `Rename`::
 
-  >>> browser.open("http://localhost/applications")
+  >>> browser.open("http://localhost/++grokui++/applications")
   >>> ctrl = browser.getControl(name='items')
   >>> ctrl.getControl(value='my-mammoth-manager').selected = True
   >>> browser.getControl('Rename').click()
@@ -91,7 +91,7 @@
   
 We are able to delete installed mammoth-managers
 
-  >>> browser.open("http://localhost/applications")
+  >>> browser.open("http://localhost/++grokui++/applications")
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
   ...
@@ -103,7 +103,7 @@
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ... <p ...>Currently no working applications...are installed.</p>
+  ... Currently no working applications are installed.
   ...
   ...<legend>Add application</legend>
   ...
@@ -114,13 +114,10 @@
 
 
 class MammothManager(grok.Application, grok.Container):
-    """A mammoth manager.
-    """
+    """A mammoth manager"""
     pass
 
 
 class Index(grok.View):
-    """A Mammoth manager view.
-    """
     def render(self):
         return u"Let's manage some mammoths!"

Modified: grokui.admin/trunk/src/grokui/admin/tests/brokenobjs.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/brokenobjs.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/brokenobjs.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -26,24 +26,25 @@
 If no broken applications are in the root, everything should look as
 usual:
 
-  >>> browser.open('http://localhost/applications')
+  >>> browser.open('http://localhost/++grokui++/applications')
   >>> 'Broken applications:' not in browser.contents
   True
 
 We have an application type available, which is intentionally broken
 and defined below::
 
-  >>> browser.open('http://localhost/applications')
+  >>> browser.open('http://localhost/++grokui++/applications')
   >>> 'PseudoBroken' in browser.contents
   True
 
 We add an instance of that new type:
 
-  >>> subform = browser.getForm(name='PseudoBroken')
+  >>> subform = browser.getForm(
+  ...             name='grokui.admin.tests.brokenobjs.PseudoBroken')
   >>> subform
   <zope.testbrowser.browser.Form object at 0x...>
 
-  >>> subform.getControl('Name your new app').value = 'mybrokenobj'
+  >>> subform.getControl(name='name').value = 'mybrokenobj'
   >>> subform.getControl('Create').click()
 
 and the broken object should show up in the applications list:

Modified: grokui.admin/trunk/src/grokui/admin/tests/events.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/events.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/events.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -29,14 +29,13 @@
 When we create a new instance of our app, the eventhandler defined
 below will be called:
 
-  >>> subform = browser.getForm(name='App')
-  >>> subform.getControl('Name your new app:').value = 'my-app'
+  >>> subform = browser.getForm(name='grokui.admin.tests.events.App')
+  >>> subform.getControl(name='name').value = 'my-app'
   >>> subform.getControl('Create').click()
   ObjectCreated event happened.
 
 """
 import grok
-from zope.component import interfaces
 
 class App(grok.Application, grok.Container):
     pass

Modified: grokui.admin/trunk/src/grokui/admin/tests/infoviews.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/infoviews.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/infoviews.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -29,7 +29,7 @@
 
 We must be authenticated to fetch those infos::
 
-  >>> browser.open('http://localhost/@@grokadmin/@@version')
+  >>> browser.open('http://localhost/++grokui++/@@admin/@@version')
   Traceback (most recent call last):
   ...
   HTTPError: HTTP Error 401: Unauthorized
@@ -40,7 +40,7 @@
 When we are authenticated, we can retrieve the grok version used::
   
   >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-  >>> browser.open('http://localhost/@@grokadmin/@@version')
+  >>> browser.open('http://localhost/++grokui++/@@admin/@@version')
   >>> print browser.contents
   grok ...
 
@@ -63,7 +63,7 @@
 To determine the used version of `grokui.admin` we can call::
 
   >>> import pkg_resources
-  >>> browser.open('http://localhost/@@grokadmin/@@version?pkg=grokui.admin')
+  >>> browser.open('http://localhost/++grokui++/@@admin/@@version?pkg=grokui.admin')
   >>> version = pkg_resources.get_distribution('grokui.admin').version
   >>> browser.contents == ('grokui.admin ' + version)
   True
@@ -74,7 +74,7 @@
 
 We can get the current security notification::
 
-  >>> browser.open('http://localhost/@@grokadmin/@@secnote')
+  >>> browser.open('http://localhost/++grokui++/@@admin/@@secnote')
   >>> print browser.contents
   Security notifications are disabled.
 

Deleted: grokui.admin/trunk/src/grokui/admin/tests/macros.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/macros.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/macros.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -1,68 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2007 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-"""
-Macros for the grok admin UI
-
-  >>> from zope.testbrowser.testing import Browser
-  >>> browser = Browser()
-  >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-  >>> browser.open('http://localhost/applications')
-
-Check, that the macros template renders correctly, even if not called
-with context of a GAIA object. This is important, because the macro
-view is bound to ``Interface`` and can therefore be called with nearly
-every object as context.
-
-We create a non-GAIA object, a mammoth called 'manfred'.
-
-  >>> subform = browser.getForm(name='Mammoth')
-  >>> subform.getControl('Name your new app:').value = 'manfred'
-  >>> subform.getControl('Create').click()
-
-and call the macroview with it:
-
-  >>> browser.open('http://localhost/manfred/@@externalview')
-  >>> print browser.contents
-  <html xmlns="http://www.w3.org/1999/xhtml">
-  ...
-     This template (grokadminmacros.pt in grok.admin) must be called
-     from a view with defined root_url.
-  ...
-
-So developers get informed, that they called the wrong macro view.
-
-Let's clean up.
-
-  >>> browser.open('http://localhost/applications')
-  >>> ctrl = browser.getControl(name='items')
-  >>> ctrl.getControl(value='manfred').selected = True
-  >>> browser.getControl('Delete Selected').click()
-
-
-"""
-import grok
-
-class Mammoth(grok.Application, grok.Container):
-    pass
-
-class ExternalView(grok.View):
-    """A view that calls grokadminmacros 'illegally'.
-    """
-    grok.context(Mammoth)
-
-externalview = grok.PageTemplate("""\
-<html metal:use-macro="context/@@grokadminmacros/macros/gaia-page">
-</html>
-""")
-

Modified: grokui.admin/trunk/src/grokui/admin/tests/packdatabase.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/packdatabase.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/packdatabase.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -19,8 +19,9 @@
   >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
   >>> browser.open("http://localhost/")
 
-  >>> subform = browser.getForm(name='StuffedMammoth')
-  >>> subform.getControl('Name your new app:').value = 'my-stuffed-mammoth'
+  >>> subform = browser.getForm(
+  ...    name='grokui.admin.tests.packdatabase.StuffedMammoth')
+  >>> subform.getControl(name='name').value = 'my-stuffed-mammoth'
   >>> subform.getControl('Create').click()
   >>> mylink = browser.getLink('my-stuffed-mammoth').click()
 
@@ -36,29 +37,19 @@
   Time to stuff a mammoth!
 
 Check the size of the ZODB.
-  >>> browser.open("http://localhost/server")
+  >>> browser.open("http://localhost/++grokui++/server")
   >>> lines = [ l.strip() for l in browser.contents.split('\\n') ]
   >>> zodb_size = lines[lines.index("Demo storage 'unnamed'")+  1]
   >>> num_zodb_size = int(zodb_size.split(' ')[0])
 
 Now, pack the database.
 
-(XXX: This test is disabled, because we get an infinite loop trying to
-      pack a demo storage.)
-
-  >>> #ctrl = browser.getControl(name='pack').click()
   >>> lines = [ l.strip() for l in browser.contents.split('\\n') ]
   >>> zodb_size = lines[lines.index("Demo storage 'unnamed'")+  1]
   >>> new_num_zodb_size = int(zodb_size.split(' ')[0])
 
-# remove this test - it highlights a problem with the zodb api, but is
-# a problem as a regression test
-#Ensure that it is smaller now:
-#  >>> new_num_zodb_size < num_zodb_size
-#  True
-
 And clean up after ourselves.
-  >>> browser.open("http://localhost/applications")
+  >>> browser.open("http://localhost/++grokui++/applications")
   >>> ctrl = browser.getControl(name='items')
   >>> ctrl.getControl(value='my-stuffed-mammoth').selected = True
   >>> browser.getControl('Delete Selected').click()
@@ -66,17 +57,15 @@
 """
 
 import grok
-try:
-    from grokcore.view import CodeView as View
-except ImportError:
-    from grok import View
 
+
 class StuffedMammoth(grok.Application, grok.Container):
     """A stuffed mammoth"""
     stuffing = None
 
-class Index(View):#
 
+class Index(grok.View):#
+
     def update(self, stuffing=None):
         if stuffing is not None:
             self.context.stuffing = stuffing*1000

Modified: grokui.admin/trunk/src/grokui/admin/tests/security.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/security.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/security.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -149,47 +149,30 @@
 
 Currently, as `grokui.admin` is merely a collection of views bound to
 root folders, also the security notification utility is normally
-managed by the local site manager of the root folder::
+managed by the local site manager of the root folder.
 
-  >>> root = getRootFolder()
-  >>> sm = root.getSiteManager()
-
-Now we can lookup the utility::
-
-  >>> from grokui.admin.interfaces import ISecurityNotifier
-  >>> notifier = sm.getUtility(ISecurityNotifier)
-  >>> notifier
-  <grokui.admin.security.SecurityNotifier object at 0x...>
-
 The utility is local, because different root folders might want
 different settings for security notifications.
 
 The utility is persistent, so that the settings are preserved when
 shutting down.
 
-Immediately after startup, the notifier exists, but is disabled::
+Immediately after startup, the notifier doesn't exists::
 
-  >>> notifier.enabled
-  False
+  >>> from grokui.admin.interfaces import ISecurityNotifier
+  
+  >>> root = getRootFolder()
+  >>> sm = root.getSiteManager()
+  >>> notifier = sm.queryUtility(ISecurityNotifier)
+  >>> notifier is None
+  True
 
-We can get notifications, of course::
+We log into the admin screen to set a new notifier URL::
 
-  >>> notifier.getNotification()
-  u'Security notifications are disabled.'
-
-We can check in a formal way, whether the current notification is a
-warning::
-
-  >>> notifier.isWarning()
-  False
-
-The notifier we got here is the same as when using the UI. We log into
-the admin screen to set a new notifier URL::
-
   >>> from zope.testbrowser.testing import Browser
   >>> browser = Browser()
   >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
-  >>> browser.open('http://localhost/@@server')
+  >>> browser.open('http://localhost/++grokui++/@@server')
 
 On the server administration page we can see the status of our
 notifier (enabled or disabled)::
@@ -205,7 +188,7 @@
 
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
-  ...<div id="securitynotifications">Security notifications are disabled.</div>
+  ...<div id="grokui-messages"><div class="grokui-security message">Security notifications are disabled.</div>
   ...
 
 But we are not bound to the default URL to do lookups. We can set
@@ -224,7 +207,7 @@
 
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
-  ...<div id="securitynotifications">You better smash ...</div>
+  ...<div id="grokui-messages"><div class="grokui-security message">You better smash ...</div>
   ...
 
 We can of course disable security notifications at any time::
@@ -232,14 +215,13 @@
   >>> browser.getControl('Disable').click()
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
-  ...<div id="securitynotifications">Security notifications are disabled.</div>
+  ...<div id="grokui-messages"><div class="grokui-security message">Security notifications are disabled.</div>
   ...
+
   
 Clean up::
 
   >>> import os
   >>> os.unlink(fake_warning_file)
 
-
-  
 """

Modified: grokui.admin/trunk/src/grokui/admin/tests/server.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/server.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/server.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -35,7 +35,8 @@
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ...   <a href="http://localhost/server">Server Control</a>
+  <a href="http://localhost/++grokui++/server"
+     title="Server Control">Server Control</a>
   ...
 
 Now we can click that link and should get the server administration
@@ -43,7 +44,7 @@
 
   >>> browser.getLink('Server Control').click()
   >>> browser.title
-  'grok administration interface'
+  'Grok User Interface'
 
 We can enter an admin message::
 
@@ -59,8 +60,10 @@
   >>> msg_form.submit()
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
-  ... <li class="admin">Hi there!</li>
   ...
+  <dl class="messages-list">
+    <dd class="admin">Hi there!</dd>
+  ...
 
 The message stays, even if we call another page::
 
@@ -68,9 +71,7 @@
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ... <li class="admin">Hi there!</li>
-  ...
-  ...
+  ... <dd class="admin">Hi there!</dd>
   ...      <legend>Add application</legend>
   ...
 
@@ -80,7 +81,7 @@
   >>> print browser.contents
   <html xmlns="http://www.w3.org/1999/xhtml">
   ...
-  ... <li class="admin">Hi there!</li>
+  ... <dd class="admin">Hi there!</dd>
   ...
 
 

Modified: grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -59,14 +59,14 @@
     for name in []:
         suite.addTest(suiteFromPackage(name))
     for name in ['utilities.py']:
-        suite.addTest(doctest.DocFileSuite(name,
-                                           package='grokui.admin',
-                                           globs=globs,
-                                           setUp=setUpZope,
-                                           tearDown=cleanUpZope,
-                                           optionflags=doctest.ELLIPSIS+
-                                           doctest.NORMALIZE_WHITESPACE)
-                      )
+        suite.addTest(doctest.DocFileSuite(
+            name,
+            package='grokui.admin',
+            globs=globs,
+            setUp=setUpZope,
+            tearDown=cleanUpZope,
+            optionflags=(doctest.ELLIPSIS|doctest.NORMALIZE_WHITESPACE),
+            ))
     return suite
 
 if __name__ == '__main__':

Modified: grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin_functional.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin_functional.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/tests/test_grokadmin_functional.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -16,10 +16,6 @@
 
 def setUp(test):
     FunctionalTestSetup().setUp()
-    # In functional tests no IDatabaseOpenedWithRootEvent are fired. We
-    # therefore have to setup security notifications manually
-    from grokui.admin.security import setupSecurityNotification
-    setupSecurityNotification(getRootFolder())
 
 def tearDown(test):
     FunctionalTestSetup().tearDown()

Modified: grokui.admin/trunk/src/grokui/admin/utilities.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/utilities.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/utilities.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -1,11 +1,8 @@
 import httplib
 import pkg_resources
-import re
 import socket
 import urllib
 import urllib2
-from zope.tal.taldefs import attrEscape
-from urlparse import urlparse, urlunparse
 
 
 def getURLWithParams(url, data=None):
@@ -38,7 +35,6 @@
     """A customised HTTPConnection allowing a per-connection
     timeout, specified at construction.
     """
-
     def __init__(self, host, port=None, strict=None, timeout=None):
         httplib.HTTPConnection.__init__(self, host, port,
                 strict)
@@ -71,7 +67,6 @@
     """A customised HTTPHandler which times out connection
     after the duration specified at construction.
     """
-
     def __init__(self, timeout=None):
         urllib2.HTTPHandler.__init__(self)
         self.timeout = timeout
@@ -84,4 +79,3 @@
                     timeout = self.timeout)
 
         return self.do_open(makeConnection, req)
-

Modified: grokui.admin/trunk/src/grokui/admin/view.py
===================================================================
--- grokui.admin/trunk/src/grokui/admin/view.py	2010-01-29 15:55:39 UTC (rev 108638)
+++ grokui.admin/trunk/src/grokui/admin/view.py	2010-01-29 15:59:54 UTC (rev 108639)
@@ -1,50 +1,22 @@
-##############################################################################
-#
-# Copyright (c) 2007-2008 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
+# -*- coding: utf-8 -*-
 """Views for the grok admin UI"""
 
 import grok
-import z3c.flashmessage.interfaces
 
+from BTrees.OOBTree import OOBTree
+from grokui.base import IGrokUIRealm, GrokUIView
 from grokui.admin.interfaces import ISecurityNotifier
 from grokui.admin.utilities import getVersion, getURLWithParams
+from grokui.admin.security import MSG_DISABLED
 
-from ZODB.broken import Broken
-from ZODB.interfaces import IDatabase
-from BTrees.OOBTree import OOBTree
-from ZODB.FileStorage.FileStorage import FileStorageError
-
-import zope.component
-from zope.interface import Interface
-from zope.exceptions import DuplicationError
 from zope.site.interfaces import IRootFolder
-from zope.authentication.interfaces import IUnauthenticatedPrincipal
+from zope.exceptions import DuplicationError
+from zope.component import getUtility, queryUtility
 
-from zope.app.applicationcontrol.interfaces import IServerControl
-from zope.app.applicationcontrol.applicationcontrol import applicationController
-from zope.app.applicationcontrol.browser.runtimeinfo import RuntimeInfoView
-from zope.app.applicationcontrol.browser.zodbcontrol import ZODBControlView
+grok.context(IGrokUIRealm)
+grok.templatedir("templates")
 
-grok.context(IRootFolder)
 
-
-def flash(message, type='message'):
-    src = zope.component.getUtility(
-        z3c.flashmessage.interfaces.IMessageSource, name='session'
-        )
-    src.send(message, type)
-
-
 class ManageApplications(grok.Permission):
     grok.name('grok.ManageApplications')
 
@@ -52,70 +24,42 @@
 class GrokAdminInfoView(grok.View):
     """A base to provide machinereadable views.
     """
-    grok.name('grokadmin')
+    grok.name('admin')
     grok.require('grok.ManageApplications')
     
     def render(self):
         return u'go to @@version or @@secnotes'
 
 
-class AdminViewBase(grok.View):
-    """A grok.View with a special application_url.
-    We have to compute the application_url different from common
-    grok.Views, because we have no root application object in the
-    adminUI. To avoid mismatch, we also call it 'root_url'.
-    """
-    grok.baseclass()
-    
-    @property
-    def grok_version(self):
-        return getVersion('grok')
-
-    @property
-    def grokuiadmin_version(self):
-        return getVersion('grokui.admin')
-
-    def is_authenticated(self):
-        """Check, wether we are authenticated.
-        """
-        return not IUnauthenticatedPrincipal.providedBy(self.request.principal)
-
-    def root_url(self, name=None):
-        obj = self.context
-        while obj is not None:
-            if IRootFolder.providedBy(obj):
-                return self.url(obj, name)
-            obj = obj.__parent__
-        raise ValueError("No application nor root element found.")
-
-
-
 class GrokAdminVersion(grok.View):
     """Display version of a package.
-    Call this view via http://localhost:8080/@@grokadmin/@@version to
+
+    Call this view via http://localhost:8080/@@admin/@@version to
     get the used grok version. Call
-    http://localhost:8080/@@grokadmin/@@version?pkg=<pkgname> to get
+    http://localhost:8080/@@admin/@@version?pkg=<pkgname> to get
     the used version of package <pkgname>.
     """
     grok.name('version')
     grok.context(GrokAdminInfoView)
     grok.require('grok.ManageApplications')
+    
     def render(self, pkg='grok'):
         return u'%s %s' % (pkg, getVersion(pkg))
 
 
 class GrokAdminSecurityNotes(grok.View):
     """Display current security notification.
-    Call this view via http://localhost:8080/@@grokadmin/@@secnote
+
+    Call this view via http://localhost:8080/@@admin/@@secnote
     """
     grok.name('secnote')
     grok.context(GrokAdminInfoView)
     grok.require('grok.ManageApplications')
+    
     def render(self):
-        site = grok.getSite()
-        site_manager = site.getSiteManager()
-        notifier = site_manager.queryUtility(ISecurityNotifier, default=None)
-        return notifier.getNotification()
+        notifier = queryUtility(ISecurityNotifier, default=None)
+        return (notifier is not None and notifier.getNotification()
+                or MSG_DISABLED)
 
 
 class Add(grok.View):
@@ -131,28 +75,27 @@
 
     def render(self, application, name, inspectapp=None):
         if name is None or name == "":
-            self.redirect(self.url(self.context))
+            self.redirect(self.url(self.context, 'applications'))
             return
         if name is None or name == "":
-            self.redirect(self.url(self.context))
+            self.redirect(self.url(self.context, 'applications'))
             return
-        app = zope.component.getUtility(grok.interfaces.IApplication,
-                                        name=application)
+        app = getUtility(grok.interfaces.IApplication, name=application)
         try:
             new_app = app()
             grok.notify(grok.ObjectCreatedEvent(new_app))
-            self.context[name] = new_app
-            flash(u'Added %s `%s`.' % (application, name))
+            self.context.root[name] = new_app
+            self.flash(u'Added %s `%s`.' % (application, name))
         except DuplicationError:
-            flash(
-                u'Name `%s` already in use. Please choose another name.' % (
-                name,))
-        self.redirect(self.url(self.context))
+            self.flash(u'Name `%s` already in use. '
+                       u'Please choose another name.' % (name,))
+        self.redirect(self.url(self.context, 'applications'))
 
 
 class ManageApps(grok.View):
     """Manage applications (delete, rename).
     """
+
     grok.require('grok.ManageApplications')
 
     def delete(self, items):
@@ -161,34 +104,35 @@
         msg = u''
         for name in items:
             try:
-                del self.context[name]
+                del self.context.root[name]
                 msg = (u'%sApplication `%s` was successfully '
                        u'deleted.\n' % (msg, name))
             except AttributeError:
                 # Object is broken.. Try it the hard way...
                 # TODO: Try to repair before deleting.
-                if not hasattr(self.context, 'data'):
+                obj = self.context.root[name]
+                if not hasattr(self.context.root, 'data'):
                     msg = (
                         u'%sCould not delete application `%s`: no '
                         u'`data` attribute found.\n' % (msg, name))
                     continue
-                if not isinstance(self.context.data, OOBTree):
+                if not isinstance(self.context.root.data, OOBTree):
                     msg = (
                         u'%sCould not delete application `%s`: no '
                         u'`data` is not a BTree.\n' % (msg, name))
                     continue
-                self.context.data.pop(name)
-                self.context.data._p_changed = True
+                self.context.root.data.pop(name)
+                self.context.root.data._p_changed = True
                 msg = (u'%sBroken application `%s` was successfully '
                        u'deleted.\n' % (msg, name))
 
-        flash(msg)
-        self.redirect(self.url(self.context))
+        self.flash(msg)
+        self.redirect(self.url(self.context, 'applications'))
 
     def render(self, rename=None, delete=None, items=None):
 
         if items is None:
-            return self.redirect(self.url(self.context))
+            return self.redirect(self.url(self.context, 'applications'))
 
         if not isinstance(items, list):
             items = [items]
@@ -199,10 +143,10 @@
             return self.redirect(getURLWithParams(
                     self.url(self.context, '@@grokadmin_rename'),
                     data=dict(items=items)))
-        self.redirect(self.url(self.context))
+        self.redirect(self.url(self.context, 'applications'))
 
 
-class Rename(AdminViewBase):
+class Rename(GrokUIView):
     """Rename Grok applications.
     """
     grok.name('grokadmin_rename')
@@ -210,237 +154,49 @@
     grok.require('grok.ManageApplications')
 
     def update(self, cancel=None, items=None, new_names=None):
-        """We proceed with the renaming, using the request parameters.
-        """
-        if cancel is not None:
-            return self.redirect(self.url(self.context))
+        msg = u''
 
+        if cancel is not None or not items:
+            return self.redirect(self.url(self.context, 'applications'))
+
         if not isinstance(items, list):
             items = [items]
         self.apps = items
 
         if new_names is not None and len(new_names) != len(items):
-            return self.redirect(self.url(self.context))
+            return self.redirect(self.url(self.context, 'applications'))
 
         if new_names is None:
             return
 
         mapping = dict([(items[x], new_names[x]) for x in range(len(items))])
+        root = self.context.__parent__
+        existing = root.keys()
 
         for oldname, newname in mapping.items():
             if oldname == newname:
                 continue
-            if oldname not in self.context.keys():
-                flash('Could not rename %s: not found' % oldname)
+            if oldname not in existing:
+                self.flash('Could not rename %s: not found' % oldname)
                 continue
-            if newname in self.context.keys():
-                flash('`%s` already exists.' % newname)
+            if newname in existing:
+                self.flash('`%s` already exists.' % newname)
                 continue
-            self.context[newname] = self.context[oldname]
-            self.context[newname].__name__ = newname
-            del self.context[oldname]
-            flash('Renamed `%s` to `%s`.' % (oldname, newname))
-        self.redirect(self.url(self.context))
+            root[newname] = root[oldname]
+            root[newname].__name__ = newname
+            del root[oldname]
+            self.flash('Renamed `%s` to `%s`.' % (oldname, newname))
+        self.redirect(self.url(self.context, 'applications'))
         return
 
 
-class Index(AdminViewBase):
+class Index(grok.View):
     """A redirector to the real frontpage.
     """
     grok.name('index.html') # The root folder is not a grok.Model
     grok.require('grok.ManageApplications')
+    grok.context(IRootFolder)
 
-    def update(self):
-        apps = zope.component.getAllUtilitiesRegisteredFor(
-            grok.interfaces.IApplication)
-        self.applications = ("%s.%s" % (x.__module__, x.__name__)
-                             for x in apps)
-        # Go to the first page immediately.
-        self.redirect(self.url('applications'))
-
-
-class Applications(AdminViewBase):
-    """View for application management.
-    """
-    grok.name('applications')
-    grok.require('grok.ManageApplications')
-
-
-    def update(self):
-        # Available apps...
-        apps = zope.component.getAllUtilitiesRegisteredFor(
-            grok.interfaces.IApplication)
-        self.applications = (
-            {'name': "%s.%s" % (x.__module__, x.__name__),
-             'docurl':("%s.%s" % (x.__module__, x.__name__)).replace('.', '/'),
-             'descr': x.__doc__}
-            for x in apps)
-
-        # Installed apps...
-        inst_apps = [x for x in self.context.values()
-                     if hasattr(x, '__class__') and x.__class__ in apps
-                     and not issubclass(x.__class__, Broken)]
-        inst_apps.sort(lambda x, y: cmp(x.__name__, y.__name__))
-        self.installed_applications = inst_apps
-
-        # Broken apps...
-        broken_apps = [{'obj':y, 'name':x} for x,y in self.context.items()
-                       if isinstance(y, Broken)]
-        broken_apps.sort(lambda x, y: cmp(x['name'], y['name']))
-        self.broken_applications = broken_apps
-
-
-class AdminMessageSource(grok.GlobalUtility):
-
-    grok.name('admin')
-    zope.interface.implements(z3c.flashmessage.interfaces.IMessageSource)
-
-    message = None
-
-    def send(self, message, type='admin'):
-        self.message = z3c.flashmessage.message.PersistentMessage(message,
-                                                                  type)
-
-    def list(self, type=None):
-        if self.message is None:
-            return
-        if type is None or self.message.type == type:
-            yield self.message
-
-    def delete(self, message):
-        if message is self.message:
-            self.message = None
-        else:
-            raise KeyError(message)
-
-
-class GrokAdminMacros(AdminViewBase):
-    """Provides the o-wrap layout.
-    """
-    grok.context(Interface)
-
-
-class Server(AdminViewBase, ZODBControlView):
-    """Zope3 management screen.
-    """
-    grok.require('grok.ManageApplications')
-
-    @property
-    def security_notifier_url(self):
-        """Get the URL to look up for security warnings.
-        """
-        return self.security_notifier.lookup_url
-    
-    @property
-    def security_notifier(self):
-        """Get a local security notifier.
-
-        The security notifier is installed as a local utility by an
-        event handler in the security module.
-        """
-        site = grok.getSite()
-        site_manager = site.getSiteManager()
-        return site_manager.queryUtility(ISecurityNotifier, default=None)
-    
-    @property
-    def secnotes_enabled(self):
-        if self.security_notifier is None:
-            # Safety belt if installation of notifier failed
-            return False
-        return self.security_notifier.enabled
-
-    @property
-    def secnotes_message(self):
-        if self.security_notifier is None:
-            return u'Security notifier is not installed.'
-        return self.security_notifier.getNotification()
-    
-    @property
-    def server_control(self):
-        return zope.component.queryUtility(IServerControl, '', None)
-
-    @property
-    def runtime_info(self):
-        riv = RuntimeInfoView()
-        riv.context = applicationController
-        return riv.runtimeInfo()
-
-    @property
-    def current_message(self):
-        source = zope.component.getUtility(
-          z3c.flashmessage.interfaces.IMessageSource, name='admin')
-        messages = list(source.list())
-        if messages:
-            return messages[0]
-
-    def updateSecurityNotifier(self, setsecnotes=None, setsecnotesource=None,
-                               secnotesource=None):
-        if self.security_notifier is None:
-            return
-        if setsecnotesource is not None:
-            self.security_notifier.setLookupURL(secnotesource)
-        if setsecnotes is not None:
-            if self.security_notifier.enabled is True:
-                self.security_notifier.disable()
-            else:
-                self.security_notifier.enable()
-        if self.secnotes_enabled is False:
-            return
-        return
-        
-    def update(self, time=None, restart=None, shutdown=None,
-               setsecnotes=None, secnotesource=None, setsecnotesource=None,
-               admin_message=None, submitted=False, dbName="", pack=None,
-               days=0):
-
-        # Packing control
-        if pack is not None:
-            return self.pack(dbName, days)
-
-        # Security notification control
-        self.updateSecurityNotifier(setsecnotes, setsecnotesource,
-                                    secnotesource)
-
-        
-        if not submitted:
-            return
-
-        # Admin message control
-        source = zope.component.getUtility(
-          z3c.flashmessage.interfaces.IMessageSource, name='admin')
-        if admin_message is not None:
-            source.send(admin_message)
-        elif getattr(source, 'current_message', False):
-            source.delete(source.current_message)
-
-        # Restart control
-        if time is not None:
-            try:
-                time = int(time)
-            except:
-                time = 0
-        else:
-            time = 0
-
-        if restart is not None:
-            self.server_control.restart(time)
-        elif shutdown is not None:
-            self.server_control.shutdown(time)
-
-        self.redirect(self.url())
-
-    def pack(self, dbName, days):
-        try:
-            days = int(days)
-        except ValueError:
-            flash('Error: Invalid Number')
-            return
-        db = zope.component.getUtility(IDatabase, name=dbName)
-        print "DB: ", db, days
-        db.pack(days=days)
-        return
-        try:
-            db.pack(days=days)
-            flash('ZODB `%s` successfully packed.' % (dbName))
-        except FileStorageError, err:
-            flash('ERROR packing ZODB `%s`: %s' % (dbName, err))
+    def render(self):
+        grokui_url = self.url(self.context) + '/++grokui++/applications'
+        self.redirect(grokui_url)

Copied: grokui.admin/trunk/versions.cfg (from rev 108638, grokui.admin/branches/fancy-layout/versions.cfg)
===================================================================
--- grokui.admin/trunk/versions.cfg	                        (rev 0)
+++ grokui.admin/trunk/versions.cfg	2010-01-29 15:59:54 UTC (rev 108639)
@@ -0,0 +1,115 @@
+# This is a copy of grok/versions.cfg revision 102959.
+#
+# Don't make local modifications here, just override it explicitly in
+# your buildout's [versions] part.
+
+[versions]
+ClientForm = 0.2.9
+grokcore.component = 1.7
+grokcore.formlib = 1.3
+grokcore.security = 1.2
+grokcore.view = 1.11
+grokcore.viewlet = 1.2
+martian = 0.11
+mechanize = 0.1.7b
+pytz = 2007k
+RestrictedPython = 3.4.2
+simplejson = 1.7.1
+z3c.autoinclude = 0.2.2
+z3c.flashmessage = 1.0
+z3c.recipe.eggbasket = 0.4.3
+z3c.testsetup = 0.4
+zc.catalog = 1.2.0
+ZConfig = 2.5.1
+zc.recipe.testrunner = 1.0.0
+zdaemon = 2.0.2
+ZODB3 = 3.8.3
+zodbcode = 3.4.0
+zope.annotation = 3.4.1
+zope.app.apidoc = 3.4.3
+zope.app.applicationcontrol = 3.4.3
+zope.app.appsetup = 3.4.1
+zope.app.authentication = 3.4.4
+zope.app.basicskin = 3.4.0
+zope.app.broken = 3.4.0
+zope.app.catalog = 3.5.1
+zope.app.component = 3.4.1
+zope.app.container = 3.5.6
+zope.app.content = 3.4.0
+zope.app.debug = 3.4.1
+zope.app.dependable = 3.4.0
+zope.app.error = 3.5.1
+zope.app.exception = 3.4.1
+zope.app.file = 3.4.4
+zope.app.folder = 3.4.0
+zope.app.form = 3.4.1
+zope.app.generations = 3.4.1
+zope.app.http = 3.4.1
+zope.app.i18n = 3.4.4
+zope.app.interface = 3.4.0
+zope.app.intid = 3.4.1
+zope.app.keyreference = 3.4.1
+zope.app.locales = 3.4.5
+zope.app.onlinehelp = 3.4.1
+zope.app.pagetemplate = 3.4.1
+zope.app.preference = 3.4.1
+zope.app.principalannotation = 3.4.0
+zope.app.publication = 3.4.3
+zope.app.publisher = 3.5.1
+zope.app.renderer = 3.4.0
+zope.app.rotterdam = 3.4.1
+zope.app.schema = 3.4.0
+zope.app.security = 3.5.2
+zope.app.securitypolicy = 3.4.6
+zope.app.server = 3.4.2
+zope.app.session = 3.5.1
+zope.app.skins = 3.4.0
+zope.app.testing = 3.4.3
+zope.app.tree = 3.4.0
+zope.app.twisted = 3.4.1
+zope.app.wsgi = 3.4.2
+zope.app.zapi = 3.4.0
+zope.app.zcmlfiles = 3.4.3
+zope.app.zopeappgenerations = 3.4.0
+zope.cachedescriptors = 3.4.1
+zope.component = 3.4.0
+zope.configuration = 3.4.0
+zope.contentprovider = 3.4.0
+zope.contenttype = 3.4.0
+zope.copypastemove = 3.4.0
+zope.datetime = 3.4.0
+zope.deferredimport = 3.4.0
+zope.deprecation = 3.4.0
+zope.dottedname = 3.4.2
+zope.dublincore = 3.4.0
+zope.error = 3.5.1
+zope.event = 3.4.0
+zope.exceptions = 3.4.0
+zope.filerepresentation = 3.4.0
+zope.formlib = 3.4.0
+zope.hookable = 3.4.0
+zope.i18n = 3.4.0
+zope.i18nmessageid = 3.4.3
+zope.index = 3.4.1
+zope.interface = 3.4.1
+zope.lifecycleevent = 3.4.0
+zope.location = 3.4.0
+zope.minmax = 1.1.0
+zope.modulealias = 3.4.0
+zope.pagetemplate = 3.4.0
+zope.proxy = 3.4.2
+zope.publisher = 3.4.9
+zope.schema = 3.4.0
+zope.security = 3.4.1
+zope.securitypolicy = 3.4.1
+zope.server = 3.4.3
+zope.session = 3.4.1
+zope.size = 3.4.0
+zope.structuredtext = 3.4.0
+zope.tal = 3.4.1
+zope.tales = 3.4.0
+zope.testbrowser = 3.4.2
+zope.testing = 3.7.6
+zope.thread = 3.4
+zope.traversing = 3.4.1
+zope.viewlet = 3.4.2



More information about the checkins mailing list