[doc] Book entry for the undo functionnality.
authorAnthony Truchet <anthony.truchet@logilab.fr>
Tue, 21 Feb 2012 18:23:23 +0100
changeset 8698 b2443e266661
parent 8697 574bb05e40a4
child 8699 864ffd247d70
[doc] Book entry for the undo functionnality.
doc/book/en/additionnal_services/index.rst
doc/book/en/additionnal_services/undo.rst
doc/book/en/images/undo_history-view_w600.png
doc/book/en/images/undo_mesage_w600.png
doc/book/en/images/undo_startup-link_w600.png
doc/book/en/index.rst
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/additionnal_services/index.rst	Tue Feb 21 18:23:23 2012 +0100
@@ -0,0 +1,14 @@
+Additional services
+===================
+
+In this chapter, we introduce services crossing the *web -
+repository - administration* organisation of the first parts of the
+CubicWeb book. Those services can be either proper services (like the
+undo functionality) or mere *topical cross-sections* across CubicWeb.
+
+.. toctree::
+   :maxdepth: 2
+
+   undo
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/additionnal_services/undo.rst	Tue Feb 21 18:23:23 2012 +0100
@@ -0,0 +1,337 @@
+Undoing changes in CubicWeb
+---------------------------
+
+Many desktop applications offer the possibility for the user to
+undo its last changes : this *undo feature* has now been
+integrated into the CubicWeb framework. This document will
+introduce you to the *undo feature* both from the end-user and the
+application developer point of view.
+
+But because a semantic web application and a common desktop
+application are not the same thing at all, especially as far as
+undoing is concerned, we will first introduce *what* is the *undo
+feature* for now.
+
+What's *undoing* in a CubicWeb application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+What is an *undo feature* is quite intuitive in the context of a
+desktop application. But it is a bit subtler in the context of a
+Semantic Web application. This section introduces some of the main
+differences between a classical desktop and a Semantic Web
+applications to keep in mind in order to state precisely *what we
+want*.
+
+The notion transactions
+```````````````````````
+
+A CubicWeb application acts upon an *Entity-Relationship* model,
+described by a schema. This allows to ensure some data integrity
+properties. It also implies that changes are made by all-or-none
+groups called *transactions*, such that the data integrity is
+preserved whether the transaction is completely applied *or* none
+of it is applied.
+
+A transaction can thus include more actions than just those
+directly required by the main purpose of the user.  For example,
+when a user *just* writes a new blog entry, the underlying
+*transaction* holds several *actions* as illustrated below :
+
+* By admin on 2012/02/17 15:18 - Created Blog entry : Torototo
+
+  #. Created Blog entry : Torototo
+  #. Added relation : Torototo owned by admin
+  #. Added relation : Torototo blog entry of Undo Blog
+  #. Added relation : Torototo in state draft (draft)
+  #. Added relation : Torototo created by admin
+
+Because of the very nature (all-or-none) of the transactions, the
+"undoable stuff" are the transactions and not the actions !
+
+Public and private actions within a transaction
+```````````````````````````````````````````````
+
+Actually, within the *transaction* "Created Blog entry :
+Torototo", two of those *actions* are said to be *public* and
+the others are said to be *private*. *Public* here means that the
+public actions (1 and 3) were directly requested by the end user ;
+whereas *private* means that the other actions (2, 4, 5) were
+triggered "under the hood" to fulfill various requirements for the
+user operation (ensuring integrity, security, ... ).
+
+And because quite a lot of actions can be triggered by a "simple"
+end-user request, most of which the end-user is not (and does not
+need or wish to be) aware, only the so-called public actions will
+appear [1]_ in the description of the an undoable transaction.
+
+* By admin on 2012/02/17 15:18 - Created Blog entry : Torototo
+
+  #. Created Blog entry : Torototo
+  #. Added relation : Torototo blog entry of Undo Blog
+
+But note that both public and private actions will be undone
+together when the transaction is undone.
+
+(In)dependent transactions : the simple case
+````````````````````````````````````````````
+
+A CubicWeb application can be used *simultaneously* by different users
+(whereas a single user works on an given office document at a
+given time), so that there is not always a single history
+time-line in the CubicWeb case. Moreover CubicWeb provides
+security through the mechanism of *permissions* granted to each
+user. This can lead to some transactions *not* being undoable in
+some contexts.
+
+In the simple case two (unprivileged) users Alice and Bob make
+relatively independent changes : then both Alice and Bob can undo
+their changes. But in some case there is a clean dependency
+between Alice's and Bob's actions or between actions of one of
+them. For example let's suppose that :
+
+- Alice has created a blog,
+- then has published a first post inside,
+- then Bob has published a second post in the same blog,
+- and finally Alice has updated its post contents.
+
+Then it is clear that Alice can undo her contents changes and Bob
+can undo his post creation independently. But Alice can not undo
+her post creation while she has not first undone her changes.
+It is also clear that Bob should *not* have the
+permissions to undo any of Alice's transactions.
+
+
+More complex dependencies between transactions
+``````````````````````````````````````````````
+
+But more surprising things can quickly happen. Going back to the
+previous example, Alice *can* undo the creation of the blog after
+Bob has published its post in it ! But this is possible only
+because the schema does not *require* for a post to be in a
+blog. Would the *blog entry of* relation have been mandatory, then
+Alice could not have undone the blog creation because it would
+have broken integrity constraint for Bob's post.
+
+When a user attempts to undo a transaction the system will check
+whether a later transaction has explicit dependency on the
+would-be-undone transaction. In this case the system will not even
+attempt the undo operation and inform the user.
+
+If no such dependency is detected the system will attempt the undo
+operation but it can fail, typically because of integrity
+constraint violations. In such a case the undo operation is
+completely [3]_ rollbacked.
+
+
+The *undo feature* for CubicWeb end-users
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The exposition of the undo feature to the end-user through a Web
+interface is still quite basic and will be improved toward a
+greater usability. But it is already fully functional.  For now
+there are two ways to access the *undo feature* as long as the it
+has been activated in the instance configuration file with the
+option *undo-support=yes*.
+
+Immediately after having done the change to be canceled through
+the **undo** link in the message. This allows to undo an
+hastily action immediately. For example, just after having
+validated the creation of the blog entry *A second blog entry* we
+get the following message, allowing to undo the creation.
+
+.. image:: /images/undo_mesage_w600.png
+   :width: 600px
+   :alt: Screenshot of the undo link in the message
+   :align: center
+
+At any time we can access the **undo-history view** accessible from the
+start-up page.
+
+.. image:: /images/undo_startup-link_w600.png
+   :width: 600px
+   :alt: Screenshot of the startup menu with access to the history view
+   :align: center
+
+This view will provide inspection of the transaction and their (public)
+actions. Each transaction provides its own **undo** link. Only the
+transactions the user has permissions to see and undo will be shown.
+
+.. image:: /images/undo_history-view_w600.png
+   :width: 600px
+   :alt: Screenshot of the undo history main view
+   :align: center
+
+If the user attempts to undo a transaction which can't be undone or
+whose undoing fails, then a message will explain the situation and
+no partial undoing will be left behind.
+
+This is all for the end-user side of the undo mechanism : this is
+quite simple indeed ! Now, in the following section, we are going
+to introduce the developer side of the undo mechanism.
+
+The *undo feature* for CubicWeb application developers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A word of warning : this section is intended for developers,
+already having some knowledge of what's under CubicWeb's hood. If
+it is not *yet* the case, please refer to CubicWeb documentation
+http://docs.cubicweb.org/ .
+
+Overview
+````````
+
+The core of the undo mechanisms is at work in the *native source*,
+beyond the RQL. This does mean that *transactions* and *actions*
+are *no entities*. Instead they are represented at the SQL level
+and exposed through the *DB-API* supported by the repository
+*Connection* objects.
+
+Once the *undo feature* has been activated in the instance
+configuration file with the option *undo-support=yes*, each
+mutating operation (cf. [2]_) will be recorded in some special SQL
+table along with its associated transaction. Transaction are
+identified by a *txuuid* through which the functions of the
+*DB-API* handle them.
+
+On the web side the last commited transaction *txuuid* is
+remembered in the request's data to allow for imediate undoing
+whereas the *undo-history view* relies upon the *DB-API* to list
+the accessible transactions. The actual undoing is performed by
+the *UndoController* accessible at URL of the form
+`www.my.host/my/instance/undo?txuuid=...`
+
+The repository side
+```````````````````
+
+Please refer to the file `cubicweb/server/sources/native.py` and
+`cubicweb/transaction.py` for the details.
+
+The undoing information is mainly stored in three SQL tables:
+
+`transactions`
+    Stores the txuuid, the user eid and the date-and-time of
+    the transaction. This table is referenced by the two others.
+
+`tx_entity_actions`
+    Stores the undo information for actions on entities.
+
+`tx_relation_actions`
+    Stores the undo information for the actions on relations.
+
+When the undo support is activated, entries are added to those
+tables for each mutating operation on the data repository, and are
+deleted on each transaction undoing.
+
+Those table are accessible through the following methods of the
+repository `Connection` object :
+
+`undoable_transactions`
+    Returns a list of `Transaction` objects accessible to the user
+    and according to the specified filter(s) if any.
+
+`tx_info`
+    Returns a `Transaction` object from a `txuuid`
+
+`undo_transaction`
+    Returns the list of `Action` object for the given `txuuid`.
+
+    NB:  By default it only return *public* actions.
+
+The web side
+````````````
+
+The exposure of the *undo feature* to the end-user through the Web
+interface relies on the *DB-API* introduced above. This implies
+that the *transactions* and *actions* are not *entities* linked by
+*relations* on which the usual views can be applied directly.
+
+That's why the file `cubicweb/web/views/undohistory.py` defines
+some dedicated views to access the undo information :
+
+`UndoHistoryView`
+    This is a *StartupView*, the one accessible from the home
+    page of the instance which list all transactions.
+
+`UndoableTransactionView`
+    This view handles the display of a single `Transaction` object.
+
+`UndoableActionBaseView`
+    This (abstract) base class provides private methods to build
+    the display of actions whatever their nature.
+
+`Undoable[Add|Remove|Create|Delete|Update]ActionView`
+    Those views all inherit from `UndoableActionBaseView` and
+    each handles a specific kind of action.
+
+`UndoableActionPredicate`
+    This predicate is used as a *selector* to pick the appropriate
+    view for actions.
+
+Apart from this main *undo-history view* a `txuuid` is stored in
+the request's data `last_undoable_transaction` in order to allow
+immediate undoing of a hastily validated operation. This is
+handled in `cubicweb/web/application.py` in the `main_publish` and
+`add_undo_link_to_msg` methods for the storing and displaying
+respectively.
+
+Once the undo information is accessible, typically through a
+`txuuid` in an *undo* URL, the actual undo operation can be
+performed by the `UndoController` defined in
+`cubicweb/web/views/basecontrollers.py`. This controller basically
+extracts the `txuuid` and performs a call to `undo_transaction` and
+in case of an undo-specific error, lets the top level publisher
+handle it as a validation error.
+
+
+Conclusion
+~~~~~~~~~~
+
+The undo mechanism relies upon a low level recording of the
+mutating operation on the repository. Those records are accessible
+through some method added to the *DB-API* and exposed to the
+end-user either through a whole history view of through an
+immediate undoing link in the message box.
+
+The undo feature is functional but the interface and configuration
+options are still quite reduced. One major improvement would be to
+be able to filter with a finer grain which transactions or actions
+one wants to see in the *undo-history view*. Another critical
+improvement would be to enable the undo feature on a part only of
+the entity-relationship schema to avoid storing too much useless
+data and reduce the underlying overhead.
+
+But both functionality are related to the strong design choice not
+to represent transactions and actions as entities and
+relations. This has huge benefits in terms of safety and conceptual
+simplicity but prevents from using lots of convenient CubicWeb
+features such as *facets* to access undo information.
+
+Before developing further the undo feature or eventually revising
+this design choice, it appears that some return of experience is
+strongly needed. So don't hesitate to try the undo feature in your
+application and send us some feedback.
+
+
+Notes
+~~~~~
+
+.. [1] The end-user Web interface could be improved to enable
+       user to choose whether he wishes to see private actions.
+
+.. [2] There is only five kind of elementary actions (beyond
+       merely accessing data for reading):
+
+       * **C** : creating an entity
+       * **D** : deleting an entity
+       * **U** : updating an entity attributes
+       * **A** : adding a relation
+       * **R** : removing a relation
+
+.. [3] Meaning none of the actions in the transaction is
+       undone. Depending upon the application, it might make sense
+       to enable *partial* undo. That is to say undo in which some
+       actions could not be undo without preventing to undo the
+       others actions in the transaction (as long as it does not
+       break schema integrity). This is not forbidden by the
+       back-end but is deliberately not supported by the front-end
+       (for now at least).
Binary file doc/book/en/images/undo_history-view_w600.png has changed
Binary file doc/book/en/images/undo_mesage_w600.png has changed
Binary file doc/book/en/images/undo_startup-link_w600.png has changed
--- a/doc/book/en/index.rst	Thu Feb 14 16:45:07 2013 +0100
+++ b/doc/book/en/index.rst	Tue Feb 21 18:23:23 2012 +0100
@@ -65,6 +65,7 @@
    :maxdepth: 2
 
    admin/index
+   additionnal_services/index
    annexes/index
 
 See also: