Simplify undo model
Simplify undo model
Author
Status
Abstract
This document proposes a simpler Undo Transaction model and UI for Zope3.
Status quo
Zope 2's Undo tab shows transactions that a user may undo in that particular location. A user may undo the changes done by users from the same user folder or from a user folder in a subfolder of the user folder the undoing user is in. That policy is complicated and confusing.
The undo feature Zope 3 currently has is really just a stub implementation. The UI can only show transactions commited by all users (the view showing your own transaction falsely always reports no transactions). It does not support undo in a special location.
Goals
- Users should be able to view and undo just their own changes ("Undo my changes"). Undoing the last change should be as easy as in GUI applications.
- Managers should be able to view and undo changes made by all users.
- One should be able to list transactions only made by in a particular location, apart from all transactions.
- Undo security should be driven by permissions.
Proposal
The IUndoManager interface will be extended to support:
a) list and undo transactions of a particular user
b) list and undo transactions of all users
in combination (intersection) with either
c) list and undo transactions in a particular location
d) list and undo transactions in a global context
Cases a) and b) are characteristics of the new undo policy. Case a)
will be protected with the zope.UndoOwnTransactions permission,
case b) will be protected with the zope.UndoAllTransactions
permission. Cases c) and d) are there to support UI aspects.
The UI will be extended to reflect c) and d). Also, for user convenience, a "Undo my last change" button will be provided, which works just like in GUI apps. The button will change into a "Redo" button when the last transaction was an undo.
For location-based undo and the "Redo" button, we need a way to
uniquely identify the location of a transaction and whether a
transaction is an undo action. Currently, ZopePublication simply
notes the local part of a request in a transaction's
description. Thus, the path noted in the transaction description
contains location-irrelevant segments such as the skin
(++skin++StaticTree) or the view name (@@contents.html). That
information might be useful to the user but not to the location
machinery. Therefore, it is proposed to store the following
information using the transaction's setExtendedInfo method:
- 'location': Location path (using
IPhysicallyLocatable.getPath) (relevant for the undo machinery) - 'request_type': ID of the request type interface (IBrowserRequest?, ...) (relevant for the user)
- In case of http-based requests (relevant for the user):
- 'url': full URL
- 'method': Method (get, post)
The Undo UI can present this information in a human-readable form and make use of the location information.
Interfaces:
class UndoError(Exception):
pass
class IUndo(Interface):
"""Undo functionality"""
def getTransactions(context=None, first=0, last=-20):
"""Return a sequence of mapping objects describing
transactions, ordered by date, descending:
Keys of mapping objects:
id -> internal id for zodb
principal -> principal that invoked the transaction
datetime -> datetime object of time
description -> description/note (string)
Extended information (not necessarily available):
request_type -> type of request that caused transaction
location -> location of the object that was modified
method -> in case of an HTTP request, the method
url -> in case on an HTTP request, the URL
If 'context' is None, all transactions will be
listed, otherwise only transactions for that location.
It skips the 'first' most recent transactions; i.e. if first
is N, then the first transaction returned will be the Nth
transaction.
If last is less than zero, then its absolute value is the
maximum number of transactions to return. Otherwise if last
is N, then only the N most recent transactions following start
are considered.
"""
def undoTransactions(ids):
"""Undo the transactions specified in the sequence 'ids'.
"""
class IPrincipalUndo(Interface):
"""Undo functionality for one specific principal"""
def getPrincipalTransactions(principal, context=None, first=0, last=-20):
"""Returns transactions invoked by the given principal.
See IUndo.getTransactions() for more information
"""
def undoPrincipalTransactions(principal, ids):
"""Undo the transactions invoked by 'principal' with the given
'ids'. Raise UndoError if a transaction is listed among 'ids'
that does not belong to 'principal'.
"""
class IUndoManager(IUndo, IPrincipalUndo):
"""Utility to provide both global and principal-specific undo
functionality
"""
Tasks (in order)
- Define and grant
zope.UndoOwnTransactionsandzope.UndoAllTransactionspermissions. - Make
ZopePublicationstore extended transactional info. - Make FileStorage?'s
UndoSearchread and return the extended transactional info. - Change
ZODBUndoManagerto implementIUndoManagerand thus support transaction lookup methods a) through d) using the extended transactional info. - Implement a UI to reflect the goals, especially the Undo/Redo button.
Progress
Completed
