[Zope-CVS] CVS: Products/DBTab - ControlPanelPatch.py:1.1 UndoPatch.py:1.1 DBTab.py:1.2 MainConfiguration.py:1.2 MountedObject.py:1.2 __init__.py:1.2 version.txt:1.2

Shane Hathaway shane@zope.com
Wed, 16 Oct 2002 17:13:05 -0400


Update of /cvs-repository/Products/DBTab
In directory cvs.zope.org:/tmp/cvs-serv20980

Modified Files:
	DBTab.py MainConfiguration.py MountedObject.py __init__.py 
	version.txt 
Added Files:
	ControlPanelPatch.py UndoPatch.py 
Log Message:
- Added a patch to view and manage all databases in the Control_Panel.

- Added a patch for Zope's undo feature so you can undo in the mounted
  databases.  (Yee-haw!)

- Gave each database an independent activity monitor.


=== Added File Products/DBTab/ControlPanelPatch.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
# 
##############################################################################
"""Modifications to the control panel for managing multiple databases.

$Id: ControlPanelPatch.py,v 1.1 2002/10/16 21:13:04 shane Exp $
"""

import Acquisition
from Acquisition import aq_base
import Globals
from OFS.SimpleItem import SimpleItem
from App.CacheManager import CacheManager
from App.ApplicationManager import ApplicationManager, DatabaseManager
from Products.PageTemplates.PageTemplateFile import PageTemplateFile

from MainConfiguration import configuration
from Exceptions import DBTabOverrideError


class AltDatabaseManager(DatabaseManager, CacheManager):
    """Database management
    """
    db_name = ApplicationManager.db_name
    db_size = ApplicationManager.db_size
    manage_pack = ApplicationManager.manage_pack

Globals.InitializeClass(AltDatabaseManager)


class FakeConnection:
    # Supports the methods of Connection that CacheManager needs

    def __init__(self, db, parent_jar):
        self._db = db
        self.version = parent_jar.getVersion()

    def db(self):
        return self._db

    def getVersion(self):
        return self.version


class DatabaseChooser (SimpleItem):
    """Lets you choose which database to view
    """
    meta_type = 'Database Management'
    name = title = 'Database Management'
    icon = 'p_/DatabaseManagement_icon'
    isPrincipiaFolderish = 1

    manage_options=(
        {'label':'Databases', 'action':'manage_main'},
        )

    manage_main = PageTemplateFile('www/chooseDatabase.pt', globals())

    def __init__(self, id):
        self.id = id

    def getDatabaseNames(self):
        names = configuration.listDatabaseNames()
        names.sort()
        return names

    def __getitem__(self, name):
        db = configuration.getDatabase(name=name)
        m = AltDatabaseManager()
        m.id = name
        m._p_jar = FakeConnection(db, self.getPhysicalRoot()._p_jar)
        return m.__of__(self)

    def tpValues(self):
        names = self.getDatabaseNames()
        res = []
        for name in names:
            m = AltDatabaseManager()
            m.id = name
            # Avoid opening the database just for the tree widget.
            m._p_jar = None
            res.append(m.__of__(self))
        return res

Globals.InitializeClass(DatabaseChooser)


if 1:
    # Replace the "Database" control panel with a database chooser
    chooser = DatabaseChooser('Database')
    ApplicationManager.Database = chooser


if 1:
    # Patch CacheManager so it no longer sets database cache parameters.
    # In theory, cache parameters are better managed by a configuration file.
    def my_initialize_cache(self):
        " "
        pass

    def my_manage_cache_size(self, value, REQUEST):
        " "
        raise DBTabOverrideError(
            "Database cache settings must be managed through dbtab.conf.")

    def my_cache_size(self):
        " "
        return self._p_jar.db().getCacheSize()

    CacheManager.initialize_cache = my_initialize_cache
    CacheManager.manage_cache_size = my_manage_cache_size
    CacheManager.cache_size = my_cache_size



=== Added File Products/DBTab/UndoPatch.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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
# 
##############################################################################
"""Modifications to UndoSupport for undo in the local database.

The changes are quite small and need to be integrated into Zope as
soon as possible.

$Id: UndoPatch.py,v 1.1 2002/10/16 21:13:04 shane Exp $
"""

from Acquisition import aq_inner, aq_parent
from App.Undo import UndoSupport, Prefix, encode64, decode64
from DateTime import DateTime
from AccessControl import getSecurityManager
import base64

if 1:

    def undoable_transactions(self, first_transaction=None,
                              last_transaction=None,
                              PrincipiaUndoBatchSize=None):

        if first_transaction is None:
            first_transaction=self.get_request_var_or_attr(
                'first_transaction', 0)

        if PrincipiaUndoBatchSize is None:
            PrincipiaUndoBatchSize=self.get_request_var_or_attr(
                'PrincipiaUndoBatchSize', 20)

        if last_transaction is None:
            last_transaction=self.get_request_var_or_attr(
                'last_transaction',
                first_transaction+PrincipiaUndoBatchSize)

        spec={}

        # A user is allowed to undo transactions that were initiated
        # by any member of a user folder in the place where the user
        # is defined.
        user = getSecurityManager().getUser()
        if hasattr(user, 'aq_parent'):
            path = '/'.join(user.aq_parent.getPhysicalPath()[1:-1])
        else:
            path=''
        if path: spec['user_name']=Prefix(path)

        ##############################
        # Here is the patched part.
        if getattr(aq_parent(aq_inner(self)), '_p_jar') == self._p_jar:
            # We only want to undo things done here
            opath='/'.join(self.getPhysicalPath())
        else:
            # Special case: at the mounted root of a database,
            # allow global undo.
            opath = None
        if opath: spec['description']=Prefix(opath)
        ##############################

        r = self._p_jar.db().undoInfo(
            first_transaction, last_transaction, spec)

        encode = base64.encodestring
        for d in r:
            d['time']=t=DateTime(d['time'])
            desc = d['description']
            tid=d['id']
            if desc:
                desc = desc.split()
                d1=desc[0]
                desc = ''.join(desc[1:])
                if len(desc) > 60: desc = desc[:56]+' ...'
                tid = "%s %s %s %s" % (encode64(tid), t, d1, desc)
            else:
                tid = "%s %s" % (encode64(tid), t)
            d['id']=tid


        return r

    def manage_undo_transactions(self, transaction_info=(), REQUEST=None):
        """
        """
        ##############################
        # Here is the patched part.
        undo = self._p_jar.db().undo
        ##############################

        for tid in transaction_info:
            tid=tid.split()
            if tid:
                get_transaction().note("Undo %s" % ''.join(tid[1:]))
                tid=decode64(tid[0])
                undo(tid)

        if REQUEST is None: return
        REQUEST['RESPONSE'].redirect("%s/manage_UndoForm" % REQUEST['URL1'])
        return ''

UndoSupport.undoable_transactions = undoable_transactions
UndoSupport.manage_undo_transactions = manage_undo_transactions



=== Products/DBTab/DBTab.py 1.1.1.1 => 1.2 ===
--- Products/DBTab/DBTab.py:1.1.1.1	Tue Oct 15 13:49:19 2002
+++ Products/DBTab/DBTab.py	Wed Oct 16 17:13:04 2002
@@ -22,6 +22,8 @@
 from thread import allocate_lock
 builtin = sys.modules['__builtin__']
 
+from ZODB.ActivityMonitor import ActivityMonitor
+
 from Exceptions import DBTabConfigurationError
 from StorageTypes import storage_types, asBoolean
 from ClassFactories import class_factories
@@ -207,6 +209,8 @@
         database = self.database_class(storage, **self.database_args)
         database.klass = self.connection_class
         database.setClassFactory(cf)
+        # Each database has an independent record of activity.
+        database.setActivityMonitor(ActivityMonitor())
         return database
 
     def getVirtualMountPaths(self):
@@ -284,6 +288,8 @@
                 self._mountPathError(mount_path)
         db = self.opened.get(name)
         if db is None:
+            if not self.db_factories.has_key(name):
+                raise KeyError('%s is not a configured database' % repr(name))
             self.lock.acquire()
             try:
                 # Check again, since the database may have been created
@@ -307,7 +313,7 @@
 
 
     def _createDatabase(self, name):
-        factory = self.db_factories.get(name)
+        factory = self.db_factories[name]
         db = factory.create()
         self.opened[name] = db
         return db


=== Products/DBTab/MainConfiguration.py 1.1.1.1 => 1.2 ===
--- Products/DBTab/MainConfiguration.py:1.1.1.1	Tue Oct 15 13:49:20 2002
+++ Products/DBTab/MainConfiguration.py	Wed Oct 16 17:13:04 2002
@@ -19,7 +19,6 @@
 import os
 
 from DBTab import DBTab
-from Exceptions import DBTabOverrideError
 
 # Read the configuration from $INSTANCE_HOME/dbtab.conf if available,
 # otherwise fall back to dbtab.conf.in.
@@ -29,27 +28,4 @@
 configuration = DBTab([main_fn], [fallback_fn])
 
 configuration.startup()
-
-
-if 1:
-    # Patch App.CacheManager so it no longer sets database cache parameters.
-    # In theory, cache parameters are better managed by a configuration file.
-    from App.CacheManager import CacheManager
-
-    def my_initialize_cache(self):
-        " "
-        pass
-
-    def my_manage_cache_size(self, value, REQUEST):
-        " "
-        raise DBTabOverrideError(
-            "Database cache settings must be managed through dbtab.conf.")
-
-    def my_cache_size(self):
-        " "
-        return self._p_jar.db().getCacheSize()
-
-    CacheManager.initialize_cache = my_initialize_cache
-    CacheManager.manage_cache_size = my_manage_cache_size
-    CacheManager.cache_size = my_cache_size
 


=== Products/DBTab/MountedObject.py 1.1.1.1 => 1.2 ===
--- Products/DBTab/MountedObject.py:1.1.1.1	Tue Oct 15 13:49:19 2002
+++ Products/DBTab/MountedObject.py	Wed Oct 16 17:13:04 2002
@@ -30,8 +30,12 @@
 _www = os.path.join(os.path.dirname(__file__), 'www')
 
 
+configuration = None
+
 def getConfiguration():
-    from MainConfiguration import configuration
+    global configuration
+    if configuration is None:
+        from MainConfiguration import configuration
     return configuration
 
 


=== Products/DBTab/__init__.py 1.1.1.1 => 1.2 ===
--- Products/DBTab/__init__.py:1.1.1.1	Tue Oct 15 13:49:20 2002
+++ Products/DBTab/__init__.py	Wed Oct 16 17:13:04 2002
@@ -36,3 +36,6 @@
                       MountedObject.manage_addMounts,),
         )
 
+    import ControlPanelPatch
+    import UndoPatch
+


=== Products/DBTab/version.txt 1.1.1.1 => 1.2 ===
--- Products/DBTab/version.txt:1.1.1.1	Tue Oct 15 13:49:19 2002
+++ Products/DBTab/version.txt	Wed Oct 16 17:13:04 2002
@@ -1 +1 @@
-1.0-beta2
+1.0-beta2+