[Checkins] SVN: zmi.core/trunk/src/zmi/core/undo/ Copy zope.app.undo browser package to zmi.core.
Yusei Tahara
yusei at domen.cx
Sat Aug 8 02:25:28 EDT 2009
Log message for revision 102567:
Copy zope.app.undo browser package to zmi.core.
Changed:
A zmi.core/trunk/src/zmi/core/undo/
A zmi.core/trunk/src/zmi/core/undo/__init__.py
A zmi.core/trunk/src/zmi/core/undo/browser.py
A zmi.core/trunk/src/zmi/core/undo/configure.zcml
A zmi.core/trunk/src/zmi/core/undo/tests.py
A zmi.core/trunk/src/zmi/core/undo/undo_all.pt
A zmi.core/trunk/src/zmi/core/undo/undo_macros.pt
A zmi.core/trunk/src/zmi/core/undo/undo_more.pt
-=-
Added: zmi.core/trunk/src/zmi/core/undo/browser.py
===================================================================
--- zmi.core/trunk/src/zmi/core/undo/browser.py (rev 0)
+++ zmi.core/trunk/src/zmi/core/undo/browser.py 2009-08-08 06:25:26 UTC (rev 102567)
@@ -0,0 +1,81 @@
+##############################################################################
+#
+# Copyright (c) 2004 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.
+#
+##############################################################################
+"""Undo view
+
+$Id: browser.py 67630 2006-04-27 00:54:03Z jim $
+"""
+import zope.component
+from zope.security.interfaces import ForbiddenAttribute
+from zope.publisher.browser import BrowserView
+from zope.app.undo.interfaces import IUndoManager
+
+class UndoView(BrowserView):
+ """Undo view"""
+
+ def principalLastTransactionIsUndo(self):
+ """Return True if the authenticated principal's last
+ transaction is an undo transaction.
+ """
+ request = self.request
+ undo = zope.component.getUtility(IUndoManager)
+ txn_info = undo.getPrincipalTransactions(request.principal, first=0,
+ last=1)
+ if txn_info:
+ return txn_info[0].get('undo', False)
+ return False
+
+ def undoPrincipalLastTransaction(self):
+ """Undo the authenticated principal's last transaction and
+ return where he/she came from"""
+ request = self.request
+ undo = zope.component.getUtility(IUndoManager)
+ txn_info = undo.getPrincipalTransactions(request.principal, first=0,
+ last=1)
+ if txn_info:
+ id = txn_info[0]['id']
+ undo.undoPrincipalTransactions(request.principal, [id])
+ target = request.get('HTTP_REFERER', '@@SelectedManagementView.html')
+ request.response.redirect(target)
+
+ def undoAllTransactions(self, ids):
+ """Undo transactions specified in 'ids'."""
+ undo = zope.component.getUtility(IUndoManager)
+ undo.undoTransactions(ids)
+ self._redirect()
+
+ def undoPrincipalTransactions(self, ids):
+ """Undo transactions that were issued by the authenticated
+ user specified in 'ids'."""
+ undo = zope.component.getUtility(IUndoManager)
+ undo.undoPrincipalTransactions(self.request.principal, ids)
+ self._redirect()
+
+ def _redirect(self):
+ target = "@@SelectedManagementView.html"
+ self.request.response.redirect(target)
+
+ def getAllTransactions(self, first=0, last=-20, showall=False):
+ context = None
+ if not showall:
+ context = self.context
+ undo = zope.component.getUtility(IUndoManager)
+ return undo.getTransactions(context, first, last)
+
+ def getPrincipalTransactions(self, first=0, last=-20, showall=False):
+ context = None
+ if not showall:
+ context = self.context
+ undo = zope.component.getUtility(IUndoManager)
+ return undo.getPrincipalTransactions(self.request.principal, context,
+ first, last)
Added: zmi.core/trunk/src/zmi/core/undo/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/undo/configure.zcml (rev 0)
+++ zmi.core/trunk/src/zmi/core/undo/configure.zcml 2009-08-08 06:25:26 UTC (rev 102567)
@@ -0,0 +1,98 @@
+<configure
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zope"
+ >
+
+ <browser:pages
+ for="*"
+ permission="zope.UndoOwnTransactions"
+ class="zmi.core.undo.browser.UndoView"
+ >
+
+ <browser:page
+ name="principalLastTransactionIsUndo"
+ attribute="principalLastTransactionIsUndo"
+ />
+
+ <browser:page
+ name="undo.html"
+ attribute="undoPrincipalLastTransaction"
+ />
+
+ <browser:page
+ name="undoPrincipalTransactions.html"
+ attribute="undoPrincipalTransactions"
+ />
+
+ <browser:page
+ name="undoMore.html"
+ template="undo_more.pt"
+ />
+
+ </browser:pages>
+
+ <browser:pages
+ for="*"
+ permission="zope.UndoAllTransactions"
+ class="zmi.core.undo.browser.UndoView"
+ >
+
+ <browser:page
+ name="undoAllTransactions.html"
+ attribute="undoAllTransactions"
+ />
+
+ <browser:page
+ name="undoAll.html"
+ template="undo_all.pt"
+ />
+
+ </browser:pages>
+
+ <!-- We hereby imply that users having zope.UndoAllTransactions also
+ have zope.UndoOwnTransactions -->
+ <browser:page
+ for="*"
+ name="undo_macros"
+ permission="zope.UndoOwnTransactions"
+ template="undo_macros.pt"
+ />
+
+
+ <!-- menu items -->
+
+ <browser:menuItem
+ for="*"
+ menu="zmi_actions"
+ title="Undo!"
+ action="@@undo.html"
+ permission="zope.UndoOwnTransactions"
+ filter="not:context/@@principalLastTransactionIsUndo"
+ />
+
+ <browser:menuItem
+ for="*"
+ menu="zmi_actions"
+ title="Redo!"
+ action="@@undo.html"
+ permission="zope.UndoOwnTransactions"
+ filter="context/@@principalLastTransactionIsUndo"
+ />
+
+ <browser:menuItem
+ for="*"
+ menu="zmi_actions"
+ title="Undo more"
+ action="@@undoMore.html"
+ permission="zope.UndoOwnTransactions"
+ />
+
+ <browser:menuItem
+ for="*"
+ menu="zmi_actions"
+ title="Undo all"
+ action="@@undoAll.html"
+ permission="zope.UndoAllTransactions"
+ />
+
+</configure>
Added: zmi.core/trunk/src/zmi/core/undo/tests.py
===================================================================
--- zmi.core/trunk/src/zmi/core/undo/tests.py (rev 0)
+++ zmi.core/trunk/src/zmi/core/undo/tests.py 2009-08-08 06:25:26 UTC (rev 102567)
@@ -0,0 +1,168 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 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.
+#
+##############################################################################
+"""Undo Tests
+
+$Id: test_undoview.py 98107 2009-03-14 17:56:45Z nadako $
+"""
+from datetime import datetime
+from unittest import TestCase, main, makeSuite
+
+from zope.component import provideUtility
+from zope.interface import implements
+from zope.principalregistry.principalregistry import principalRegistry
+from zope.publisher.browser import TestRequest
+
+from zope.app.component.testing import PlacefulSetup
+from zope.app.undo.interfaces import IUndoManager
+from zmi.core.undo.browser import UndoView
+
+class TestIUndoManager(object):
+ implements(IUndoManager)
+
+ def __init__(self):
+ self.dummy_db = [
+ dict(id='1', user_name='monkey', description='thing1',
+ time='today', datetime=datetime(2001, 01, 01, 12, 00, 00)),
+ dict(id='2', user_name='monkey', description='thing2',
+ time='today', datetime=datetime(2001, 01, 01, 12, 00, 00)),
+ dict(id='3', user_name='bonobo', description='thing3',
+ time='today', datetime=datetime(2001, 01, 01, 12, 00, 00)),
+ dict(id='4', user_name='monkey', description='thing4',
+ time='today', datetime=datetime(2001, 01, 01, 12, 00, 00)),
+ dict(id='5', user_name='bonobo', description='thing5',
+ time='today', datetime=datetime(2001, 01, 01, 12, 00, 00)),
+ dict(id='6', user_name='bonobo', description='thing6',
+ time='today', datetime=datetime(2001, 01, 01, 12, 00, 00)),
+ ]
+ self.dummy_db.reverse()
+
+ def getTransactions(self, context=None, first=0, last=-20):
+ self.context = context
+ list = [dict for dict in self.dummy_db
+ if not dict.get('undone', False)]
+ return list[first:abs(last)]
+
+ def getPrincipalTransactions(self, principal, context=None,
+ first=0, last=-20):
+ self.principal = principal
+ self.context = context
+ list = [dict for dict in self.dummy_db
+ if dict['user_name'] == principal.id
+ and not dict.get('undone', False)]
+ return list[first:abs(last)]
+
+ def _emulatePublication(self, request):
+ self._user_name = request.principal.id
+
+ def undoTransactions(self, ids):
+ # just remove an element for now
+ for db_record in self.dummy_db:
+ if db_record['id'] in ids:
+ db_record['undone'] = True
+
+ self.dummy_db.insert(0, dict(
+ id=str(len(self.dummy_db)+1), user_name=self._user_name,
+ description='undo', undo=True,
+ datetime=datetime(2001, 01, 01, 12, 00, 00)
+ ))
+
+ def undoPrincipalTransactions(self, principal, ids):
+ self.principal = principal
+ self.undoTransactions(ids)
+
+class Test(PlacefulSetup, TestCase):
+
+ def setUp(self):
+ super(Test, self).setUp()
+ self.request = TestRequest()
+ self.undo = TestIUndoManager()
+ provideUtility(self.undo, IUndoManager)
+ principalRegistry.definePrincipal('monkey', 'Monkey Patch',
+ login='monkey')
+ principalRegistry.definePrincipal('bonobo', 'Bonobo Abdul-Fasil',
+ login='bonobo')
+
+ def testPrincipalLastTransactionIsUndo(self):
+ request = self.request
+ bonobo = principalRegistry.getPrincipal('bonobo')
+ request.setPrincipal(bonobo)
+
+ view = UndoView(self.folder1, request)
+ self.failIf(view.principalLastTransactionIsUndo())
+
+ # now undo the last transaction
+ self.undo._emulatePublication(request)
+ self.undo.undoTransactions(['6'])
+
+ self.assert_(view.principalLastTransactionIsUndo())
+
+ def testUndoPrincipalLastTransaction(self):
+ request = self.request
+ bonobo = principalRegistry.getPrincipal('bonobo')
+ request.setPrincipal(bonobo)
+
+ self.undo._emulatePublication(request)
+ view = UndoView(self.folder1, request)
+ view.undoPrincipalLastTransaction()
+
+ last_txn = self.undo.getTransactions(None, 0, 1)[0]
+ self.assert_(last_txn.has_key('undo'))
+ self.assert_(last_txn['undo'])
+ self.assertEqual(last_txn['user_name'], bonobo.id)
+
+ def testGetAllTransactions(self):
+ request = self.request
+ view = UndoView(self.folder1, request)
+ expected = self.undo.getTransactions()
+ self.assertEqual(view.getAllTransactions(), expected)
+ self.assert_(self.undo.context is self.folder1)
+
+ # test showall parameter
+ view.getAllTransactions(showall=True)
+ self.assert_(self.undo.context is None)
+
+ def testGetPrincipalTransactions(self):
+ request = self.request
+ bonobo = principalRegistry.getPrincipal('bonobo')
+ request.setPrincipal(bonobo)
+
+ view = UndoView(self.folder1, request)
+ expected = self.undo.getPrincipalTransactions(bonobo)
+ self.assertEqual(view.getPrincipalTransactions(), expected)
+ self.assert_(self.undo.context is self.folder1)
+ self.assert_(self.undo.principal is bonobo)
+
+ # test showall parameter and principal
+ self.undo.principal = None
+ view.getPrincipalTransactions(showall=True)
+ self.assert_(self.undo.context is None)
+ self.assert_(self.undo.principal is bonobo)
+
+ def testUndoPrincipalTransactions(self):
+ request = self.request
+ bonobo = principalRegistry.getPrincipal('bonobo')
+ request.setPrincipal(bonobo)
+ view = UndoView(self.folder1, request)
+
+ # Just test whether it accepts the principal. We know that
+ # our undo dummy above "works".
+ self.undo._emulatePublication(request)
+ view.undoPrincipalTransactions(['6'])
+ self.assert_(self.undo.principal is bonobo)
+
+def test_suite():
+ return makeSuite(Test)
+
+if __name__=='__main__':
+ main(defaultTest='test_suite')
Added: zmi.core/trunk/src/zmi/core/undo/undo_all.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/undo/undo_all.pt (rev 0)
+++ zmi.core/trunk/src/zmi/core/undo/undo_all.pt 2009-08-08 06:25:26 UTC (rev 102567)
@@ -0,0 +1,37 @@
+<html metal:use-macro="context/@@standard_macros/page"
+ i18n:domain="zope">
+<body>
+<div metal:fill-slot="body">
+
+<h2 i18n:translate="">Undo all</h2>
+
+<p i18n:translate="">This form lets you undo all transactions
+initiated by any user.</p>
+
+<p i18n:translate="">Select one or more transactions from the list
+below and click the button below. Please be aware that you may only
+undo a transaction if the object has not been modified in a later
+transaction by you or any other user.</p>
+
+<tal:var define="global macros nocall:context/@@undo_macros" />
+<div metal:use-macro="macros/global_vars" />
+
+<div metal:use-macro="macros/location_link" />
+
+<form action="@@undoAllTransactions.html" method="post">
+<div metal:use-macro="macros/previous_batch" />
+
+<div metal:use-macro="macros/undo_log">
+ <div metal:fill-slot="define_info">
+ <tal:var define="global undo_info python:view.getAllTransactions(
+ first=first, last=-batch_size, showall=showall)" />
+ </div>
+</div>
+
+<div metal:use-macro="macros/submit_button" />
+<div metal:use-macro="macros/next_batch" />
+</form>
+
+</div>
+</body>
+</html>
Added: zmi.core/trunk/src/zmi/core/undo/undo_macros.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/undo/undo_macros.pt (rev 0)
+++ zmi.core/trunk/src/zmi/core/undo/undo_macros.pt 2009-08-08 06:25:26 UTC (rev 102567)
@@ -0,0 +1,126 @@
+<html i18n:domain="zope">
+<body>
+
+<!-- This file contains macros common to undo views. -->
+
+<div metal:define-macro="global_vars">
+ <tal:var define="global batch_size python:10;
+ global first python:int(request.get('first', 0));
+ global showall python:bool(request.get('showall', False))"
+ />
+</div>
+
+<div metal:define-macro="location_link">
+ <span tal:condition="showall">
+ <p>
+ <span i18n:translate="">You are looking at transactions
+ regardless of location.</span> <a href="?"
+ i18n:translate="">View only transactions in this location</a>.
+ </p>
+ </span>
+
+ <span tal:condition="not:showall">
+ <p>
+ <span i18n:translate="">You are looking only at transactions
+ from this location.</span> <a href="?showall=true"
+ i18n:translate="">View transactions regardless of location</a>.
+ </p>
+ </span>
+</div>
+
+<div metal:define-macro="undo_log">
+
+ <!-- We expect the list of undo information in the global
+ 'undo_info' variable -->
+
+ <div metal:define-slot="define_info">
+ <tal:var define="global undo_info python:[]" />
+ </div>
+
+ <table style="width: 100%; border: none;">
+
+ <tr>
+ <th></th>
+ <th i18n:translate="heading-location">Location</th>
+ <th i18n:translate="heading-request-info">Request info</th>
+ <th i18n:translate="heading-principal">Principal</th>
+ <th i18n:translate="heading-date">Date</th>
+ <th i18n:translate="heading-description">Description</th>
+ </tr>
+
+ <tal:block repeat="item undo_info">
+ <tr tal:attributes="class python:repeat['item'].odd() and
+ 'content odd' or 'content even'">
+
+ <td width="16">
+ <input type="checkbox" name="ids:list" value="-1"
+ tal:attributes="value item/id" />
+ </td>
+
+ <td tal:define="location item/location | nothing">
+ <tal:location replace="location" />
+ <tal:if condition="not:location"
+ i18n:translate="label-not-available">not available</tal:if>
+ </td>
+
+ <td>
+ <tal:request_info replace="item/request_type | nothing" /><br />
+ <tal:request_info replace="item/request_info | nothing" />
+ <tal:if condition="python:not item.get('request_type', '') and
+ not item.get('request_info', '')"
+ i18n:translate="label-not-available">not available</tal:if>
+ </td>
+
+ <td>
+ <tal:principal replace="item/principal/id | nothing" />
+ <tal:if condition="not:exists:item/principal/id"
+ i18n:translate="label-not-available">not available</tal:if>
+ </td>
+
+ <td tal:define="formatter python:request.locale.dates.getFormatter(
+ 'dateTime', 'medium')"
+ tal:content="python:formatter.format(item['datetime'])">
+ </td>
+
+ <td>
+ <tal:description i18n:translate=""
+ replace="item/description | nothing" />
+ <tal:if condition="not:item/description"
+ i18n:translate="label-not-available">not available</tal:if>
+ </td>
+ </tr>
+ </tal:block>
+
+ </table>
+</div>
+
+<p metal:define-macro="next_batch">
+ <a tal:define="showall python:showall and '&showall=true' or ''"
+ tal:attributes="href python:'?first=%s%s'%(first+batch_size, showall)">
+ <<<
+ <tal:text i18n:translate="">
+ View <tal:num replace="batch_size" i18n:name="number" />
+ earlier transactions
+ </tal:text>
+ </a>
+</p>
+
+<p metal:define-macro="previous_batch">
+ <a tal:define="showall python:showall and '&showall=true' or ''"
+ tal:condition="python:first >= batch_size"
+ tal:attributes="href python:'?first=%s%s'%(first-batch_size, showall)">
+ <tal:text i18n:translate="">
+ View <tal:num tal:replace="batch_size" i18n:name="number" />
+ later transactions
+ </tal:text>
+ >>>
+ </a>
+</p>
+
+<p metal:define-macro="submit_button">
+ <input type="submit" value="Undo"
+ i18n:attributes="value undo-button" />
+</p>
+
+</body>
+</html>
Added: zmi.core/trunk/src/zmi/core/undo/undo_more.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/undo/undo_more.pt (rev 0)
+++ zmi.core/trunk/src/zmi/core/undo/undo_more.pt 2009-08-08 06:25:26 UTC (rev 102567)
@@ -0,0 +1,38 @@
+<html metal:use-macro="context/@@standard_macros/page"
+ i18n:domain="zope">
+<body>
+<div metal:fill-slot="body">
+
+<h2 i18n:translate="">Undo more</h2>
+
+<p i18n:translate="">This form lets you undo your last
+transactions. You are only viewing transactions initiated by you.</p>
+
+<p i18n:translate="">Select one or more transactions from the list
+below and click the button below. Please be aware that you may only
+undo a transaction if the object has not been modified in a later
+transaction by you or any other user.</p>
+
+<tal:var define="global macros nocall:context/@@undo_macros" />
+<div metal:use-macro="macros/global_vars" />
+
+<div metal:use-macro="macros/location_link" />
+
+<form action="@@undoPrincipalTransactions.html" method="post">
+<div metal:use-macro="macros/previous_batch" />
+
+<div metal:use-macro="macros/undo_log">
+ <div metal:fill-slot="define_info">
+ <tal:var define="global undo_info python:view.getPrincipalTransactions(
+ first=first, last=-batch_size, showall=showall)" />
+ </div>
+</div>
+
+<div metal:use-macro="macros/submit_button" />
+<div metal:use-macro="macros/next_batch" />
+
+</form>
+
+</div>
+</body>
+</html>
More information about the Checkins
mailing list