merge stable
authorAlexandre Fayolle <alexandre.fayolle@logilab.fr>
Mon, 26 Apr 2010 12:52:48 +0200
branchstable
changeset 5404 092bb9355769
parent 5401 547911327475 (diff)
parent 5403 354cf5ef31dc (current diff)
child 5405 c03a9792e53a
merge
--- a/cwconfig.py	Fri Apr 23 13:36:43 2010 +0200
+++ b/cwconfig.py	Mon Apr 26 12:52:48 2010 +0200
@@ -226,7 +226,7 @@
       }),
     ('short-line-size',
      {'type' : 'int',
-      'default': 40,
+      'default': 80,
       'help': _('maximum number of characters in short description'),
       'group': 'navigation',
       }),
--- a/devtools/testlib.py	Fri Apr 23 13:36:43 2010 +0200
+++ b/devtools/testlib.py	Mon Apr 26 12:52:48 2010 +0200
@@ -255,10 +255,10 @@
             self.__class__._repo_init_failed = ex
             raise
         resume_tracing()
+        self._cnxs = []
         self.setup_database()
         self.commit()
         MAILBOX[:] = [] # reset mailbox
-        self._cnxs = []
 
     def tearDown(self):
         for cnx in self._cnxs:
--- a/doc/book/en/admin/additional-tips.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/additional-tips.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -1,40 +1,37 @@
 
 .. _Additional Tips:
 
-Additional Tips
----------------
-
-Here are some additional tips as far as administration of a CubicWeb is concerned.
+Backups (mostly with postgresql)
+--------------------------------
 
-Backup, backup, backup
-``````````````````````
+It is always a good idea to backup. If your system does not do that,
+you should set it up. Note that whenever you do an upgrade,
+`cubicweb-ctl` offers you to backup your database.  There are a number
+of ways for doing backups.
 
-It is always a good idea to backup. If your system does not do that, you should
-set it up. Note that whenever you do an upgrade, `cubicweb-ctl` offers you to
-backup your database.  There are a number of ways for doing backups. Before you
+Using postgresql (and only that)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before you
 go ahead, make sure the following permissions are correct ::
 
    # chgrp postgres /var/lib/cubicweb/backup
-
    # chmod g+ws /var/lib/cubicweb/backup
-
    # chgrp postgres /etc/cubicweb.d/*<instance>*/sources
-
    # chmod g+r /etc/cubicweb.d/*<instance>*/sources
 
-**Classic way on PostgreSQL server**
-
 Simply use the pg_dump in a cron installed for `postgres` user on the database server::
 
     # m h  dom mon dow   command
     0 2 * * * pg_dump -Fc --username=cubicweb --no-owner <instance> > /var/backups/<instance>-$(date '+%Y-%m-%d_%H:%M:%S').dump
 
-**CubicWeb way**
+Using :command:`cubicweb-ctl db-dump`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The CubicWeb way is to use the `db-dump` command. For that, you have to put
-your passwords in a user-only-readable file at the home directory of root user.
-The file is `.pgpass` (`chmod 0600`), in this case for a socket run connection
-to PostgreSQL ::
+The CubicWeb way is to use the :command:`db-dump` command. For that,
+you have to put your passwords in a user-only-readable file at the
+home directory of root user.  The file is `.pgpass` (`chmod 0600`), in
+this case for a socket run connection to PostgreSQL ::
 
     /var/run/postgresql:5432:<instance>:<database user>:<database password>
 
@@ -45,7 +42,9 @@
     # m h  dom mon dow   command
     0 2 * * * cubicweb-ctl db-dump <instance>
 
-**The automated sysadmin way**
+
+Backup ninja
+~~~~~~~~~~~~
 
 You can use a combination `backup-ninja`_ (which has a postgres script in the
 example directory), `backuppc`)_ (for versionning).
@@ -56,3 +55,10 @@
 .. _`here` : http://www.postgresql.org/docs/current/static/libpq-pgpass.html
 .. _`backup-ninja` : https://labs.riseup.net/code/projects/show/backupninja/
 .. _`backuppc` : http://backuppc.sourceforge.net/
+
+.. warning::
+
+  Remember that these indications will fail you whenever you use
+  another database backend than postgres. Also it does properly handle
+  externally managed data such as files (using the Bytes File System
+  Storage).
--- a/doc/book/en/admin/gae.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/gae.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -210,7 +210,7 @@
 This cookie values needs to be provided to ``laxctl`` commands
 in order to handle datastore administration requests.
 
-.. image:: ../images/lax-book.02-cookie-values.en.png
+.. image:: ../images/lax-book_02-cookie-values_en.png
    :alt: displaying the detailed view of the cookie values returned
 
 
--- a/doc/book/en/admin/multisources.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/multisources.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -3,4 +3,4 @@
 
 Data sources include SQL, LDAP, RQL, mercurial and subversion.
 
-XXX feed me
+.. XXX feed me
--- a/doc/book/en/admin/site-config.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/site-config.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -3,7 +3,7 @@
 User interface for web site configuration
 =========================================
 
-.. image:: ../images/lax-book.03-site-config-panel.en.png
+.. image:: ../images/lax-book_03-site-config-panel_en.png
 
 This panel allows you to configure the appearance of your instance site.
 Six menus are available and we will go through each of them to explain how
--- a/doc/book/en/annexes/cookbook.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Cook book
-=========
-
-We gathered together some of our tricks and scripts that could make
-life easier.
-
-
-* How to import LDAP users in *CubicWeb*?
-
-  [XXX distribute this script with cubicweb instead]
-
-  Here is a very useful script which enables you to import LDAP users
-  into your *CubicWeb* instance by running the following:
-
-.. sourcecode:: python
-
-    import os
-    import pwd
-    import sys
-
-    from logilab.common.db import get_connection
-
-    def getlogin():
-        """avoid usinng os.getlogin() because of strange tty / stdin problems
-        (man 3 getlogin)
-        Another solution would be to use $LOGNAME, $USER or $USERNAME
-        """
-        return pwd.getpwuid(os.getuid())[0]
-
-
-    try:
-        database = sys.argv[1]
-    except IndexError:
-        print 'USAGE: python ldap2system.py <database>'
-        sys.exit(1)
-
-    if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'):
-        cnx = get_connection(user=getlogin(), database=database)
-        cursor = cnx.cursor()
-
-        insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, firstname, surname, last_login_time, upassword) '
-                  "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, %(surname)s, %(mtime)s, './fqEz5LeZnT6');")
-        update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;"
-        cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'")
-        for eid, type, source, extid, mtime in cursor.fetchall():
-            if type != 'CWUser':
-                print "don't know what to do with entity type", type
-                continue
-            if source != 'ldapuser':
-                print "don't know what to do with source type", source
-                continue
-            ldapinfos = dict(x.strip().split('=') for x in extid.split(','))
-            login = ldapinfos['uid']
-            firstname = ldapinfos['uid'][0].upper()
-            surname = ldapinfos['uid'][1:].capitalize()
-            if login != 'jcuissinat':
-                args = dict(eid=eid, type=type, source=source, login=login,
-                            firstname=firstname, surname=surname, mtime=mtime)
-                print args
-                cursor.execute(insert, args)
-                cursor.execute(update, args)
-
-        cnx.commit()
-        cnx.close()
-
-
-* How to load data from a script?
-
-  The following script aims at loading data within a script assuming pyro-nsd is
-  running and your instance is configured with ``pyro-server=yes``, otherwise
-  you would not be able to use dbapi.
-
-.. sourcecode:: python
-
-    from cubicweb import dbapi
-
-    cnx = dbapi.connection(database='instance-id', user='admin', password='admin')
-    cur = cnx.cursor()
-    for name in ('Personal', 'Professional', 'Computers'):
-        cur.execute('INSERT Blog B: B name %s', name)
-    cnx.commit()
-
-
--- a/doc/book/en/annexes/faq.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/faq.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -249,7 +249,7 @@
    By default all instance will look for a ``logo.png`` to be
    rendered in the logo section.
 
-   .. image:: ../images/lax-book.06-main-template-logo.en.png
+   .. image:: ../images/lax-book_06-main-template-logo_en.png
 
 2. In your cube directory, you can specify which file to use for the logo.
    This is configurable in ``mycube/data/external_resources``: ::
@@ -290,6 +290,66 @@
 
 You can find additional information in the section :ref:`LDAP`.
 
+How to import LDAP users in |cubicweb| ?
+----------------------------------------
+
+  Here is a useful script which enables you to import LDAP users
+  into your *CubicWeb* instance by running the following:
+
+.. sourcecode:: python
+
+    import os
+    import pwd
+    import sys
+
+    from logilab.common.db import get_connection
+
+    def getlogin():
+        """avoid usinng os.getlogin() because of strange tty / stdin problems
+        (man 3 getlogin)
+        Another solution would be to use $LOGNAME, $USER or $USERNAME
+        """
+        return pwd.getpwuid(os.getuid())[0]
+
+
+    try:
+        database = sys.argv[1]
+    except IndexError:
+        print 'USAGE: python ldap2system.py <database>'
+        sys.exit(1)
+
+    if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'):
+        cnx = get_connection(user=getlogin(), database=database)
+        cursor = cnx.cursor()
+
+        insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, '
+                  ' firstname, surname, last_login_time, upassword) '
+                  "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, "
+                  "%(surname)s, %(mtime)s, './fqEz5LeZnT6');")
+        update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;"
+        cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'")
+        for eid, type, source, extid, mtime in cursor.fetchall():
+            if type != 'CWUser':
+                print "don't know what to do with entity type", type
+                continue
+            if source != 'ldapuser':
+                print "don't know what to do with source type", source
+                continue
+            ldapinfos = dict(x.strip().split('=') for x in extid.split(','))
+            login = ldapinfos['uid']
+            firstname = ldapinfos['uid'][0].upper()
+            surname = ldapinfos['uid'][1:].capitalize()
+            if login != 'jcuissinat':
+                args = dict(eid=eid, type=type, source=source, login=login,
+                            firstname=firstname, surname=surname, mtime=mtime)
+                print args
+                cursor.execute(insert, args)
+                cursor.execute(update, args)
+
+        cnx.commit()
+        cnx.close()
+
+
 I get NoSelectableObject exceptions, how do I debug selectors ?
 ---------------------------------------------------------------
 
--- a/doc/book/en/annexes/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -13,7 +13,6 @@
    :numbered:
 
    faq
-   cookbook
    cubicweb-ctl
    rql/index
    mercurial
--- a/doc/book/en/annexes/rql/implementation.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/rql/implementation.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -128,7 +128,7 @@
 
 - The current implementation does not support linking two relations of type 'is'
   with an OR. I do not think that the negation is supported on this type of
-  relation (XXX FIXME to be confirmed).
+  relation (XXX to be confirmed).
 
 - Relations defining the variables must be left to those using them.  For
   example::
--- a/doc/book/en/annexes/rql/intro.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/rql/intro.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -1,3 +1,5 @@
+
+.. _rql_intro:
 
 Introduction
 ------------
--- a/doc/book/en/annexes/rql/language.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/rql/language.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -92,8 +92,7 @@
     Any X WHERE X name IN ( 'chauvat', 'fayolle', 'di mascio', 'thenault')
 
 
-XXX nico: "A trick <> 'bar'" wouldn't it be more convenient than
-"NOT A trick 'bar'" ?
+.. XXX nico: "A trick <> 'bar'" wouldn't it be more convenient than "NOT A trick 'bar'" ?
 
 .. _PriorityOperators:
 
--- a/doc/book/en/development/cubes/available-cubes.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-
-Available cubes
----------------
-
-An instance is based on several basic cubes. In the set of available
-basic cubes we can find for example :
-
-Base entity types
-~~~~~~~~~~~~~~~~~
-* addressbook_: PhoneNumber and PostalAddress
-* card_: Card, generic documenting card
-* event_: Event (define events, display them in calendars)
-* file_: File (to allow users to upload and store binary or text files)
-* link_: Link (to collect links to web resources)
-* mailinglist_: MailingList (to reference a mailing-list and the URLs
-  for its archives and its admin interface)
-* person_: Person (easily mixed with addressbook)
-* task_: Task (something to be done between start and stop date)
-* zone_: Zone (to define places within larger places, for example a
-  city in a state in a country)
-
-
-Classification
-~~~~~~~~~~~~~~
-* folder_: Folder (to organize things but grouping them in folders)
-* keyword_: Keyword (to define classification schemes)
-* tag_: Tag (to tag anything)
-
-Other features
-~~~~~~~~~~~~~~
-* basket_: Basket (like a shopping cart)
-* blog_: a blogging system uxing Blog and BlogEntry entity types
-* comment_: system to attach comment threads to entities)
-* email_: archiving management for emails (`Email`, `Emailpart`,
-  `Emailthread`), trigger action in cubicweb through email
-
-
-
-
-
-.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
-.. _basket: http://www.cubicweb.org/project/cubicweb-basket
-.. _card: http://www.cubicweb.org/project/cubicweb-card
-.. _blog: http://www.cubicweb.org/project/cubicweb-blog
-.. _comment: http://www.cubicweb.org/project/cubicweb-comment
-.. _email: http://www.cubicweb.org/project/cubicweb-email
-.. _event: http://www.cubicweb.org/project/cubicweb-event
-.. _file: http://www.cubicweb.org/project/cubicweb-file
-.. _folder: http://www.cubicweb.org/project/cubicweb-folder
-.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
-.. _link: http://www.cubicweb.org/project/cubicweb-link
-.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
-.. _person: http://www.cubicweb.org/project/cubicweb-person
-.. _tag: http://www.cubicweb.org/project/cubicweb-tag
-.. _task: http://www.cubicweb.org/project/cubicweb-task
-.. _zone: http://www.cubicweb.org/project/cubicweb-zone
-
-To declare the use of a component, once installed, add the name of the component
-to the variable `__use__` in the file `__pkginfo__.py` of your own component.
-
-.. note::
-  The listed cubes above are available as debian-packages on `CubicWeb's forge`_.
-
-.. _`CubicWeb's forge`: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
--- a/doc/book/en/development/cubes/cc-newcube.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-Creating a new cube from scratch using :command:`cubicweb-ctl newcube`
-----------------------------------------------------------------------
-
-Let's start by creating the cube environment in which we will develop ::
-
-  cd ~/hg
-  # use cubicweb-ctl to generate a template for the cube
-  cubicweb-ctl newcube mycube  # will ask some questions, most with nice default
-  # makes the cube source code managed by mercurial
-  cd mycube
-  hg init
-  hg add .
-  hg ci
-
-If all went well, you should see the cube you just created in the list
-returned by ``cubicweb-ctl list`` in the section *Available cubes*,
-and if it is not the case please refer to :ref:`ConfigurationEnv`.
-
-To reuse an existing cube, add it to the list named ``__use__`` and defined in
-:file:`__pkginfo__.py`.  This variable is used for the instance packaging
-(dependencies handled by system utility tools such as APT) and the usable cubes
-at the time the base is created (import_erschema('MyCube') will not properly
-work otherwise).
-
-.. note::
-
-    Please note that if you do not wish to use default directory for your cubes
-    library, you should set the :envvar:`CW_CUBES_PATH` environment variable to
-    add extra directories where cubes will be search, and you'll then have to use
-    the option `--directory` to specify where you would like to place the source
-    code of your cube:
-
-    ``cubicweb-ctl newcube --directory=/path/to/cubes/library mycube``
-
-
-.. XXX resurrect once live-server is back
-.. Usage of :command:`cubicweb-ctl liveserver`
-.. -------------------------------------------
-
-.. To quickly test a new cube, you can also use the `liveserver` command for cubicweb-ctl
-.. which allows to create an instance in memory (using an SQLite database by
-.. default) and make it accessible through a web server ::
-
-..   cubicweb-ctl live-server mycube
-
-.. or by using an existing database (SQLite or Postgres)::
-
-..   cubicweb-ctl live-server -s myfile_sources mycube
--- a/doc/book/en/development/cubes/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-Cubes
-=====
-
-This chapter describes how to define your own cubes and reuse already available cubes.
-
-.. toctree::
-   :maxdepth: 1
-
-   layout.rst
-   cc-newcube.rst
-   available-cubes.rst
--- a/doc/book/en/development/cubes/layout.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-
-.. _foundationsCube:
-
-.. _cubelayout:
-
-Standard structure for a cube
------------------------------
-
-A cube is structured as follows:
-
-::
-
-  mycube/
-  |
-  |-- data/
-  |   |-- cubes.mycube.css
-  |   |-- cubes.mycube.js
-  |   `-- external_resources
-  |
-  |-- debian/
-  |   |-- changelog
-  |   |-- compat
-  |   |-- control
-  |   |-- copyright
-  |   |-- cubicweb-mycube.prerm
-  |   `-- rules
-  |
-  |-- entities.py
-  |
-  |-- i18n/
-  |   |-- en.po
-  |   |-- es.po
-  |   `-- fr.po
-  |
-  |-- __init__.py
-  |
-  |-- MANIFEST.in
-  |
-  |-- migration/
-  |   |-- postcreate.py
-  |   `-- precreate.py
-  |
-  |-- __pkginfo__.py
-  |
-  |-- schema.py
-  |
-  |-- setup.py
-  |
-  |-- site_cubicweb.py
-  |
-  |-- hooks.py
-  |
-  |-- test/
-  |   |-- data/
-  |   |   `-- bootstrap_cubes
-  |   |-- pytestconf.py
-  |   |-- realdb_test_mycube.py
-  |   `-- test_mycube.py
-  |
-  `-- views.py
-
-
-We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
-``schema.py`` or ``hooks.py``. For example, we could have:
-
-::
-
-  mycube/
-  |
-  |-- entities.py
-  |-- hooks.py
-  `-- views/
-      |-- forms.py
-      |-- primary.py
-      `-- widgets.py
-
-
-where :
-
-* ``schema`` contains the schema definition (server side only)
-* ``entities`` contains the entities definition (server side and web interface)
-* ``hooks`` contains hooks and/or views notifications (server side only)
-* ``views`` contains the web interface components (web interface only)
-* ``test`` contains tests related to the cube (not installed)
-* ``i18n`` contains message catalogs for supported languages (server side and
-  web interface)
-* ``data`` contains data files for static content (images, css, javascripts)
-  ...(web interface only)
-* ``migration`` contains initialization files for new instances (``postcreate.py``)
-  and a file containing dependencies of the component depending on the version
-  (``depends.map``)
-* ``debian`` contains all the files managing debian packaging (you will find
-  the usual files ``control``, ``rules``, ``changelog``... not installed)
-* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
-  and the current version (server side and web interface) or sub-cubes used by
-  the cube.
-
-
-At least you should have:
-
-* the file ``__pkginfo__.py``
-* the schema definition
-  XXX false, we may want to have cubes which are only adding a service,
-  no persistent data (eg embedding for instance)
-
-
-
-The :file:`__init__.py` and :file:`site_cubicweb.py` files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :file:`__pkginfo__.py` file
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX contains metadata describing your cubes
-    distname / modname
-    version / numversion
-    __use__
-    __recommend__
-
-
-:file:`migration/precreate.py` and :file:`migration/postcreate.py`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX detail steps of instance creation
-
-
-External resources such as image, javascript and css files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX naming convention external_resources file
-
-
-Out-of the box testing
-~~~~~~~~~~~~~~~~~~~~~~
-XXX MANIFEST.in, __pkginfo__.include_dirs, debian
-
-
-
-Packaging and distribution
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX MANIFEST.in, __pkginfo__.include_dirs, debian
-
--- a/doc/book/en/development/datamodel/baseschema.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-.. _pre_defined_entity_types:
-
-Pre-defined entities in the library
------------------------------------
-
-The library defines a set of entity schemas that are required by the system
-or commonly used in *CubicWeb* instances.
-
-
-Entity types used to store the schema
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`CWEType`, entity type
-* _`CWRType`, relation type
-* _`CWRelation`, relation definition
-* _`CWAttribute`, attribute relation definition
-* _`CWConstraint`,  `CWConstraintType`, `RQLExpression`
-
-Entity types used to manage users and permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`CWUser`, system users
-* _`CWGroup`, users groups
-* _`CWPermission`, used to configure the security of the instance
-
-Entity types used to manage workflows
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`Workflow`, workflow entity, linked to some entity types which may use this workflow
-* _`State`, workflow state
-* _`Transition`, workflow transition
-* _`TrInfo`, record of a transition trafic for an entity
-
-Other entity types
-~~~~~~~~~~~~~~~~~~
-* _`CWCache`, cache entities used to improve performances
-* _`CWProperty`, used to configure the instance
-
-* _`EmailAddress`, email address, used by the system to send notifications
-  to the users and also used by others optionnals schemas
-
-* _`Bookmark`, an entity type used to allow a user to customize his links within
-  the instance
-
-* _`ExternalUri`, used for semantic web site to indicate that an entity is the
-  same as another from an external site
--- a/doc/book/en/development/datamodel/define-workflows.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Workflow:
-
-Define a Workflow
-=================
-
-General
--------
-
-A workflow describes how certain entities have to evolve between
-different states. Hence we have a set of states, and a "transition graph",
-i.e. a set of possible transitions from one state to another state.
-
-We will define a simple workflow for a blog, with only the following
-two states: `submitted` and `published`. So first, we create a simple
-*CubicWeb* instance in ten minutes (see :ref:`BlogFiveMinutes`).
-
-Set-up a workflow
------------------
-
-We want to create a workflow to control the quality of the BlogEntry
-submitted on the instance. When a BlogEntry is created by a user
-its state should be `submitted`. To be visible to all, it has to
-be in the state `published`. To move it from `submitted` to `published`,
-we need a transition that we can call `approve_blogentry`.
-
-A BlogEntry state should not be modifiable by every user.
-So we have to define a group of users, `moderators`, and
-this group will have appropriate permissions to publish a BlogEntry.
-
-There are two ways to create a workflow: from the user interface, or
-by defining it in ``migration/postcreate.py``. This script is executed
-each time a new ``cubicweb-ctl db-init`` is done.  We strongly
-recommend to create the workflow in ``migration/postcreate.py`` and we
-will now show you how. Read `Two bits of warning`_ to understand why.
-
-The state of an entity is managed by the `in_state` attribute which
-can be added to your entity schema by inheriting from
-`cubicweb.schema.WorkflowableEntityType`.
-
-
-About our example of BlogEntry, we must have:
-
-.. sourcecode:: python
-
-  from cubicweb.schema import WorkflowableEntityType
-
-  class BlogEntry(WorkflowableEntityType):
-      ...
-
-
-Create states, transitions and group permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``postcreate.py`` script is executed in a special environment, adding
-several *CubicWeb* primitives that can be used.
-
-They are all defined in the ``class ServerMigrationHelper``.
-We will only discuss the methods we use to create a workflow in this example.
-
-A workflow is a collection of entities of type ``State`` and of type
-``Transition`` which are standard *CubicWeb* entity types.
-
-To define a workflow for BlogDemo, please add the following lines
-to ``migration/postcreate.py``:
-
-.. sourcecode:: python
-
-  _ = unicode
-
-  moderators = add_entity('CWGroup', name=u"moderators")
-
-This adds the `moderators` user group.
-
-.. sourcecode:: python
-
-  wf = add_workflow(u'blog publication workflow', 'BlogEntry')
-
-At first, instanciate a new workflow object with a gentle description
-and the concerned entity types (this one can be a tuple for multiple
-value).
-
-.. sourcecode:: python
-
-  submitted = wf.add_state(_('submitted'), initial=True)
-  published = wf.add_state(_('published'))
-
-This will create two entities of type ``State``, one with name
-'submitted', and the other with name 'published'.
-
-``add_state`` expects as first argument the name of the state you want
-to create and an optional argument to say if it is supposed to be the
-initial state of the entity type.
-
-.. sourcecode:: python
-
-  wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
-
-This will create an entity of type ``Transition`` with name
-`approve_blogentry` which will be linked to the ``State`` entities
-created before.
-
-``add_transition`` expects
-
-  * as the first argument: the name of the transition
-  * then the list of states on which the transition can be triggered,
-  * the target state of the transition,
-  * and the permissions
-    (e.g. a list of user groups who can apply the transition; the user
-    has to belong to at least one of the listed group to perform the action).
-
-.. sourcecode:: python
-
-  checkpoint()
-
-.. note::
-  Do not forget to add the `_()` in front of all states and transitions names while creating
-  a workflow so that they will be identified by the i18n catalog scripts.
-
-In addition to the user groups (one of which the user needs to belong
-to), we could have added a RQL condition.  In this case, the user can
-only perform the action if the two conditions are satisfied.
-
-If we use an RQL condition on a transition, we can use the following variables:
-
-* `X`, the entity on which we may pass the transition
-* `U`, the user executing that may pass the transition
-
-
-.. image:: ../../images/03-transitions-view.en.png
-
-You can notice that in the action box of a BlogEntry, the state is now
-listed as well as the possible transitions for the current state
-defined by the workflow.
-
-The transitions will only be displayed for users having the right permissions.
-In our example, the transition `approve_blogentry` will only be displayed
-for the users belonging to the group `moderators` or `managers`.
-
-
-Two bits of warning
-~~~~~~~~~~~~~~~~~~~
-
-We could perfectly use the administration interface to do these
-operations. It is a convenient thing to do at times (when doing
-development, to quick-check things). But it is not recommended beyond
-that because it is a bit complicated to do it right and it will be
-only local to your instance (or, said a bit differently, such a
-workflow only exists in an instance database). Furthermore, you cannot
-write unit tests against deployed instances, and experience shows it
-is mandatory to have tests for any mildly complicated workflow
-setup.
-
-Indeed, if you create the states and transitions through the user
-interface, next time you initialize the database you will have to
-re-create all the workflow entities. The user interface should only be
-a reference for you to view the states and transitions, but is not the
-appropriate interface to define your application workflow.
--- a/doc/book/en/development/datamodel/definition.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,630 +0,0 @@
- .. -*- coding: utf-8 -*-
-
-Yams *schema*
--------------
-
-The **schema** is the core piece of a *CubicWeb* instance as it
-defines and handles the data model. It is based on entity types that
-are either already defined in `Yams`_ and the *CubicWeb* standard
-library; or more specific types defined in cubes. The schema for a
-cube is defined in a `schema` python module or package.
-
-.. _`Yams`: http://www.logilab.org/project/yams
-
-Overview
-~~~~~~~~
-
-The core idea of the yams schema is not far from the classical
-`Entity-relationship`_ model. But while an E/R model (or `logical
-model`) traditionally has to be manually translated to a lower-level
-data description language (such as the SQL `create table`
-sublanguage), also often described as the `physical model`, no such
-step is required with |yams| and |cubicweb|.
-
-.. _`Entity-relationship`: http://en.wikipedia.org/wiki/Entity-relationship_model
-
-This is because in addition to high-level, logical |yams| models, one
-uses the |rql| data manipulation language to query, insert, update and
-delete data. |rql| abstracts as much of the underlying SQL database as
-a |yams| schema abstracts from the physical layout. The vagaries of
-SQL are avoided.
-
-As a bonus point, such abstraction make it quite comfortable to build
-or use different backends to which |rql| queries apply.
-
-So, as in the E/R formalism, the building blocks are ``entities``
-(:ref:`EntityType`), ``relationships`` (:ref:`RelationType`,
-:ref:`RelationDefinition`) and ``attributes`` (handled like relation
-with |yams|).
-
-Let us detail a little the divergences between E/R and |yams|:
-
-* all relationship are binary which means that to represent a
-  non-binary relationship, one has to use an entity,
-* relationships do not support attributes (yet, see:
-  http://www.cubicweb.org/ticket/341318), hence the need to reify it
-  as an entity if need arises,
-* all entities have an `eid` attribute (an integer) that is its
-  primary key (but it is possible to declare uniqueness on other
-  attributes)
-
-Also |yams| supports the notions of:
-
-* entity inheritance,
-* relation type: that is, relationships can be established over a set
-  of couple of entity types (henre the distinction made between
-  `RelationType` and `RelationDefinition` below)
-
-Finally |yams| has a few concepts of its own:
-
-* relationships being oriented and binary, we call the left hand
-  entity type the `subject` and the right hand entity type the
-  `object`
-
-.. note::
-
-   The |yams| schema is available at run time through the .schema
-   attribute of the `vregistry`.  It's an instance of
-   :class:`cubicweb.schema.Schema`, which extends
-   :class:`yams.schema.Schema`.
-
-.. _EntityType:
-
-Entity type
-~~~~~~~~~~~
-
-An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
-a set of attributes and relations, and some permissions which define who can add, read,
-update or delete entities of this type.
-
-The following built-in types are available: ``String``, ``Int``,
-``Float``, ``Decimal``, ``Boolean``, ``Date``, ``Datetime``, ``Time``,
-``Interval``, ``Byte`` and ``Password``. They can only be used as
-attributes of an other entity type.
-
-You can find more base entity types in
-:ref:`pre_defined_entity_types`.
-
-.. XXX yams inheritance
-
-.. _RelationType:
-
-Relation type
-~~~~~~~~~~~~~
-
-A relation type is an instance of
-:class:`yams.schema.RelationSchema`. A relation type is simply a
-semantic definition of a kind of relationship that may occur in an
-application.
-
-It may be referenced by zero, one or more relation definitions.
-
-It is important to choose a good name, at least to avoid conflicts
-with some semantically different relation defined in other cubes
-(since there's only a shared name space for these names).
-
-A relation type holds the following properties (which are hence shared
-between all relation definitions of that type):
-
-* `inlined`: boolean handling the physical optimization for archiving
-  the relation in the subject entity table, instead of creating a specific
-  table for the relation. This applies to relations where cardinality
-  of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
-  definitions.
-
-* `symmetric`: boolean indicating that the relation is symmetrical, which
-  means that `X relation Y` implies `Y relation X`.
-
-.. _RelationDefinition:
-
-Relation definition
-~~~~~~~~~~~~~~~~~~~
-
-A relation definition is an instance of
-:class:`yams.schema.RelationDefinition`. It is a complete triplet
-"<subject entity type> <relation type> <object entity type>".
-
-When creating a new instance of that class, the corresponding
-:class:`RelationType` instance is created on the fly if necessary.
-
-Properties
-``````````
-
-The available properties for relation definitions are enumerated
-here. There are several kind of properties, as some relation
-definitions are actually attribute definitions, and other are not.
-
-Some properties may be completely optional, other may have a default
-value.
-
-Common properties for attributes and relations:
-
-* `description`: an unicode string describing an attribute or a
-  relation. By default this string will be used in the editing form of
-  the entity, which means that it is supposed to help the end-user and
-  should be flagged by the function `_` to be properly
-  internationalized.
-
-* `constraints`: a list of conditions/constraints that the relation has to
-  satisfy (c.f. `Constraints`_)
-
-* `cardinality`: a two character string specifying the cardinality of
-  the relation. The first character defines the cardinality of the
-  relation on the subject, and the second on the object. When a
-  relation can have multiple subjects or objects, the cardinality
-  applies to all, not on a one-to-one basis (so it must be
-  consistent...). Default value is '**'. The possible values are
-  inspired from regular expression syntax:
-
-    * `1`: 1..1
-    * `?`: 0..1
-    * `+`: 1..n
-    * `*`: 0..n
-
-Attributes properties:
-
-* `unique`: boolean indicating if the value of the attribute has to be
-  unique or not within all entities of the same type (false by
-  default)
-
-* `indexed`: boolean indicating if an index needs to be created for
-  this attribute in the database (false by default). This is useful
-  only if you know that you will have to run numerous searches on the
-  value of this attribute.
-
-* `default`: default value of the attribute. In case of date types, the values
-  which could be used correspond to the RQL keywords `TODAY` and `NOW`.
-
-Properties for `String` attributes:
-
-* `fulltextindexed`: boolean indicating if the attribute is part of
-  the full text index (false by default) (*applicable on the type
-  `Byte` as well*)
-
-* `internationalizable`: boolean indicating if the value of the
-  attribute is internationalizable (false by default)
-
-Relation properties:
-
-* `composite`: string indicating that the subject (composite ==
-  'subject') is composed of the objects of the relations. For the
-  opposite case (when the object is composed of the subjects of the
-  relation), we just set 'object' as value. The composition implies
-  that when the relation is deleted (so when the composite is deleted,
-  at least), the composed are also deleted.
-
-* `fulltext_container`: string indicating if the value if the full
-  text indexation of the entity on one end of the relation should be
-  used to find the entity on the other end. The possible values are
-  'subject' or 'object'. For instance the use_email relation has that
-  property set to 'subject', since when performing a full text search
-  people want to find the entity using an email address, and not the
-  entity representing the email address.
-
-Constraints
-```````````
-
-By default, the available constraint types are:
-
-General Constraints
-......................
-
-* `SizeConstraint`: allows to specify a minimum and/or maximum size on
-  string (generic case of `maxsize`)
-
-* `BoundConstraint`: allows to specify a minimum and/or maximum value
-  on numeric types and date
-
-.. sourcecode:: python
-
-   from yams.constraints import BoundConstraint, TODAY
-   BoundConstraint('<=', TODAY())
-
-* `IntervalBoundConstraint`: allows to specify an interval with
-  included values
-
-.. sourcecode:: python
-
-     class Node(EntityType):
-         latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
-
-* `UniqueConstraint`: identical to "unique=True"
-
-* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
-
-.. XXX Attribute, NOW
-
-RQL Based Constraints
-......................
-
-RQL based constraints may take three arguments. The first one is the ``WHERE``
-clause of a RQL query used by the constraint. The second argument ``mainvars``
-is the ``Any`` clause of the query. By default this include `S` reserved for the
-subject of the relation and `O` for the object. Additional variables could be
-specified using ``mainvars``. The argument expects a single string with all
-variable's name separated by spaces. The last one, ``msg``, is the error message
-displayed when the constraint fails. As RQLVocabularyConstraint never fails the
-third argument is not available.
-
-* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
-  by the subject and/or the object of relation. In this query the variables
-  `S` and `O` are reserved for the relation subject and object entities.
-
-* `RQLVocabularyConstraint`: similar to the previous type of constraint except
-  that it does not express a "strong" constraint, which means it is only used to
-  restrict the values listed in the drop-down menu of editing form, but it does
-  not prevent another entity to be selected.
-
-* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
-  attribute is unique in a specific context. The Query must **never** return more
-  than a single result to be satisfied. In this query the variables `S` is
-  reserved for the relation subject entity. The other variables should be
-  specified with the second constructor argument (mainvars). This constraints
-  should be used when UniqueConstraint doesn't fit. Here is a simple example.
-
-.. sourcecode:: python
-
-    # Check that in the same Workflow each state's name is unique.  Using
-    # UniqueConstraint (or unique=True) here would prevent states in different
-    # workflows to have the same name.
-
-    # With: State S, Workflow W, String N ; S state_of W, S name N
-
-    RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
-                        mainvars='Y',
-                        msg=_('workflow already has a state of that name'))
-
-.. XXX note about how to add new constraint
-
-.. _securitymodel:
-
-The security model
-~~~~~~~~~~~~~~~~~~
-
-The security model of `CubicWeb` is based on `Access Control List`.
-The main principles are:
-
-* users and groups of users
-* a user belongs to at least one group of user
-* permissions (read, update, create, delete)
-* permissions are assigned to groups (and not to users)
-
-For *CubicWeb* in particular:
-
-* we associate rights at the entities/relations schema level
-* for each entity, we distinguish four kinds of permissions: `read`,
-  `add`, `update` and `delete`
-* for each relation, we distinguish three kinds of permissions: `read`,
-  `add` and `delete` (it is not possible to `modify` a relation)
-* the default groups are: `administrators`, `users` and `guests`
-* by default, users belong to the `users` group
-* there is a virtual group called `owners` to which we
-  can associate only `delete` and `update` permissions
-
-  * we can not add users to the `Owners` group, they are
-    implicitly added to it according to the context of the objects
-    they own
-  * the permissions of this group are only checked on `update`/`delete`
-    actions if all the other groups the user belongs to do not provide
-    those permissions
-
-Setting permissions is done with the attribute `__permissions__` of entities and
-relation types. The value of this attribute is a dictionary where the keys are the access types
-(action), and the values are the authorized groups or expressions.
-
-For an entity type, the possible actions are `read`, `add`, `update` and
-`delete`.
-
-For a relation type, the possible actions are `read`, `add`, and `delete`.
-
-For each access type, a tuple indicates the name of the authorized groups and/or
-one or multiple RQL expressions to satisfy to grant access. The access is
-provided if the user is in one of the listed groups or if one of the RQL condition
-is satisfied.
-
-The standard user groups
-````````````````````````
-
-* `guests`
-
-* `users`
-
-* `managers`
-
-* `owners`: virtual group corresponding to the entity's owner.
-  This can only be used for the actions `update` and `delete` of an entity
-  type.
-
-It is also possible to use specific groups if they are defined in the
-precreate script of the cube (``migration/precreate.py``). Defining groups in
-postcreate script or later makes them unavailable for security
-purposes (in this case, an `sync_schema_props_perms` command has to
-be issued in a CubicWeb shell).
-
-
-Use of RQL expression for write permissions
-```````````````````````````````````````````
-It is possible to define RQL expression to provide update permission
-(`add`, `delete` and `update`) on relation and entity types.
-
-RQL expression for entity type permission:
-
-* you have to use the class `ERQLExpression`
-
-* the used expression corresponds to the WHERE statement of an RQL query
-
-* in this expression, the variables `X` and `U` are pre-defined references
-  respectively on the current entity (on which the action is verified) and
-  on the user who send the request
-
-* it is possible to use, in this expression, a special relation
-  "has_<ACTION>_permission" where the subject is the user and the
-  object is any variable, meaning that the user needs to have
-  permission to execute the action <ACTION> on the entities related
-  to this variable
-
-For RQL expressions on a relation type, the principles are the same except
-for the following:
-
-* you have to use the class `RRQLExpression` in the case of a non-final relation
-
-* in the expression, the variables `S`, `O` and `U` are pre-defined references
-  to respectively the subject and the object of the current relation (on
-  which the action is being verified) and the user who executed the query
-
-* we can also define rights over attributes of an entity (non-final relation),
-  knowing that:
-
-  - to define RQL expression, we have to use the class `ERQLExpression`
-    in which `X` represents the entity the attribute belongs to
-
-  - the permissions `add` and `delete` are equivalent. Only `add`/`read`
-    are actually taken in consideration.
-
-.. note::
-
-  Potentially, the `use of an RQL expression to add an entity or a
-  relation` can cause problems for the user interface, because if the
-  expression uses the entity or the relation to create, then we are
-  not able to verify the permissions before we actually add the entity
-  (please note that this is not a problem for the RQL server at all,
-  because the permissions checks are done after the creation). In such
-  case, the permission check methods (CubicWebEntitySchema.check_perm
-  and has_perm) can indicate that the user is not allowed to create
-  this entity but can obtain the permission.  To compensate this
-  problem, it is usually necessary, for such case, to use an action
-  that reflects the schema permissions but which enables to check
-  properly the permissions so that it would show up if necessary.
-
-
-Use of RQL expression for reading rights
-````````````````````````````````````````
-
-The principles are the same but with the following restrictions:
-
-* we can not use `RRQLExpression` on relation types for reading
-
-* special relations "has_<ACTION>_permission" can not be used
-
-
-
-
-Defining your schema using yams
--------------------------------
-
-Entity type definition
-~~~~~~~~~~~~~~~~~~~~~~
-
-An entity type is defined by a Python class which inherits from
-:class:`yams.buildobjs.EntityType`.  The class definition contains the
-description of attributes and relations for the defined entity type.
-The class name corresponds to the entity type name. It is expected to
-be defined in the module ``mycube.schema``.
-
-:Note on schema definition:
-
- The code in ``mycube.schema`` is not meant to be executed. The class
- EntityType mentioned above is different from the EntitySchema class
- described in the previous chapter. EntityType is a helper class to
- make Entity definition easier. Yams will process EntityType classes
- and create EntitySchema instances from these class definitions. Similar
- manipulation happen for relations.
-
-When defining a schema using python files, you may use the following shortcuts:
-
-- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
-
-- `vocabulary`: specify static possible values of an attribute
-
-- `maxsize`: integer providing the maximum size of a string (no limit by default)
-
-For example:
-
-.. sourcecode:: python
-
-  class Person(EntityType):
-    """A person with the properties and the relations necessary for my
-    application"""
-
-    last_name = String(required=True, fulltextindexed=True)
-    first_name = String(required=True, fulltextindexed=True)
-    title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
-    date_of_birth = Date()
-    works_for = SubjectRelation('Company', cardinality='?*')
-
-
-The entity described above defines three attributes of type String,
-last_name, first_name and title, an attribute of type Date for the date of
-birth and a relation that connects a `Person` to another entity of type
-`Company` through the semantic `works_for`.
-
-:Naming convention:
-
- Entity class names must start with an uppercase letter. The common
- usage is to use ``CamelCase`` names.
-
- Attribute and relation names must start with a lowercase letter. The
- common usage is to use ``underscore_separated_words``. Attribute and
- relation names starting with a single underscore are permitted, to
- denote a somewhat "protected" or "private" attribute.
-
- In any case, identifiers starting with "CW" or "cw" are reserved for
- internal use by the framework.
-
-
-The name of the Python attribute corresponds to the name of the attribute
-or the relation in *CubicWeb* application.
-
-An attribute is defined in the schema as follows::
-
-    attr_name = attr_type(properties)
-
-where `attr_type` is one of the type listed above and `properties` is
-a list of the attribute needs to satisfy (see `Properties`_
-for more details).
-
-* it is possible to use the attribute `meta` to flag an entity type as a `meta`
-  (e.g. used to describe/categorize other entities)
-
-.. XXX the paragraph below needs clarification and / or moving out in
-.. another place
-
-*Note*: if you end up with an `if` in the definition of your entity, this probably
-means that you need two separate entities that implement the `ITree` interface and
-get the result from `.children()` which ever entity is concerned.
-
-Inheritance
-```````````
-XXX feed me
-
-
-Definition of relations
-~~~~~~~~~~~~~~~~~~~~~~~
-
-XXX add note about defining relation type / definition
-
-A relation is defined by a Python class heriting `RelationType`. The name
-of the class corresponds to the name of the type. The class then contains
-a description of the properties of this type of relation, and could as well
-contain a string for the subject and a string for the object. This allows to create
-new definition of associated relations, (so that the class can have the
-definition properties from the relation) for example ::
-
-  class locked_by(RelationType):
-    """relation on all entities indicating that they are locked"""
-    inlined = True
-    cardinality = '?*'
-    subject = '*'
-    object = 'CWUser'
-
-If provided, the `subject` and `object` attributes denote the subject
-and object of the various relation definitions related to the relation
-type. Allowed values for these attributes are:
-
-* a string corresponding to an entity type
-* a tuple of string corresponding to multiple entity types
-* special string such as follows:
-
-  - "**": all types of entities
-  - "*": all types of non-meta entities
-  - "@": all types of meta entities but not system entities (e.g. used for
-    the basic schema description)
-
-When a relation is not inlined and not symmetrical, and it does not require
-specific permissions, it can be defined using a `SubjectRelation`
-attribute in the EntityType class. The first argument of `SubjectRelation` gives
-the entity type for the object of the relation.
-
-:Naming convention:
-
- Although this way of defining relations uses a Python class, the
- naming convention defined earlier prevails over the PEP8 conventions
- used in the framework: relation type class names use
- ``underscore_separated_words``.
-
-:Historical note:
-
-   It has been historically possible to use `ObjectRelation` which
-   defines a relation in the opposite direction. This feature is soon to be
-   deprecated and therefore should not be used in newly written code.
-
-:Future deprecation note:
-
-  In an even more remote future, it is quite possible that the
-  SubjectRelation shortcut will become deprecated, in favor of the
-  RelationType declaration which offers some advantages in the context
-  of reusable cubes.
-
-Definition of permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-The entity type `CWPermission` from the standard library
-allows to build very complex and dynamic security architectures. The schema of
-this entity type is as follow:
-
-.. sourcecode:: python
-
-    class CWPermission(EntityType):
-        """entity type that may be used to construct some advanced security configuration
-        """
-        name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
-        require_group = SubjectRelation('CWGroup', cardinality='+*',
-                                        description=_('groups to which the permission is granted'))
-        require_state = SubjectRelation('State',
-                                        description=_("entity's state in which the permission is applicable"))
-        # can be used on any entity
-        require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
-                                            description=_("link a permission to the entity. This "
-                                                          "permission should be used in the security "
-                                                          "definition of the entity's type to be useful."))
-
-
-Example of configuration:
-
-.. sourcecode:: python
-
-    class Version(EntityType):
-        """a version is defining the content of a particular project's release"""
-
-        __permissions__ = {'read':   ('managers', 'users', 'guests',),
-                           'update': ('managers', 'logilab', 'owners',),
-                           'delete': ('managers', ),
-                           'add':    ('managers', 'logilab',
-                                       ERQLExpression('X version_of PROJ, U in_group G,'
-                                                 'PROJ require_permission P, P name "add_version",'
-                                                 'P require_group G'),)}
-
-
-    class version_of(RelationType):
-        """link a version to its project. A version is necessarily linked to one and only one project.
-        """
-        __permissions__ = {'read':   ('managers', 'users', 'guests',),
-                           'delete': ('managers', ),
-                           'add':    ('managers', 'logilab',
-                                  RRQLExpression('O require_permission P, P name "add_version",'
-                                                 'U in_group G, P require_group G'),)
-                       }
-        inlined = True
-
-
-This configuration indicates that an entity `CWPermission` named
-"add_version" can be associated to a project and provides rights to create
-new versions on this project to specific groups. It is important to notice that:
-
-* in such case, we have to protect both the entity type "Version" and the relation
-  associating a version to a project ("version_of")
-
-* because of the genericity of the entity type `CWPermission`, we have to execute
-  a unification with the groups and/or the states if necessary in the expression
-  ("U in_group G, P require_group G" in the above example)
-
-
-
-Handling schema changes
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Also, it should be clear that to properly handle data migration, an
-instance's schema is stored in the database, so the python schema file
-used to defined it is only read when the instance is created or
-upgraded.
-
-.. XXX complete me
--- a/doc/book/en/development/datamodel/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-Data model
-==========
-
-This chapter describes how you define a schema and how to make it evolves as the time goes.
-
-.. toctree::
-   :maxdepth: 1
-
-   definition
-   metadata
-   baseschema
-   define-workflows
--- a/doc/book/en/development/datamodel/metadata.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-
-Metadata
---------
-
-.. index::
-   schema: meta-data;
-   schema: eid; creation_date; modification_data; cwuri
-   schema: created_by; owned_by; is; is_instance;
-
-Each entity type in |cubicweb| has at least the following meta-data attributes and relations:
-
-`eid`
-  entity's identifier which is unique in an instance. We usually call this identifier `eid` for historical reason.
-
-`creation_date`
-  Date and time of the creation of the entity.
-
-`modification_date`
-  Date and time of the latest modification of an entity.
-
-`cwuri`
-  Reference URL of the entity, which is not expected to change.
-
-`created_by`
-  Relation to the :ref:`users <CWUser>` who has created the entity
-
-`owned_by`
-  Relation to :ref:`users <CWUser>` whom the entity belongs; usually the creator but not
-  necessary, and it could have multiple owners notably for permission control
-
-`is`
-  Relation to the :ref:`entity type <CWEType>` of which type the entity is.
-
-`is_instance`
-  Relation to the :ref:`entity types <CWEType>` of which type the
-  entity is an instance of.
-
--- a/doc/book/en/development/devcore/cwconfig.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-Configuration
--------------
-
-.. automodule:: cubicweb.cwconfig
-      :members:
--- a/doc/book/en/development/devcore/dbapi.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-.. _dbapi:
-
-Python/RQL API
-~~~~~~~~~~~~~~
-
-The Python API developped to interface with RQL is inspired from the standard db-api,
-with a Connection object having the methods cursor, rollback and commit essentially.
-The most important method is the `execute` method of a cursor.
-
-.. sourcecode:: python
-
-  execute(rqlstring, args=None, build_descr=True)
-
-:rqlstring: the RQL query to execute (unicode)
-:args: if the query contains substitutions, a dictionary containing the values to use
-
-The `Connection` object owns the methods `commit` and `rollback`. You
-*should never need to use them* during the development of the web
-interface based on the *CubicWeb* framework as it determines the end
-of the transaction depending on the query execution success. They are
-however useful in other contexts such as tests or custom controllers.
-
-.. note::
-
-  While executing update queries (SET, INSERT, DELETE), if a query generates
-  an error related to security, a rollback is automatically done on the current
-  transaction.
-
-Executing RQL queries from a view or a hook
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When you're within code of the web interface, the db-api like connexion is
-handled by the request object. You should not have to access it directly, but
-use the `execute` method directly available on the request, eg:
-
-   rset = self._cw.execute(rqlstring, kwargs)
-
-Similarly, on the server side (eg in hooks), there is no db-api connexion (since
-you're directly inside the data-server), so you'll have to use the execute method
-of the session object.
-
-
-Important note about proper usage of .execute
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's say you want to get T which is in configuration C, this translates to:
-
-.. sourcecode:: python
-
-   self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
-
-But it must be written in a syntax that will benefit from the use
-of a cache on the RQL server side:
-
-.. sourcecode:: python
-
-   self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
-
-The syntax tree is built once for the "generic" RQL and can be re-used
-with a number of different eids. There rql IN operator is an exception
-to this rule.
-
-.. sourcecode:: python
-
-   self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
-                    % ','.join(['foo', 'bar']))
-
-Alternativelly, some of the common data related to an entity can be
-obtained from the `entity.related()` method (which is used under the
-hood by the orm when you use attribute access notation on an entity to
-get a relation. The initial request would then be translated to:
-
-.. sourcecode:: python
-
-   entity.related('in_conf', 'object')
-
-Additionnaly this benefits from the fetch_attrs policy (see
-:ref:`FetchAttrs`) eventually defined on the class element, which says
-which attributes must be also loaded when the entity is loaded through
-the orm.
-
-
-.. _resultset:
-
-The `ResultSet` API
-~~~~~~~~~~~~~~~~~~~
-
-ResultSet instances are a very commonly manipulated object. They have
-a rich API as seen below, but we would like to highlight a bunch of
-methods that are quite useful in day-to-day practice:
-
-* `__str__()` (applied by `print`) gives a very useful overview of both
-  the underlying RQL expression and the data inside; unavoidable for
-  debugging purposes
-
-* `printable_rql()` produces back a well formed RQL expression as a
-  string; it is very useful to build views
-
-* `entities()` returns a generator on all entities of the result set
-
-* `get_entity(row, col)` gets the entity at row, col coordinates; one
-  of the most used result set method
-
-.. autoclass:: cubicweb.rset.ResultSet
-   :members:
-
-
-The `Cursor` API
-~~~~~~~~~~~~~~~~
-
-The whole cursor API is developped below.
-
-.. note:
-
-  In practice we use the `.execute` method on the _cw object of
-  appobjects. Usage of other methods is quite rare.
-
-.. autoclass:: cubicweb.dbapi.Cursor
-   :members:
--- a/doc/book/en/development/devcore/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Core APIs
-=========
-
-.. toctree::
-   :maxdepth: 1
-
-   dbapi.rst
-   reqbase.rst
-   cwconfig.rst
-
--- a/doc/book/en/development/devcore/reqbase.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-Request and ResultSet methods
------------------------------
-
-Those are methods you'll find on both request objects and on repository session:
-
-:URL handling:
-  * `build_url(*args, **kwargs)`, returns an absolute URL based on the
-    given arguments. The *controller* supposed to handle the response,
-    can be specified through the first positional parameter (the
-    connection is theoretically done automatically :).
-:Data formatting:
-  * `format_date(date, date_format=None, time=False)` returns a string for a
-    date time according to instance's configuration
-
-  * `format_time(time)` returns a string for a date time according to
-    instance's configuration
-
-:And more...:
-
-  * `tal_render(template, variables)`, renders a precompiled page template with
-    variables in the given dictionary as context
-
-
-Result set methods:
-
-  * `get_entity(row, col)`, returns the entity corresponding to the data position
-    in the *result set*
-
-  * `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but
-    also call the method `complete()` on the entity before returning it
-
-
--- a/doc/book/en/development/devrepo/hooks.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,436 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _hooks:
-
-Hooks and Operations
-====================
-
-Generalities
-------------
-
-Paraphrasing the `emacs`_ documentation, let us say that hooks are an
-important mechanism for customizing an application. A hook is
-basically a list of functions to be called on some well-defined
-occasion (this is called `running the hook`).
-
-.. _`emacs`: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
-
-In CubicWeb, hooks are subclasses of the Hook class in
-`server/hook.py`, implementing their own `call` method, and selected
-over a set of pre-defined `events` (and possibly more conditions,
-hooks being selectable AppObjects like views and components).
-
-There are two families of events: data events and server events. In a
-typical application, most of the Hooks are defined over data
-events.
-
-The purpose of data hooks is to complement the data model as defined
-in the schema.py, which is static by nature, with dynamic or value
-driven behaviours. It is functionally equivalent to a `database
-trigger`_, except that database triggers definition languages are not
-standardized, hence not portable (for instance, PL/SQL works with
-Oracle and PostgreSQL but not SqlServer nor Sqlite).
-
-.. _`database trigger`: http://en.wikipedia.org/wiki/Database_trigger
-
-Data hooks can serve the following purposes:
-
-* enforcing constraints that the static schema cannot express
-  (spanning several entities/relations, exotic value ranges and
-  cardinalities, etc.)
-
-* implement computed attributes
-
-Operations are Hook-like objects that may be created by Hooks and
-scheduled to happen just before (or after) the `commit` event. Hooks
-being fired immediately on data operations, it is sometime necessary
-to delay the actual work down to a time where all other Hooks have
-run, for instance a validation check which needs that all relations be
-already set on an entity. Also while the order of execution of Hooks
-is data dependant (and thus hard to predict), it is possible to force
-an order on Operations.
-
-Operations also may be used to process various side effects associated
-with a transaction such as filesystem udpates, mail notifications,
-etc.
-
-Operations are subclasses of the Operation class in `server/hook.py`,
-implementing `precommit_event` and other standard methods (wholly
-described in :ref:`operations_api`).
-
-Events
-------
-
-Hooks are mostly defined and used to handle `dataflow`_ operations. It
-means as data gets in (entities added, updated, relations set or
-unset), specific events are issued and the Hooks matching these events
-are called.
-
-.. _`dataflow`: http://en.wikipedia.org/wiki/Dataflow
-
-Below comes a list of the dataflow events related to entities operations:
-
-* before_add_entity
-
-* before_update_entity
-
-* before_delete_entity
-
-* after_add_entity
-
-* after_update_entity
-
-* after_delete_entity
-
-These define ENTTIES HOOKS. RELATIONS HOOKS are defined
-over the following events:
-
-* after_add_relation
-
-* after_delete_relation
-
-* before_add_relation
-
-* before_delete_relation
-
-This is an occasion to remind us that relations support the add/delete
-operation, but no update.
-
-Non data events also exist. These are called SYSTEM HOOKS.
-
-* server_startup
-
-* server_shutdown
-
-* server_maintenance
-
-* server_backup
-
-* server_restore
-
-* session_open
-
-* session_close
-
-
-Using dataflow Hooks
---------------------
-
-Dataflow hooks either automate data operations or maintain the
-consistency of the data model. In the later case, we must use a
-specific exception named ValidationError
-
-Validation Errors
-~~~~~~~~~~~~~~~~~
-
-When a condition is not met in a Hook/Operation, it must raise a
-`ValidationError`. Raising anything but a (subclass of)
-ValidationError is a programming error. Raising a ValidationError
-entails aborting the current transaction.
-
-The ValidationError exception is used to convey enough information up
-to the user interface. Hence its constructor is different from the
-default Exception constructor. It accepts, positionally:
-
-* an entity eid,
-
-* a dict whose keys represent attribute (or relation) names and values
-  an end-user facing message (hence properly translated) relating the
-  problem.
-
-An entity hook
-~~~~~~~~~~~~~~
-
-We will use a very simple example to show hooks usage. Let us start
-with the following schema.
-
-.. sourcecode:: python
-
-   class Person(EntityType):
-       age = Int(required=True)
-
-We would like to add a range constraint over a person's age. Let's
-write an hook. It shall be placed into mycube/hooks.py. If this file
-were to grow too much, we can easily have a mycube/hooks/... package
-containing hooks in various modules.
-
-.. sourcecode:: python
-
-   from cubicweb import ValidationError
-   from cubicweb.selectors import implements
-   from cubicweb.server.hook import Hook
-
-   class PersonAgeRange(Hook):
-        __regid__ = 'person_age_range'
-        events = ('before_add_entity', 'before_update_entity')
-        __select__ = Hook.__select__ & implements('Person')
-
-        def __call__(self):
-            if 0 >= self.entity.age <= 120:
-               return
-            msg = self._cw._('age must be between 0 and 120')
-            raise ValidationError(self.entity.eid, {'age': msg})
-
-Hooks being AppObjects like views, they have a __regid__ and a
-__select__ class attribute. The base __select__ is augmented with an
-`implements` selector matching the desired entity type. The `events`
-tuple is used by the Hook.__select__ base selector to dispatch the
-hook on the right events. In an entity hook, it is possible to
-dispatch on any entity event (e.g. 'before_add_entity',
-'before_update_entity') at once if needed.
-
-Like all appobjects, hooks have the `self._cw` attribute which
-represents the current session. In entity hooks, a `self.entity`
-attribute is also present.
-
-
-A relation hook
-~~~~~~~~~~~~~~~
-
-Let us add another entity type with a relation to person (in
-mycube/schema.py).
-
-.. sourcecode:: python
-
-   class Company(EntityType):
-        name = String(required=True)
-        boss = SubjectRelation('Person', cardinality='1*')
-
-We would like to constrain the company's bosses to have a minimum
-(legal) age. Let's write an hook for this, which will be fired when
-the `boss` relation is established.
-
-.. sourcecode:: python
-
-   class CompanyBossLegalAge(Hook):
-        __regid__ = 'company_boss_legal_age'
-        events = ('before_add_relation',)
-        __select__ = Hook.__select__ & match_rtype('boss')
-
-        def __call__(self):
-            boss = self._cw.entity_from_eid(self.eidto)
-            if boss.age < 18:
-                msg = self._cw._('the minimum age for a boss is 18')
-                raise ValidationError(self.eidfrom, {'boss': msg})
-
-We use the `match_rtype` selector to select the proper relation type.
-
-The essential difference with respect to an entity hook is that there
-is no self.entity, but `self.eidfrom` and `self.eidto` hook attributes
-which represent the subject and object eid of the relation.
-
-
-Using Operations
-----------------
-
-Let's augment our example with a new `subsidiary_of` relation on Company.
-
-.. sourcecode:: python
-
-   class Company(EntityType):
-        name = String(required=True)
-        boss = SubjectRelation('Person', cardinality='1*')
-        subsidiary_of = SubjectRelation('Company', cardinality='*?')
-
-Base example
-~~~~~~~~~~~~
-
-We would like to check that there is no cycle by the `subsidiary_of`
-relation. This is best achieved in an Operation since all relations
-are likely to be set at commit time.
-
-.. sourcecode:: python
-
-    def check_cycle(self, session, eid, rtype, role='subject'):
-        parents = set([eid])
-        parent = session.entity_from_eid(eid)
-        while parent.related(rtype, role):
-            parent = parent.related(rtype, role)[0]
-            if parent.eid in parents:
-                msg = session._('detected %s cycle' % rtype)
-                raise ValidationError(eid, {rtype: msg})
-            parents.add(parent.eid)
-
-    class CheckSubsidiaryCycleOp(Operation):
-
-        def precommit_event(self):
-            check_cycle(self.session, self.eidto, 'subsidiary_of')
-
-
-    class CheckSubsidiaryCycleHook(Hook):
-        __regid__ = 'check_no_subsidiary_cycle'
-        events = ('after_add_relation',)
-        __select__ = Hook.__select__ & match_rtype('subsidiary_of')
-
-        def __call__(self):
-            CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
-
-The operation is instantiated in the Hook.__call__ method.
-
-An operation always takes a session object as first argument
-(accessible as `.session` from the operation instance), and optionally
-all keyword arguments needed by the operation. These keyword arguments
-will be accessible as attributes from the operation instance.
-
-Like in Hooks, ValidationError can be raised in Operations. Other
-exceptions are programming errors.
-
-Notice how our hook will instantiate an operation each time the Hook
-is called, i.e. each time the `subsidiary_of` relation is set.
-
-Using set_operation
-~~~~~~~~~~~~~~~~~~~
-
-There is an alternative method to schedule an Operation from a Hook,
-using the `set_operation` function.
-
-.. sourcecode:: python
-
-   from cubicweb.server.hook import set_operation
-
-   class CheckSubsidiaryCycleHook(Hook):
-       __regid__ = 'check_no_subsidiary_cycle'
-       events = ('after_add_relation',)
-       __select__ = Hook.__select__ & match_rtype('subsidiary_of')
-
-       def __call__(self):
-           set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto,
-                         CheckSubsidiaryCycleOp, rtype=self.rtype)
-
-   class CheckSubsidiaryCycleOp(Operation):
-
-       def precommit_event(self):
-           for eid in self._cw.transaction_data['subsidiary_cycle_detection']:
-               check_cycle(self.session, eid, self.rtype)
-
-Here, we call set_operation with a session object, a specially forged
-key, a value that is the actual payload of an individual operation (in
-our case, the object of the subsidiary_of relation) , the class of the
-Operation, and more optional parameters to give to the operation (here
-the rtype which do not vary accross operations).
-
-The body of the operation must then iterate over the values that have
-been mapped in the transaction_data dictionary to the forged key.
-
-This mechanism is especially useful on two occasions (not shown in our
-example):
-
-* massive data import (reduced memory consumption within a large
-  transaction)
-
-* when several hooks need to instantiate the same operation (e.g. an
-  entity and a relation hook).
-
-.. note::
-
-  A more realistic example can be found in the advanced tutorial
-  chapter :ref:`adv_tuto_security_propagation`.
-
-.. _operations_api:
-
-Operation: a small API overview
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: cubicweb.server.hook.Operation
-.. autoclass:: cubicweb.server.hook.LateOperation
-.. autofunction:: cubicweb.server.hook.set_operation
-
-Hooks writing rules
--------------------
-
-Remainder
-~~~~~~~~~
-
-Never, ever use the `entity.foo = 42` notation to update an entity. It
-will not work.
-
-How to choose between a before and an after event ?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Before hooks give you access to the old attribute (or relation)
-values. By definition the database is not yet updated in a before
-hook.
-
-To access old and new values in an before_update_entity hook, one can
-use the `server.hook.entity_oldnewvalue` function which returns a
-tuple of the old and new values. This function takes an entity and an
-attribute name as parameters.
-
-In a 'before_add|update_entity' hook the self.entity contains the new
-values. One is allowed to further modify them before database
-operations, using the dictionary notation.
-
-.. sourcecode:: python
-
-   self.entity['age'] = 42
-
-This is because using self.entity.set_attributes(age=42) will
-immediately update the database (which does not make sense in a
-pre-database hook), and will trigger any existing
-before_add|update_entity hook, thus leading to infinite hook loops or
-such awkward situations.
-
-Beyond these specific cases, updating an entity attribute or relation
-must *always* be done using `set_attributes` and `set_relations`
-methods.
-
-(Of course, ValidationError will always abort the current transaction,
-whetever the event).
-
-Peculiarities of inlined relations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some relations are defined in the schema as `inlined` (see
-:ref:`RelationType` for details). In this case, they are inserted in
-the database at the same time as entity attributes.
-
-Hence in the case of before_add_relation, such relations already exist
-in the database.
-
-Edited attributes
-~~~~~~~~~~~~~~~~~
-
-On udpates, it is possible to ask the `entity.edited_attributes`
-variable whether one attribute has been updated.
-
-.. sourcecode:: python
-
-  if 'age' not in entity.edited_attribute:
-      return
-
-Deleted in transaction
-~~~~~~~~~~~~~~~~~~~~~~
-
-The session object has a deleted_in_transaction method, which can help
-writing deletion Hooks.
-
-.. sourcecode:: python
-
-   if self._cw.deleted_in_transaction(self.eidto):
-      return
-
-Given this predicate, we can avoid scheduling an operation.
-
-Disabling hooks
-~~~~~~~~~~~~~~~
-
-It is sometimes convenient to disable some hooks. For instance to
-avoid infinite Hook loops. One uses the `hooks_control` context
-manager.
-
-This can be controlled more finely through the `category` Hook class
-attribute, which is a string.
-
-.. sourcecode:: python
-
-   with hooks_control(self.session, self.session.HOOKS_ALLOW_ALL, <category>):
-       # ... do stuff
-
-.. autoclass:: cubicweb.server.session.hooks_control
-
-The existing categories are: ``email``, ``syncsession``,
-``syncschema``, ``bookmark``, ``security``, ``worfklow``,
-``metadata``, ``notification``, ``integrity``, ``activeintegrity``.
-
-Nothing precludes one to invent new categories and use the
-hooks_control context manager to filter them (in or out).
--- a/doc/book/en/development/devrepo/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Repository customization
-++++++++++++++++++++++++
-.. toctree::
-   :maxdepth: 1
-
-   sessions
-   hooks
-   notifications
-   tasks
-
-
--- a/doc/book/en/development/devrepo/notifications.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Notifications management
-========================
-
-XXX FILLME
--- a/doc/book/en/development/devrepo/sessions.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Sessions
-========
-
-There are three kinds of sessions.
-
-* `user sessions` are the most common: they are related to users and
-  carry security checks coming with user credentials
-
-* `super sessions` are children of ordinary user sessions and allow to
-  bypass security checks (they are created by calling unsafe_execute
-  on a user session); this is often convenient in hooks which may
-  touch data that is not directly updatable by users
-
-* `internal sessions` have all the powers; they are also used in only a
-  few situations where you don't already have an adequate session at
-  hand, like: user authentication, data synchronisation in
-  multi-source contexts
-
-.. note::
-  Do not confuse the session type with their connection mode, for
-  instance : 'in memory' or 'pyro'.
-
-[WRITE ME]
-
-* authentication and management of sessions
--- a/doc/book/en/development/devrepo/tasks.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tasks
-=========
-
-[WRITE ME]
-
-* repository tasks
-
--- a/doc/book/en/development/devweb/controllers.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-.. _controllers:
-
-Controllers
------------
-
-Overview
-++++++++
-
-Controllers are responsible for taking action upon user requests
-(loosely following the terminology of the MVC meta pattern).
-
-The following controllers are provided out-of-the box in CubicWeb. We
-list them by category.
-
-`Browsing`:
-
-* the View controller (web/views/basecontrollers.py) is associated
-  with most browsing actions within a CubicWeb application: it always
-  instantiates a `main template` and lets the ResultSet/Views dispatch
-  system build up the whole content; it handles ObjectNotFound and
-  NoSelectableObject errors that may bubble up to its entry point, in
-  an end-user-friendly way (but other programming errors will slip
-  through)
-
-* the JSon controller (web/views/basecontrollers.py) provides services
-  for Ajax calls, typically using JSON as a serialization format for
-  input, and sometimes using either JSON or XML for output;
-
-* the Login/Logout controllers (web/views/basecontrollers.py) make
-  effective user login or logout requests
-
-`Edition`:
-
-* the Edit controller (see :ref:`edit_controller`) handles CRUD
-  operations in response to a form being submitted; it works in close
-  association with the Forms, to which it delegates some of the work
-
-* the Form validator controller (web/views/basecontrollers.py)
-  provides form validation from Ajax context, using the Edit
-  controller, to implement the classic form handling loop (user edits,
-  hits 'submit/apply', validation occurs server-side by way of the
-  Form validator controller, and the UI is decorated with failure
-  information, either global or per-field , until it is valid)
-
-`Other`:
-
-* the SendMail controller (web/views/basecontrollers.py) is reponsible
-  for outgoing email notifications
-
-* the MailBugReport controller (web/views/basecontrollers.py) allows
-  to quickly have a `repotbug` feature in one's application
-
-Registration
-++++++++++++
-
-All controllers (should) live in the 'controllers' namespace within
-the global registry.
-
-API
-+++
-
-Most API details should be resolved by source code inspection, as the
-various controllers have differing goals.
-
-`web/controller.py` contains the top-level abstract Controller class and
-its (NotImplemented) entry point `publish(rset=None)` method.
-
-A handful of helpers are also provided there:
-
-* process_rql builds a result set from an rql query typically issued
-  from the browser (and available through _cw.form['rql'])
-
-* validate_cache will force cache validation handling with respect to
-  the HTTP Cache directives (that were typically originally issued
-  from a previous server -> client response); concrete Controller
-  implementations dealing with HTTP (thus, for instance, not the
-  SendMail controller) may very well call this in their publication
-  process.
-
-
-.. _edit_controller:
-
-The `edit controller`
-+++++++++++++++++++++
-
-It can be found in (:mod:`cubicweb.web.views.editcontroller`).
-
-Editing control
-~~~~~~~~~~~~~~~~
-
-Re-requisites: the parameters related to entities to edit are
-specified as follows ::
-
-  <field name>:<entity eid>
-
-where entity eid could be a letter in case of an entity to create. We
-name those parameters as *qualified*.
-
-1. Retrieval of entities to edit by looking for the forms parameters
-   starting by `eid:` and also having a parameter `__type` associated
-   (also *qualified* by eid)
-
-2. For all the attributes and the relations of an entity to edit:
-
-   1. search for a parameter `edits-<relation name>` or `edito-<relation name>`
-      qualified in the case of a relation where the entity is object
-   2. if found, the value returned is considered as the initial value
-      for this relaiton and we then look for the new value(s)  in the parameter
-      <relation name> (qualified)
-   3. if the value returned is different from the initial value, an database update
-      request is done
-
-3. For each entity to edit:
-
-   1. if a qualified parameter `__linkto` is specified, its value has to be
-      a string (or a list of string) such as: ::
-
-        <relation type>:<eids>:<target>
-
-      where <target> is either `subject` or `object` and each eid could be
-      separated from the others by a `_`. Target specifies if the *edited entity*
-      is subject or object of the relation and each relation specified will
-      be inserted.
-
-    2. if a qualified parameter `__clone_eid` is specified for an entity, the
-       relations of the specified entity passed as value of this parameter are
-       copied on the edited entity.
-
-    3. if a qualified parameter `__delete` is specified, its value must be
-       a string or a list of string such as follows: ::
-
-          <ssubjects eids>:<relation type>:<objects eids>
-
-       where each eid subject or object can be seperated from the other
-       by `_`. Each relation specified will be deleted.
-
-    4. if a qualified parameter `__insert` is specified, its value should
-       follow the same pattern as `__delete`, but each relation specified is
-       inserted.
-
-4. If the parameters `__insert` and/or `__delete` are found not qualified,
-   they are interpreted as explained above (independantly from the number
-   of entities edited).
-
-5. If no entity is edited but the form contains the parameters `__linkto`
-   and `eid`, this one is interpreted by using the value specified for `eid`
-   to designate the entity on which to add the relations.
-
-
-.. note::
-
-   * If the parameter `__action_delete` is found, all the entities specified
-     as to be edited will be deleted.
-
-   * If the parameter `__action_cancel` is found, no action is completed.
-
-   * If the parameter `__action_apply` is found, the editing is
-     applied normally but the redirection is done on the form (see
-     :ref:`RedirectionControl`).
-
-   * The parameter `__method` is also supported as for the main template
-
-   * If no entity is found to be edited and if there is no parameter
-     `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or
-     `__insert`, an error is raised.
-
-   * Using the parameter `__message` in the form will allow to use its value
-     as a message to provide the user once the editing is completed.
-
-
-.. _RedirectionControl:
-
-Redirection control
-~~~~~~~~~~~~~~~~~~~
-Once editing is completed, there is still an issue left: where should we go
-now? If nothing is specified, the controller will do his job but it does not
-mean we will be happy with the result. We can control that by using the
-following parameters:
-
-* `__redirectpath`: path of the URL (relative to the root URL of the site,
-  no form parameters
-
-* `__redirectparams`: forms parameters to add to the path
-
-* `__redirectrql`: redirection RQL request
-
-* `__redirectvid`: redirection view identifier
-
-* `__errorurl`: initial form URL, used for redirecting in case a validation
-  error is raised during editing. If this one is not specified, an error page
-  is displayed instead of going back to the form (which is, if necessary,
-  responsible for displaying the errors)
-
-* `__form_id`: initial view form identifier, used if `__action_apply` is
-  found
-
-In general we use either `__redirectpath` and `__redirectparams` or
-`__redirectrql` and `__redirectvid`.
-
--- a/doc/book/en/development/devweb/css.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-CSS Stylesheet
----------------
-Conventions
-~~~~~~~~~~~
-
-XXX external_resources variable
-    naming convention
-    request.add_css
-
-
-Extending / overriding existing styles
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We cannot modify the order in which the application is reading the CSS. In
-the case we want to create new CSS style, the best is to define it a in a new
-CSS located under ``myapp/data/`` and use those new styles while writing
-customized views and templates.
-
-If you want to modify an existing CSS styling property, you will have to use
-``!important`` declaration to override the existing property. The application
-apply a higher priority on the default CSS and you can not change that.
-Customized CSS will not be read first.
-
-
-CubicWeb stylesheets
-~~~~~~~~~~~~~~~~~~~~
-XXX explain diffenrent files and main classes
--- a/doc/book/en/development/devweb/facets.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-The facets system
------------------
-
-Facets allow to restrict searches according to some criteria. CubicWeb has a builtin `facet`_ system to define restrictions
-`filters`_ really as easily as possible. A few base classes for facets
-are provided in ``cubicweb.web.facet.py``. All classes inherits from
-the base class ``AbstractFacet``. 
-
-Here is an overview of the facets rendering pick from the `tracker` cube:
-
-.. image:: ../../images/facet_overview.png
-
-Facets will appear on each page presenting more than one entity.
-
-
-
-VocabularyFacet
-~~~~~~~~~~~~~~~~
-The ``VocabularyFacet`` inherits from the ``AbstractFacet``.
-A class which inherits from VocabularyFacets must redefine these methods:
-
-.. automethod:: cubicweb.web.facet.VocabularyFacet.vocabulary
-.. automethod:: cubicweb.web.facet.VocabularyFacet.possible_values
-
-RelationFacet
-~~~~~~~~~~~~~~
-
-The ``RelationFacet`` inherits from the ``VocabularyFacet``. It allows to filter entities according to certain relation's values. Generally, you just have to define some class attributes like:
-
-- rtype: the name of the relation
-- role: the default value is set to `subject`
-- target_attr: needed if it is not the default attribute of the entity
-
-
-To illustrate this facet, let's take for example an *excerpt* of the schema of an office location search application:
-
-.. sourcecode:: python
-
-  class Office(WorkflowableEntityType):
-      price = Int(description='euros / m2 / HC / HT')
-      surface = Int(description='m2')
-      description = RichString(fulltextindexed=True)
-      has_address = SubjectRelation('PostalAddress',
-                                    cardinality='1?',
-                                    composite='subject')
-      proposed_by = SubjectRelation('Agency')
-      comments = ObjectRelation('Comment',
-                                cardinality='1*',
-                                composite='object')
-      screenshots = SubjectRelation(('File', 'Image'),
-                                    cardinality='*1',
-                                    composite='subject')
-
-
-We define a facet to filter offices according to the attribute
-`postalcode` of their associated `PostalAdress`.
-
-.. sourcecode:: python
-
-  class PostalCodeFacet(RelationFacet):
-      __regid__ = 'postalcode-facet'      # every registered class must have an id
-      __select__ = implements('Office')   # this facet should only be selected when
-                                          # visualizing offices
-      rtype = 'has_address'               # this facet is a filter on the entity linked to
-                                          # the office thrhough the relation
-                                          # has_address
-      target_attr = 'postalcode'          # the filter's key is the attribute "postal_code"
-                                          # of the target PostalAddress entity
-
-
-AttributeFacet
-~~~~~~~~~~~~~~
-
-The ``AttributeFacet`` inherits from the ``RelationFacet``. It allows to filter entities according to certain attribute's values.
-
-The example below resumes the former schema. We define now a filter based on the `surface` attribute of the
-`Office`.
-
-.. sourcecode:: python
-
-  class SurfaceFacet(AttributeFacet):
-      __regid__ = 'surface-facet'       # every registered class must have an id
-      __select__ = implements('Office') # this facet should only be selected when
-                                        # visualizing offices
-      rtype = 'surface'                 # the filter's key is the attribute "surface"
-      comparator = '>='                 # override the default value of operator since
-                                        # we want to filter according to a
-                                        # minimal
-                                        # value, not an exact one
-
-      def rset_vocabulary(self, ___):
-          """override the default vocabulary method since we want to hard-code
-          our threshold values.
-          Not overriding would generate a filter box with all existing surfaces
-          defined in the database.
-          """
-          return [('> 200', '200'), ('> 250', '250'),
-                  ('> 275', '275'), ('> 300', '300')]
-
-RangeFacet
-~~~~~~~~~~
-The ``RangeFacet`` inherits from the ``AttributeFacet``. It allows to filter entities according to certain attributes of numerical type.
-
-The ``RangeFacet`` displays a slider using `jquery`_ to choose a lower bound and an upper bound.
-
-The example below defines a facet to filter a selection of books according to their number of pages.
-
-.. sourcecode:: python
-
-   class BookPagesFacet(RangeFacet):
-       __regid__ = 'priority-facet'
-       __select__ = RangeFacet.__select__ & implements('Book')
-       rtype = 'pages'
-
-The image below display the rendering of the ``RangeFacet``:
-
-.. image:: ../../images/facet_range.png
-
-DateRangeFacet
-~~~~~~~~~~~~~~
-The ``DateRangeFacet`` inherits from the ``RangeFacet``. It allows to filter entities according to certain attributes of date type.
-
-Here is an example of code that defines a facet to filter
-musical works according to their composition date:
-
-.. sourcecode:: python
-
-    class CompositionDateFacet(DateRangeFacet):
-        # 1. make sure this facet is displayed only on Track selection
-        __select__ = DateRangeFacet.__select__ & implements('Track')
-        # 2. give the facet an id required by CubicWeb)
-        __regid__ = 'compdate-facet'
-        # 3. specify the attribute name that actually stores the date in the DB
-        rtype = 'composition_date'
-
-With this facet, on each page displaying tracks, you'll be able to filter them
-according to their composition date with a jquery slider.
-
-The image below display the rendering of the ``DateRangeFacet``:
-
-.. image:: ../../images/facet_date_range.png
-
-
-HasRelationFacet
-~~~~~~~~~~~~~~~~
-
-The ``DateRangeFacet`` inherits from the ``AbstractFacet``. It will
-display a simple checkbox and lets you refine your selection in order
-to get only entities that actually use this relation.
-
-Here is an example of the rendering of the ``HasRelationFacet`` to
-filter entities with image and the corresponding code:
-
-.. image:: ../../images/facet_has_image.png
-
-.. sourcecode:: python
-
-  class HasImageFacet(HasRelationFacet):
-      __regid__ = 'hasimage-facet'
-      __select__ = HasRelationFacet.__select__ & implements('Book')
-      rtype = 'has_image'
-
-
-
-To use ``HasRelationFacet`` on a reverse relation add ``role = 'object'`` in
-it's definitions.
-
-.. _facet: http://en.wikipedia.org/wiki/Faceted_browser
-.. _filters: http://www.cubicweb.org/blogentry/154152
-.. _jquery: http://www.jqueryui.com/
-
--- a/doc/book/en/development/devweb/form.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-HTML form construction
-----------------------
-
-CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
-to provide generic building blocks which will greatly help you in building forms
-properly integrated with CubicWeb (coherent display, error handling, etc...),
-while keeping things as flexible as possible.
-
-A **form** basically only holds a set of **fields**, and has te be bound to a
-**renderer** which is responsible to layout them. Each field is bound to a
-**widget** that will be used to fill in value(s) for that field (at form
-generation time) and 'decode' (fetch and give a proper Python type to) values
-sent back by the browser.
-
-The **field** should be used according to the type of what you want to edit.
-E.g. if you want to edit some date, you'll have to use the
-:class:`~cubicweb.web.formfields.DateField`. Then you can choose among multiple
-widgets to edit it, for instance :class:`~cubicweb.web.formwidgets.TextInput` (a
-bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
-calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
-calendar).  You can of course also write your own widget.
-
-
-.. automodule:: cubicweb.web.formfields
-.. automodule:: cubicweb.web.formwidgets
-.. automodule:: cubicweb.web.views.forms
-.. automodule:: cubicweb.web.views.autoform
-.. automodule:: cubicweb.web.views.formrenderers
-
-
-Now what ? Example of bare fields form
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We want to define a form doing something else than editing an entity. The idea is
-to propose a form to send an email to entities in a resultset which implements
-:class:`IEmailable`.  Let's take a simplified version of what you'll find in
-:mod:`cubicweb.web.views.massmailing`.
-
-Here is the source code:
-
-.. sourcecode:: python
-
-    def sender_value(form):
-	return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
-
-    def recipient_choices(form, field):
-	return [(e.get_email(), e.eid) for e in form.cw_rset.entities()
-		 if e.get_email()]
-
-    def recipient_value(form):
-	return [e.eid for e in form.cw_rset.entities() if e.get_email()]
-
-    class MassMailingForm(forms.FieldsForm):
-	__regid__ = 'massmailing'
-
-	needs_js = ('cubicweb.widgets.js',)
-	domid = 'sendmail'
-	action = 'sendmail'
-
-	sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
-				label=_('From:'),
-				value=sender_value)
-
-	recipient = ff.StringField(widget=CheckBox(),
-	                           label=_('Recipients:'),
-				   choices=recipient_choices,
-				   value=recipients_value)
-
-	subject = ff.StringField(label=_('Subject:'), max_length=256)
-
-	mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
-						    inputid='mailbody'))
-
-	form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
-				  _('send email'), 'SEND_EMAIL_ICON'),
-			ImgButton('cancelbutton', "javascript: history.back()",
-				  stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
-
-Let's detail what's going on up there. Our form will hold four fields:
-
-* a sender field, which is disabled and will simply contains the user's name and
-  email
-
-* a recipients field, which will be displayed as a list of users in the context
-  result set with checkboxes so user can still choose who will receive his mailing
-  by checking or not the checkboxes. By default all of them will be checked since
-  field's value return a list containing same eids as those returned by the
-  vocabulary function.
-
-* a subject field, limited to 256 characters (hence we know a
-  :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
-  :class:`~cubicweb.web.formfields.StringField`)
-
-* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
-  and whose definition won't be shown here. Notice though that we tell this form
-  need this javascript file by using `needs_js`
-
-Last but not least, we add two buttons control: one to post the form using
-javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
-set to 'sendmail', which is our form DOM id as specified by its `domid`
-attribute), another to cancel the form which will go back to the previous page
-using another javascript call. Also we specify image to used as button icon a
-resource identifier (see :ref:`external_resources`) given as last argument to
-:class:`cubicweb.web.formwidgets.ImgButton`.
-
-To see this form, we still have to wrap it in a view. This is pretty simple:
-
-.. sourcecode:: python
-
-    class MassMailingFormView(form.FormViewMixIn, EntityView):
-	__regid__ = 'massmailing'
-	__select__ = implements(IEmailable) & authenticated_user()
-
-	def call(self):
-	    form = self._cw.vreg['forms'].select('massmailing', self._cw,
-	                                         rset=self.cw_rset)
-	    self.w(form.render())
-
-As you see, we simply define a view with proper selector so it only apply to a
-result set containing :class:`IEmailable` entities, and so that only users in the
-managers or users group can use it. Then in the `call()` method for this view we
-simply select the above form and write what its `.render()` method returns.
-
-When this form is submitted, a controller with id 'sendmail' will be called (as
-specified using `action`). This controller will be responsible to actually send
-the mail to specified recipients.
-
-Here is what it looks like:
-
-.. sourcecode:: python
-
-    class SendMailController(Controller):
-        __regid__ = 'sendmail'
-        __select__ = authenticated_user() & match_form_params('recipient', 'mailbody', 'subject')
-
-        def publish(self, rset=None):
-            body = self._cw.form['mailbody']
-            subject = self._cw.form['subject']
-            eids = self._cw.form['recipient']
-            # eids may be a string if only one recipient was specified
-            if isinstance(eids, basestring):
-                rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
-            else:
-                rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
-            recipients = list(rset.entities())
-            msg = format_mail({'email' : self._cw.user.get_email(),
-                               'name' : self._cw.user.dc_title()},
-                              recipients, body, subject)
-            if not self._cw.vreg.config.sendmails([(msg, recipients]):
-                msg = self._cw._('could not connect to the SMTP server')
-            else:
-                msg = self._cw._('emails successfully sent')
-            raise Redirect(self._cw.build_url(__message=msg))
-
-
-The entry point of a controller is the publish method. In that case we simply get
-back post values in request's `form` attribute, get user instances according
-to eids found in the 'recipient' form value, and send email after calling
-:func:`format_mail` to get a proper email message. If we can't send email or
-if we successfully sent email, we redirect to the index page with proper message
-to inform the user.
-
-Also notice that our controller has a selector that deny access to it to
-anonymous users (we don't want our instance to be used as a spam relay), but also
-check expected parameters are specified in forms. That avoid later defensive
-programming (though it's not enough to handle all possible error cases).
-
-To conclude our example, suppose we wish a different form layout and that existent
-renderers are not satisfying (we would check that first of course :). We would then
-have to define our own renderer:
-
-.. sourcecode:: python
-
-    class MassMailingFormRenderer(formrenderers.FormRenderer):
-        __regid__ = 'massmailing'
-
-        def _render_fields(self, fields, w, form):
-            w(u'<table class="headersform">')
-            for field in fields:
-                if field.name == 'mailbody':
-                    w(u'</table>')
-                    w(u'<div id="toolbar">')
-                    w(u'<ul>')
-                    for button in form.form_buttons:
-                        w(u'<li>%s</li>' % button.render(form))
-                    w(u'</ul>')
-                    w(u'</div>')
-                    w(u'<div>')
-                    w(field.render(form, self))
-                    w(u'</div>')
-                else:
-                    w(u'<tr>')
-                    w(u'<td class="hlabel">%s</td>' % self.render_label(form, field))
-                    w(u'<td class="hvalue">')
-                    w(field.render(form, self))
-                    w(u'</td></tr>')
-
-        def render_buttons(self, w, form):
-            pass
-
-We simply override the `_render_fields` and `render_buttons` method of the base form renderer
-to arrange fields as we desire it: here we'll have first a two columns table with label and
-value of the sender, recipients and subject field (form order respected), then form controls,
-then a div containing the textarea for the email's content.
-
-To bind this renderer to our form, we should add to our form definition above:
-
-.. sourcecode:: python
-
-    form_renderer_id = 'massmailing'
-
-
-.. Example of entity fields form
--- a/doc/book/en/development/devweb/httpcaching.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-HTTP cache management
----------------------
-XXX feedme
\ No newline at end of file
--- a/doc/book/en/development/devweb/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-Web development
-===============
-
-In this chapter, we will describe the core APIs for web development in
-the *CubicWeb* framework.
-
-.. toctree::
-   :maxdepth: 2
-
-   publisher
-   controllers
-   request
-   views/index
-   rtags
-   js
-   css
-   form
-   facets
-   internationalization
-   property
-   httpcaching
--- a/doc/book/en/development/devweb/internationalization.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _internationalization:
-
-Internationalization
----------------------
-
-Cubicweb fully supports the internalization of its content and interface.
-
-Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
-
-.. _`GNU gettext`: http://www.gnu.org/software/gettext/
-
-Cubicweb' internalization involves two steps:
-
-* in your Python code and cubicweb-tal templates : mark translatable strings
-
-* in your instance : handle the translation catalog, edit translations
-
-String internationalization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-User defined string
-```````````````````
-
-In the Python code and cubicweb-tal templates translatable strings can be
-marked in one of the following ways :
-
- * by using the *built-in* function `_` ::
-
-     class PrimaryView(EntityView):
-         """the full view of an non final entity"""
-         __regid__ = 'primary'
-         title = _('primary')
-
-  OR
-
- * by using the equivalent request's method ::
-
-     class NoResultView(View):
-         """default view when no result has been found"""
-         __regid__ = 'noresult'
-
-         def call(self, **kwargs):
-             self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
-                 % self._cw._('No result matching query'))
-
-The goal of the *built-in* function `_` is only **to mark the
-translatable strings**, it will only return the string to translate
-itself, but not its translation (it's actually another name for the
-`unicode` builtin).
-
-In the other hand the request's method `self._cw._` is also meant to
-retrieve the proper translation of translation strings in the
-requested language.
-
-Finally you can also use the `__` attribute of request object to get a
-translation for a string *which should not itself added to the catalog*,
-usually in case where the actual msgid is created by string interpolation ::
-
-  self._cw.__('This %s' % etype)
-
-In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
-messages catalogs.
-
-Translations in cubicweb-tal template can also be done with TAL tags
-`i18n:content` and `i18n:replace`.
-
-If you need to add messages on top of those that can be found in the source,
-you can create a file named `i18n/static-messages.pot`.
-
-You could put there messages not found in the python sources or
-overrides for some messages of used cubes.
-
-Generated string
-````````````````
-
-We do not need to mark the translation strings of entities/relations used by a
-particular instance's schema as they are generated automatically. String for
-various actions are also generated.
-
-For exemple the following schema ::
-
-  Class EntityA(EntityType):
-      relation_a2b = SubjectRelation('EntityB')
-
-  class EntityB(EntityType):
-      pass
-
-May generate the following message ::
-
-  add EntityA relation_a2b EntityB subject
-
-This message will be used in views of ``EntityA`` for creation of a new
-``EntityB`` with a preset relation ``relation_a2b`` between the current
-``EntityA`` and the new ``EntityB``. The opposite message ::
-
-  add EntityA relation_a2b EntityB object
-
-Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
-title of they respective creation form will be ::
-
-  creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
-
-  creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
-
-In the translated string you can use ``%(linkto)s`` for reference to the source
-``entity``.
-
-Handling the translation catalog
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Once the internationalization is done in your code, you need to populate and
-update the translation catalog. Cubicweb provides the following commands for this
-purpose:
-
-
-* `i18ncubicweb` updates Cubicweb framework's translation
-  catalogs. Unless you actually work on the framework itself, you
-  don't need to use this command.
-
-* `i18ncube` updates the translation catalogs of *one particular cube*
-  (or of all cubes). After this command is executed you must update
-  the translation files *.po* in the "i18n" directory of your
-  cube. This command will of course not remove existing translations
-  still in use. It will mark unused translation but not remove them.
-
-* `i18ninstance` recompiles the translation catalogs of *one particular
-  instance* (or of all instances) after the translation catalogs of
-  its cubes have been updated. This command is automatically
-  called every time you create or update your instance. The compiled
-  catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
-  instance where `lang` is the language identifier ('en' or 'fr'
-  for exemple).
-
-
-Example
-```````
-
-You have added and/or modified some translation strings in your cube
-(after creating a new view or modifying the cube's schema for exemple).
-To update the translation catalogs you need to do:
-
-1. `cubicweb-ctl i18ncube <cube>`
-2. Edit the <cube>/i18n/xxx.po  files and add missing translations (empty `msgstr`)
-3. `hg ci -m "updated i18n catalogs"`
-4. `cubicweb-ctl i18ninstance <myinstance>`
-
-Editing po files
-~~~~~~~~~~~~~~~~
-
-Using a PO aware editor
-````````````````````````
-
-Many tools exist to help maintain .po (PO) files. Common editors or
-development environment provides modes for these. One can also find
-dedicated PO files editor, such as `poedit`_.
-
-.. _`poedit`:  http://www.poedit.net/
-
-While usage of such a tool is commendable, PO files are perfectly
-editable with a (unicode aware) plain text editor. It is also useful
-to know their structure for troubleshooting purposes.
-
-Structure of a PO file
-``````````````````````
-
-In this section, we selectively quote passages of the `GNU gettext`_
-manual chapter on PO files, available there::
-
- http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
-
-One PO file entry has the following schematic structure::
-
-     white-space
-     #  translator-comments
-     #. extracted-comments
-     #: reference...
-     #, flag...
-     #| msgid previous-untranslated-string
-     msgid untranslated-string
-     msgstr translated-string
-
-
-A simple entry can look like this::
-
-     #: lib/error.c:116
-     msgid "Unknown system error"
-     msgstr "Error desconegut del sistema"
-
-It is also possible to have entries with a context specifier. They
-look like this::
-
-     white-space
-     #  translator-comments
-     #. extracted-comments
-     #: reference...
-     #, flag...
-     #| msgctxt previous-context
-     #| msgid previous-untranslated-string
-     msgctxt context
-     msgid untranslated-string
-     msgstr translated-string
-
-
-The context serves to disambiguate messages with the same
-untranslated-string. It is possible to have several entries with the
-same untranslated-string in a PO file, provided that they each have a
-different context. Note that an empty context string and an absent
-msgctxt line do not mean the same thing.
-
-Contexts and CubicWeb
-`````````````````````
-
-CubicWeb PO files have both non-contextual and contextual msgids.
-
-Contextual entries are automatically used in some cases. For instance,
-entity.dc_type(), eschema.display_name(req) or display_name(etype,
-req, form, context) methods/function calls will use them.
-
-It is also possible to explicitly use the with _cw.pgettext(context,
-msgid).
--- a/doc/book/en/development/devweb/js.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,355 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Javascript
-----------
-
-*CubicWeb* uses quite a bit of javascript in its user interface and
-ships with jquery (1.3.x) and parts of the jquery UI library, plus a
-number of homegrown files and also other third party libraries.
-
-All javascript files are stored in cubicweb/web/data/. There are
-around thirty js files there. In a cube it goes to data/.
-
-Obviously one does not want javascript pieces to be loaded all at
-once, hence the framework provides a number of mechanisms and
-conventions to deal with javascript resources.
-
-Conventions
-~~~~~~~~~~~
-
-It is good practice to name cube specific js files after the name of
-the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
-
-XXX external_resources variable (which needs love)
-
-CubicWeb javascript API
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Javascript resources are typically loaded on demand, from views. The
-request object (available as self._cw from most application objects,
-for instance views and entities objects) has a few methods to do that:
-
-* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
-  javascript files and writes proper entries into the HTML header
-  section. The localfile parameter allows to declare resources which
-  are not from web/data (for instance, residing on a content delivery
-  network).
-
-* `add_onload(self, jscode)` which adds one raw javascript code
-  snippet inline in the html headers. This is quite useful for setting
-  up early jQuery(document).ready(...) initialisations.
-
-CubicWeb javascript events
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* ``server-response``: this event is triggered on HTTP responses (both
-  standard and ajax). The two following extra parameters are passed
-  to callbacks :
-
-  - ``ajax``: a boolean that says if the reponse was issued by an
-    ajax request
-
-  - ``node``: the DOM node returned by the server in case of an
-    ajax request, otherwise the document itself for standard HTTP
-    requests.
-
-Important AJAX APIS
-~~~~~~~~~~~~~~~~~~~
-
-* `asyncRemoteExec` and `remoteExec` are the base building blocks for
-  doing arbitrary async (resp. sync) communications with the server
-
-* `reloadComponent` is a convenience function to replace a DOM node
-  with server supplied content coming from a specific registry (this
-  is quite handy to refresh the content of some boxes for instances)
-
-* `jQuery.fn.loadxhtml` is an important extension to jQuery which
-  allows proper loading and in-place DOM update of xhtml views. It is
-  suitably augmented to trigger necessary events, and process CubicWeb
-  specific elements such as the facet system, fckeditor, etc.
-
-
-A simple example with asyncRemoteExec
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In the python side, we have to extend the BaseController class. The
-@jsonize decorator ensures that the `return value` of the method is
-encoded as JSON data. By construction, the JSonController inputs
-everything in JSON format.
-
-.. sourcecode: python
-
-    from cubicweb.web.views.basecontrollers import JSonController, jsonize
-
-    @monkeypatch(JSonController)
-    @jsonize
-    def js_say_hello(self, name):
-        return u'hello %s' % name
-
-In the javascript side, we do the asynchronous call. Notice how it
-creates a `deferred` object. Proper treatment of the return value or
-error handling has to be done through the addCallback and addErrback
-methods.
-
-.. sourcecode: javascript
-
-    function asyncHello(name) {
-        var deferred = asyncRemoteExec('say_hello', name);
-        deferred.addCallback(function (response) {
-            alert(response);
-        });
-        deferred.addErrback(function (error) {
-            alert('something fishy happened');
-        });
-     }
-
-     function syncHello(name) {
-         alert( remoteExec('say_hello', name) );
-     }
-
-Anatomy of a reloadComponent call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`reloadComponent` allows to dynamically replace some DOM node with new
-elements. It has the following signature:
-
-* `compid` (mandatory) is the name of the component to be reloaded
-
-* `rql` (optional) will be used to generate a result set given as
-  argument to the selected component
-
-* `registry` (optional) defaults to 'components' but can be any other
-  valid registry name
-
-* `nodeid` (optional) defaults to compid + 'Component' but can be any
-  explicitly specified DOM node id
-
-* `extraargs` (optional) should be a dictionary of values that will be
-  given to the cell_call method of the component
-
-A simple reloadComponent example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The server side implementation of `reloadComponent` is the
-js_component method of the JSonController.
-
-The following function implements a two-steps method to delete a
-standard bookmark and refresh the UI, while keeping the UI responsive.
-
-.. sourcecode:: javascript
-
-    function removeBookmark(beid) {
-        d = asyncRemoteExec('delete_bookmark', beid);
-        d.addCallback(function(boxcontent) {
-	    reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
-            document.location.hash = '#header';
-            updateMessage(_("bookmark has been removed"));
-         });
-    }
-
-`reloadComponent` is called with the id of the bookmark box as
-argument, no rql expression (because the bookmarks display is actually
-independant of any dataset context), a reference to the 'boxes'
-registry (which hosts all left, right and contextual boxes) and
-finally an explicit 'bookmarks_box' nodeid argument that stipulates
-the target DOM node.
-
-Anatomy of a loadxhtml call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
-proper loading and in-place DOM update of xhtml views. The existing
-`jQuery.load`_ function does not handle xhtml, hence the addition. The
-API of loadxhtml is roughly similar to that of `jQuery.load`_.
-
-.. _`jQuery.load`: http://api.jquery.com/load/
-
-
-* `url` (mandatory) should be a complete url (typically referencing
-  the JSonController, but this is not strictly mandatory)
-
-* `data` (optional) is a dictionary of values given to the
-  controller specified through an `url` argument; some keys may have a
-  special meaning depending on the choosen controller (such as `fname`
-  for the JSonController); the `callback` key, if present, must refer
-  to a function to be called at the end of loadxhtml (more on this
-  below)
-
-* `reqtype` (optional) specifies the request method to be used (get or
-  post); if the argument is 'post', then the post method is used,
-  otherwise the get method is used
-
-* `mode` (optional) is one of `replace` (the default) which means the
-  loaded node will replace the current node content, `swap` to replace
-  the current node with the loaded node, and `append` which will
-  append the loaded node to the current node content
-
-About the `callback` option:
-
-* it is called with two parameters: the current node, and a list
-  containing the loaded (and post-processed node)
-
-* whenever is returns another function, this function is called in
-  turn with the same parameters as above
-
-This mechanism allows callback chaining.
-
-
-A simple example with loadxhtml
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here we are concerned with the retrieval of a specific view to be
-injected in the live DOM. The view will be of course selected
-server-side using an entity eid provided by the client side.
-
-.. sourcecode:: python
-
-    from cubicweb import typed_eid
-    from cubicweb.web.views.basecontrollers import JSonController, xhtmlize
-
-    @monkeypatch(JSonController)
-    @xhtmlize
-    def js_frob_status(self, eid, frobname):
-        entity = self._cw.entity_from_eid(typed_eid(eid))
-        return entity.view('frob', name=frobname)
-
-.. sourcecode:: javascript
-
-    function update_some_div(divid, eid, frobname) {
-        var params = {fname:'frob_status', eid: eid, frobname:frobname};
-        jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
-     }
-
-In this example, the url argument is the base json url of a cube
-instance (it should contain something like
-`http://myinstance/json?`). The actual JSonController method name is
-encoded in the `params` dictionary using the `fname` key.
-
-A more real-life example from CubicWeb
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A frequent use case of Web 2 applications is the delayed (or
-on-demand) loading of pieces of the DOM. This is typically achieved
-using some preparation of the initial DOM nodes, jQuery event handling
-and proper use of loadxhtml.
-
-We present here a skeletal version of the mecanism used in CubicWeb
-and available in web/views/tabs.py, in the `LazyViewMixin` class.
-
-.. sourcecode:: python
-
-    def lazyview(self, vid, rql=None):
-        """ a lazy version of wview """
-        w = self.w
-        self._cw.add_js('cubicweb.lazy.js')
-        urlparams = {'vid' : vid, 'fname' : 'view'}
-        if rql is not None:
-            urlparams['rql'] = rql
-        w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
-            vid, xml_escape(self._cw.build_url('json', **urlparams))))
-        w(u'</div>')
-        self._cw.add_onload(u"""
-            jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
-                   load_now('#lazy-%(vid)s');});"""
-            % {'event': 'load_%s' % vid, 'vid': vid})
-
-This creates a `div` with a specific event associated to it.
-
-The full version deals with:
-
-* optional parameters such as an entity eid, an rset
-
-* the ability to further reload the fragment
-
-* the ability to display a spinning wheel while the fragment is still
-  not loaded
-
-* handling of browsers that do not support ajax (search engines,
-  text-based browsers such as lynx, etc.)
-
-The javascript side is quite simple, due to loadxhtml awesomeness.
-
-.. sourcecode:: javascript
-
-    function load_now(eltsel) {
-        var lazydiv = jQuery(eltsel);
-        lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
-    }
-
-This is all significantly different of the previous `simple example`
-(albeit this example actually comes from real-life code).
-
-Notice how the `cubicweb:loadurl` is used to convey the url
-information. The base of this url is similar to the global javascript
-JSON_BASE_URL. According to the pattern described earlier,
-the `fname` parameter refers to the standard `js_view` method of the
-JSonController. This method renders an arbitrary view provided a view
-id (or `vid`) is provided, and most likely an rql expression yielding
-a result set against which a proper view instance will be selected.
-
-The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML
-in a specific cubicweb namespace. It is a means to pass information
-without breaking HTML nor XHTML compliance and without resorting to
-ungodly hacks.
-
-Given all this, it is easy to add a small nevertheless useful feature
-to force the loading of a lazy view (for instance, a very
-computation-intensive web page could be scinded into one fast-loading
-part and a delayed part).
-
-On the server side, a simple call to a javascript function is
-sufficient.
-
-.. sourcecode:: python
-
-    def forceview(self, vid):
-        """trigger an event that will force immediate loading of the view
-        on dom readyness
-        """
-        self._cw.add_onload("trigger_load('%s');" % vid)
-
-The browser-side definition follows.
-
-.. sourcecode:: javascript
-
-    function trigger_load(divid) {
-        jQuery('#lazy-' + divd).trigger('load_' + divid);
-    }
-
-
-
-
-XXX reloadComponent
-XXX userCallback / user_callback
-
-Javascript library: overview
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* jquery.* : jquery and jquery UI library
-
-* cubicweb.ajax.js : concentrates all ajax related facilities (it
-  extends jQuery with the loahxhtml function, provides a handfull of
-  high-level ajaxy operations like asyncRemoteExec, reloadComponent,
-  replacePageChunk, getDomFromResponse)
-
-* cubicweb.python.js : adds a number of practical extension to stdanrd
-  javascript objects (on Date, Array, String, some list and dictionary
-  operations), and a pythonesque way to build classes. Defines a
-  CubicWeb namespace.
-
-* cubicweb.htmlhelpers.js : a small bag of convenience functions used
-  in various other cubicweb javascript resources (baseuri, progress
-  cursor handling, popup login box, html2dom function, etc.)
-
-* cubicweb.widgets.js : provides a widget namespace and constructors
-  and helpers for various widgets (mainly facets and timeline)
-
-* cubicweb.edition.js : used by edition forms
-
-* cubicweb.preferences.js : used by the preference form
-
-* cubicweb.facets.js : used by the facets mechanism
-
-There is also javascript support for massmailing, gmap (google maps),
-fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
-AppEngine), flot (charts drawing), tabs and bookmarks.
--- a/doc/book/en/development/devweb/property.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-The property mecanism
----------------------
-XXX CWProperty and co
-
-
-Property API
-~~~~~~~~~~~~
-XXX feed me
-
-Registering and using your own property
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX feed me
--- a/doc/book/en/development/devweb/publisher.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-.. _publisher:
-
-Publisher
----------
-
-What happens when an HTTP request is issued ?
-
-The story begins with the ``CubicWebPublisher.main_publish``
-method. We do not get upper in the bootstrap process because it is
-dependant on the used HTTP library. With `twisted`_ however,
-``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the
-real entry point.
-
-What main_publish does:
-
-* get a controller id and a result set from the path (this is actually
-  delegated to the `urlpublisher` component)
-
-* the controller is then selected (if not, this is considered an
-  authorization failure and signaled as such) and called
-
-* then either a proper result is returned, in which case the
-  request/connection object issues a ``commit`` and returns the result
-
-* or error handling must happen:
-
-  * ``ValidationErrors`` pop up there and may lead to a redirect to a
-    previously arranged url or standard error handling applies
-  * an HTTP 500 error (`Internal Server Error`) is issued
-
-
-Now, let's turn to the controller. There are many of them in
-:mod:`cubicweb.web.views.basecontrollers`. We can just follow the
-default `view` controller that is selected on a `view` path. See the
-:ref:`controllers` chapter for more information on controllers.
-
-The `View` controller's entry point is the `publish` method. It does
-the following:
-
-* compute the `main` view to be applied, using either the given result
-  set or building one from a user provided rql string (`rql` and `vid`
-  can be forced from the url GET parameters), that is:
-
-    * compute the `vid` using the result set and the schema (see
-      `cubicweb.web.views.vid_from_rset`)
-    * handle all error cases that could happen in this phase
-
-* do some cache management chores
-
-* select a main template (typically `TheMainTemplate`, see chapter
-  :ref:`templates`)
-
-* call it with the result set and the computed view.
-
-What happens next actually depends on the template and the view, but
-in general this is the rendering phase.
-
-
-CubicWebPublisher API
-`````````````````````
-
-.. autoclass:: cubicweb.web.application.CubicWebPublisher
-   :members:
--- a/doc/book/en/development/devweb/request.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-The `Request` class (`cubicweb.web`)
-------------------------------------
-
-Overview
-````````
-
-A request instance is created when an HTTP request is sent to the web server.
-It contains informations such as form parameters, user authenticated, etc.
-
-**Globally, a request represents a user query, either through HTTP or not
-(we also talk about RQL queries on the server side for example).**
-
-An instance of `Request` has the following attributes:
-
-* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
-  user
-* `form`, dictionary containing the values of a web form
-* `encoding`, character encoding to use in the response
-
-But also:
-
-* `Session data handling`
-
-  * `session_data()`, returns a dictionary containing all the session data
-  * `get_session_data(key, default=None)`, returns a value associated to the given
-    key or the value `default` if the key is not defined
-  * `set_session_data(key, value)`, assign a value to a key
-  * `del_session_data(key)`,  suppress the value associated to a key
-
-*  `Cookies handling`
-
-  * `get_cookie()`, returns a dictionary containing the value of the header
-    HTTP 'Cookie'
-  * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
-    with a minimal 5 minutes length of duration by default (`maxage` = None
-    returns a *session* cookie which will expire when the user closes the browser
-    window)
-  * `remove_cookie(cookie, key)`, forces a value to expire
-
-* `URL handling`
-
-  * `url()`, returns the full URL of the HTTP request
-  * `base_url()`, returns the root URL of the web application
-  * `relative_path()`, returns the relative path of the request
-
-* `And more...`
-
-  * `set_content_type(content_type, filename=None)`, adds the header HTTP
-    'Content-Type'
-  * `get_header(header)`, returns the value associated to an arbitrary header
-    of the HTTP request
-  * `set_header(header, value)`, adds an arbitrary header in the response
-  * `cursor()` returns a RQL cursor on the session
-  * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
-  * `property_value(key)`, properties management (`CWProperty`)
-  * dictionary `data` to store data to share informations between components
-    *while a request is executed*
-
-Please note that this class is abstract and that a concrete implementation
-will be provided by the *frontend* web used (in particular *twisted* as of
-today). For the views or others that are executed on the server side,
-most of the interface of `Request` is defined in the session associated
-to the client.
-
-API
-```
-
-The elements we gave in overview for above are built in three layers,
-from ``cubicweb.req.RequestSessionBase``, ``cubicweb.dbapi.DBAPIRequest`` and
-``cubicweb.web.CubicWebRequestBase``.
-
-.. autoclass:: cubicweb.req.RequestSessionBase
-   :members:
-
-.. autoclass:: cubicweb.dbapi.DBAPIRequest
-   :members:
-
-.. autoclass:: cubicweb.web.request.CubicWebRequestBase
-   :members:
--- a/doc/book/en/development/devweb/rtags.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-Configuring the user interface
-------------------------------
-
-.. _relation_tags:
-
-Relation tags
-~~~~~~~~~~~~~
-.. automodule:: cubicweb.rtags
-
-.. _uicfg:
-
-The ``uicfg`` module
-~~~~~~~~~~~~~~~~~~~~
-
-.. note::
-
- The part of uicfg that deals with primary views is in the
- :ref:`primary_view_configuration` chapter.
-
-.. automodule:: cubicweb.web.uicfg
-
--- a/doc/book/en/development/devweb/views/basetemplates.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. |cubicweb| replace:: *CubicWeb*
-
-.. _templates:
-
-Templates
-=========
-
-Templates are the entry point for the |cubicweb| view system. As seen
-in :ref:`views_base_class`, there are two kinds of views: the
-templatable and non-templatable.
-
-Non-templatable views are standalone. They are responsible for all the
-details such as setting a proper content type (or mime type), the
-proper document headers, namespaces, etc. Examples are pure xml views
-such as RSS or Semantic Web views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked
-Data`_, etc.).
-
-.. _`SIOC`: http://sioc-project.org/
-.. _`DOAP`: http://trac.usefulinc.com/doap
-.. _`FOAF`: http://www.foaf-project.org/
-.. _`Linked Data`: http://linkeddata.org/
-
-Templatable views are not concerned with such pesky details. They
-leave it to the template. Conversely, the template's main job is to:
-
-* set up the proper document header and content type
-* define the general layout of a document
-* invoke adequate views in the various sections of the document
-
-
-Look at :mod:`cubicweb.web.views.basetemplates` and you will find the
-base templates used to generate (X)HTML for your application. The most
-important template there is `TheMainTemplate`.
-
-.. _the_main_template_layout:
-
-TheMainTemplate
----------------
-
-.. _the_main_template_sections:
-
-Layout and sections
-```````````````````
-
-A page is composed as indicated on the schema below :
-
-.. image:: ../../../images/main_template.png
-
-The sections dispatches specific views:
-
-* `header`: the rendering of the header is delegated to the
-  `htmlheader` view, whose default implementation can be found in
-  ``basetemplates.py`` and which does the following things:
-
-    * inject the favicon if there is one
-    * inject the global style sheets and javascript resources
-    * call and display a link to an rss component if there is one available
-
-  it also sets up the page title, and fills the actual
-  `header` section with top-level components, using the `header` view, which:
-
-    * tries to display a logo, the name of the application and the `breadcrumbs`
-    * provides a login status area
-    * provides a login box (hiden by default)
-
-* `left column`: this is filled with all selectable boxes matching the
-  `left` context (there is also a right column but nowadays it is
-  seldom used due to bad usability)
-
-* `contentcol`: this is the central column; it is filled with:
-
-    * the `rqlinput` view (hidden by default)
-    * the `applmessages` component
-    * the `contentheader` view which in turns dispatches all available
-      content navigation components having the `navtop` context (this
-      is used to navigate through entities implementing the IPrevNext
-      interface)
-    * the view that was given as input to the template's `call`
-      method, also dealing with pagination concerns
-    * the `contentfooter`
-
-* `footer`: adds all footer actions
-
-.. note::
-
-  How and why a view object is given to the main template is explained
-  in the :ref:`publisher` chapter.
-
-Class attributes
-````````````````
-
-We can also control certain aspects of the main template thanks to the following
-forms parameters:
-
-* `__notemplate`, if present (whatever the value assigned), only the content view
-  is returned
-* `__force_display`, if present and its value is not null, no navigation
-  whatever the number of entities to display
-* `__method`, if the result set to render contains only one entity and this
-  parameter is set, it refers to a method to call on the entity by passing it
-  the dictionary of the forms parameters, before going the classic way (through
-  step 1 and 2 described juste above)
-
-Other templates
----------------
-
-Other standard templates include:
-
-* `login` and `logout`
-
-* `error-template` specializes TheMainTemplate to do proper end-user
-  output if an error occurs during the computation of TheMainTemplate
-  (it is a fallback view).
--- a/doc/book/en/development/devweb/views/baseviews.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Base views
-----------
-
-*CubicWeb* provides a lot of standard views, that can be found in
- :mod:`cubicweb.web.views` and :mod:`cubicweb.web.views.baseviews`.
-
-A certain number of views are used to build the web interface, which
-apply to one or more entities. Their identifier is what distinguish
-them from each others and the main ones are:
-
-HTML views
-~~~~~~~~~~
-
-Special views
-`````````````
-
-*noresult*
-    This view is the default view used when no result has been found
-    (e.g. empty result set).
-
-*final*
-    Display the value of a cell without trasnformation (in case of a non final
-    entity, we see the eid). Applicable on any result set.
-
-.. note::
-
-   `final` entities are merely attributes.
-
-*null*
-    This view is the default view used when nothing needs to be rendered.
-    It is always applicable.
-
-Entity views
-````````````
-
-*incontext, outofcontext*
-    Those are used to display a link to an entity, depending on the
-    entity having to be displayed in or out of context
-    (of another entity).  By default it respectively produces the
-    result of `textincontext` and `textoutofcontext` wrapped in a link
-    leading to the primary view of the entity.
-
-*oneline*
-    This view is used when we can't tell if the entity should be considered as
-    displayed in or out of context.  By default it produces the result of `text`
-    in a link leading to the primary view of the entity.
-
-List
-`````
-
-*list*
-    This view displays a list of entities by creating a HTML list (`<ul>`)
-    and call the view `listitem` for each entity of the result set.
-
-*listitem*
-    This view redirects by default to the `outofcontext` view.
-
-*sameetypelist*
-    This view displays a list of entities of the same type, in HTML section (`<div>`)
-    and call the view `sameetypelistitem` for each entity of the result set.
-
-*sameetypelistitem*
-    This view redirects by default to the `listitem` view.
-
-*csv*
-    This view applies to entity groups, which are individually
-    displayed using the `incontext` view. It displays each entity as a
-    coma separated list. It is NOT related to the well-known text file
-    format.
-
-Text entity views
-~~~~~~~~~~~~~~~~~
-
-*text*
-    This is the simplest text view for an entity. By default it returns the
-    result of the `.dc_title` method, which is cut to fit the
-    `navigation.short-line-size` property if necessary.
-
-*textincontext, textoutofcontext*
-    Similar to the `text` view, but called when an entity is considered out or
-    in context. By default it returns respectively the result of the
-    methods `.dc_title` and `.dc_long_title` of the entity.
--- a/doc/book/en/development/devweb/views/boxes.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-Boxes
------
-
-(:mod:`cubicweb.web.views.boxes`)
-
-*sidebox*
-  This view displays usually a side box of some related entities
-  in a primary view.
-
-The action box
-~~~~~~~~~~~~~~~
-
-The ``add_related`` is an automatic menu in the action box that allows to create
-an entity automatically related to the initial entity (context in
-which the box is displayed). By default, the links generated in this
-box are computed from the schema properties of the displayed entity,
-but it is possible to explicitly specify them thanks to the
-`cubicweb.web.uicfg.rmode` *relation tag*:
-
-* `link`, indicates that a relation is in general created pointing
-  to an existing entity and that we should not to display a link
-  for this relation
-
-* `create`, indicates that a relation is in general created pointing
-  to new entities and that we should display a link to create a new
-  entity and link to it automatically
-
-
-If necessary, it is possible to overwrite the method
-`relation_mode(rtype, targettype, x='subject')` to dynamically
-compute a relation creation category.
-
-Please note that if at least one action belongs to the `addrelated` category,
-the automatic behavior is desactivated in favor of an explicit behavior
-(e.g. display of `addrelated` category actions only).
-
--- a/doc/book/en/development/devweb/views/breadcrumbs.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-Breadcrumbs
------------
-
-Breadcrumbs are a navigation component to help the user locate himself
-along a path of entities.
-
-Display
-~~~~~~~
-
-Breadcrumbs are displayed by default in the header section (see
-:ref:`the_main_template_sections`).  With the default main
-template, the header section is composed by the logo, the application
-name, breadcrumbs and, at the most right, the login box. Breadcrumbs
-are displayed just next to the application name, thus breadcrumbs
-begin with a separator.
-
-Here is the header section of the CubicWeb's forge:
-
-.. image:: ../../../images/breadcrumbs_header.png
-
-There are three breadcrumbs components defined in
-:mod:`cubicweb.web.views.ibreadcrumbs`:
-
-- `BreadCrumbEntityVComponent`: displayed for a result set with one line
-  if the entity implements the ``IBreadCrumbs`` interface.
-- `BreadCrumbETypeVComponent`: displayed for a result set with more than
-  one line, but with all entities of the same type which implement the
-  ``IBreadCrumbs`` interface.
-- `BreadCrumbAnyRSetVComponent`: displayed for any other result set.
-
-Building breadcrumbs
-~~~~~~~~~~~~~~~~~~~~
-
-The ``IBreadCrumbs`` interface is defined in the
-:mod:`cubicweb.interfaces` module. It specifies that an entity which
-implements this interface must have a ``breadcrumbs`` method.
-
-.. note::
-
-   Redefining the breadcrumbs is the hammer way to do it. Another way
-   is to define the `parent` method on an entity (as defined in the
-   `ITree` interface). If available, it will be used to compute
-   breadcrumbs.
-
-Here is the API of the ``breadcrumbs`` method:
-
-.. automethod:: cubicweb.interfaces.IBreadCrumbs.breadcrumbs
-
-If the breadcrumbs method return a list of entities, the
-``cubicweb.web.views.ibreadcrumbs.BreadCrumbView`` is used to display
-the elements.
-
-By default, for any entity, if recurs=True, breadcrumbs method returns
-a list of entities, else a list of a simple string.
-
-In order to see a hierarchical breadcrumbs, entities must have a
-``parent`` method which returns the parent entity. By default this
-method doesn't exist on entity, given that it can not be guessed.
--- a/doc/book/en/development/devweb/views/editforms.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-Standard forms
---------------
-
- (:mod:`cubicweb.web.views.editforms`)
-
-XXX feed me
--- a/doc/book/en/development/devweb/views/embedding.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Embedding external pages
-------------------------
-
-(:mod:`cubicweb.web.views.embedding`)
-
-including external content
-
--- a/doc/book/en/development/devweb/views/idownloadable.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-The 'download' view
--------------------
-
-(:mod:`cubicweb.web.views.idownloadable`)
-
--- a/doc/book/en/development/devweb/views/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-The View system
-===============
-
-This chapter aims to describe the concept of a `view` used all along
-the development of a web application and how it has been implemented
-in |cubicweb|.
-
-
-.. toctree::
-   :maxdepth: 3
-
-   views
-   basetemplates
-   primary
-   baseviews
-   startup
-   boxes
-   table
-   xmlrss
-..   editforms
-
-.. toctree::
-   :maxdepth: 3
-
-   urlpublish
-   breadcrumbs
-..   wdoc
-..   embedding
-..   idownloadable
-
--- a/doc/book/en/development/devweb/views/primary.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,312 +0,0 @@
-.. _primary_view:
-
-The Primary View
------------------
-
-(:mod:`cubicweb.web.views.primary`)
-
-By default, *CubicWeb* provides a view that fits every available
-entity type. This is the first view you might be interested in
-modifying. It is also one of the richest and most complex.
-
-It is automatically selected on a one line result set containing an
-entity.
-
-This view is supposed to render a maximum of informations about the
-entity.
-
-.. _primary_view_layout:
-
-Layout
-``````
-
-The primary view has the following layout.
-
-.. image:: ../../../images/primaryview_template.png
-
-.. _primary_view_configuration:
-
-Primary view configuration
-``````````````````````````
-
-If you want to customize the primary view of an entity, overriding the primary
-view class may not be necessary. For simple adjustments (attributes or relations
-display locations and styles), a much simpler way is to use uicfg.
-
-Attributes/relations display location
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-In the primary view, there are 3 sections where attributes and
-relations can be displayed (represented in pink in the image above):
-
-* attributes
-* relations
-* sideboxes
-
-**Attributes** can only be displayed in the attributes section (default
-  behavior). They can also be hidden.
-
-For instance, to hide the ``title`` attribute of the ``Blog`` entity:
-
-.. sourcecode:: python
-
-   from cubicweb.web import uicfg
-   uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
-
-**Relations** can be either displayed in one of the three sections or hidden.
-
-For relations, there are two methods:
-
-* ``tag_object_of`` for modifying the primary view of the object
-* ``tag_subject_of`` for modifying the primary view of the subject
-
-These two methods take two arguments:
-
-* a triplet ``(subject, relation_name, object)``, where subject or object can be replaced with ``'*'``
-* the section name or ``hidden``
-
-.. sourcecode:: python
-
-   pv_section = uicfg.primaryview_section
-   # hide every relation `entry_of` in the `Blog` primary view
-   pv_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
-
-   # display `entry_of` relations in the `relations`
-   # section in the `BlogEntry` primary view
-   pv_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations')
-
-
-Display content
-^^^^^^^^^^^^^^^
-
-You can use ``primaryview_display_ctrl`` to customize the display of attributes
-or relations. Values of ``primaryview_display_ctrl`` are dictionaries.
-
-
-Common keys for attributes and relations are:
-
-* ``vid``: specifies the regid of the view for displaying the attribute or the relation.
-
-  If ``vid`` is not specified, the default value depends on the section:
-    * ``attributes`` section: 'reledit' view
-    * ``relations`` section: 'autolimited' view
-    * ``sideboxes`` section: 'sidebox' view
-
-* ``order``: int used to control order within a section. When not specified,
-  automatically set according to order in which tags are added.
-
-.. sourcecode:: python
-
-   # let us remind the schema of a blog entry
-   class BlogEntry(EntityType):
-       title = String(required=True, fulltextindexed=True, maxsize=256)
-       publish_date = Date(default='TODAY')
-       content = String(required=True, fulltextindexed=True)
-       entry_of = SubjectRelation('Blog', cardinality='?*')
-
-   # now, we want to show attributes
-   # with an order different from that in the schema definition
-   view_ctrl = uicfg.primaryview_display_ctrl
-   for index, attr in enumerate('title', 'content', 'publish_date'):
-       view_ctrl.tag_attribute(('BlogEntry', attr), {'order': index})
-
-Keys for relations only:
-
-* ``label``: label for the relations section or side box
-
-* ``showlabel``: boolean telling whether the label is displayed
-
-* ``limit``: boolean telling if the results should be limited. If so, a link to all results is displayed
-
-* ``filter``: callback taking the related result set as argument and returning it filtered
-
-.. sourcecode:: python
-
-   pv_section = uicfg.primaryview_section
-   # in `CWUser` primary view, display `created_by`
-   # relations in relations section
-   pv_section.tag_object_of(('*', 'created_by', 'CWUser'), 'relations')
-
-   # display this relation as a list, sets the label,
-   # limit the number of results and filters on comments
-   def filter_comment(rset):
-       return rset.filtered_rset(lambda x: x.e_schema == 'Comment')
-   pv_ctrl = uicfg.primaryview_display_ctrl
-   pv_ctrl.tag_object_of(('*', 'created_by', 'CWUser'),
-                         {'vid': 'list', 'label': _('latest comment(s):'),
-                          'limit': True,
-                          'filter': filter_comment})
-
-.. warning:: with the ``primaryview_display_ctrl`` rtag, the subject or the
-   object of the relation is ignored for respectively ``tag_object_of`` or
-   ``tag_subject_of``. To avoid warnings during execution, they should be set to
-   ``'*'``.
-
-Rendering methods and attributes
-````````````````````````````````
-
-The basic layout of a primary view is as in the
-:ref:`primary_view_layout` section. This layout is actually drawn by
-the `render_entity` method.
-
-The methods you may want to modify while customizing a ``PrimaryView``
-are:
-
-*render_entity_title(self, entity)*
-    Renders the entity title using the ``def dc_title(self)`` method.
-
-*render_entity_metadata(self, entity)*
-    Renders the entity metadata by calling the ``metadata`` view on the
-    entity. This generic view is in cubicweb.views.baseviews.
-
-*render_entity_attributes(self, entity)*
-    Renders all the attribute of an entity with the exception of
-    attribute of type `Password` and `Bytes`. The skip_none class
-    attribute controls the display of None valued attributes.
-
-*render_entity_relations(self, entity)*
-    Renders all the relations of the entity in the main section of the page.
-
-*render_side_boxes(self, entity, boxes)*
-    Renders relations of the entity in a side box.
-
-The placement of relations in the relations section or in side boxes
-can be controlled through the :ref:`primary_view_configuration` mechanism.
-
-*content_navigation_components(self, context)*
-    This method is applicable only for entity type implementing the interface
-    `IPrevNext`. This interface is for entities which can be linked to a previous
-    and/or next entity. This method will render the navigation links between
-    entities of this type, either at the top or at the bottom of the page
-    given the context (navcontent{top|bottom}).
-
-Also, please note that by setting the following attributes in your
-subclass, you can already customize some of the rendering:
-
-*show_attr_label*
-    Renders the attribute label next to the attribute value if set to True.
-    Otherwise, does only display the attribute value.
-
-*show_rel_label*
-    Renders the relation label next to the relation value if set to True.
-    Otherwise, does only display the relation value.
-
-*skip_none*
-    Does not render an attribute value that is None if set to True.
-
-*main_related_section*
-    Renders the relations of the entity if set to True.
-
-A good practice is for you to identify the content of your entity type for which
-the default rendering does not answer your need so that you can focus on the specific
-method (from the list above) that needs to be modified. We do not advise you to
-overwrite ``render_entity`` unless you want a completely different layout.
-
-Example of customization and creation
-`````````````````````````````````````
-
-We'll show you now an example of a ``primary`` view and how to customize it.
-
-We continue along the basic tutorial :ref:`tuto_blog`.
-
-If you want to change the way a ``BlogEntry`` is displayed, just override
-the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py``.
-
-.. sourcecode:: python
-
-  from cubicweb.selectors import implements
-  from cubicweb.web.views.primary import Primaryview
-
-  class BlogEntryPrimaryView(PrimaryView):
-    __select__ = PrimaryView.__select__ & implements('BlogEntry')
-
-      def render_entity_attributes(self, entity):
-          self.w(u'<p>published on %s</p>' %
-                 entity.publish_date.strftime('%Y-%m-%d'))
-          super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
-
-The above source code defines a new primary view for
-``BlogEntry``. The `id` class attribute is not repeated there since it
-is inherited through the `primary.PrimaryView` class.
-
-The selector for this view chains the selector of the inherited class
-with its own specific criterion.
-
-The view method ``self.w()`` is used to output data. Here `lines
-08-09` output HTML for the publication date of the entry.
-
-.. image:: ../../../images/lax-book.09-new-view-blogentry.en.png
-   :alt: blog entries now look much nicer
-
-Let us now improve the primary view of a blog
-
-.. sourcecode:: python
-
- from logilab.mtconverter import xml_escape
- from cubicweb.selectors import implements, one_line_rset
- from cubicweb.web.views.primary import Primaryview
-
- class BlogPrimaryView(PrimaryView):
-     __regid__ = 'primary'
-     __select__ = PrimaryView.__select__ & implements('Blog')
-     rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
-
-     def render_entity_relations(self, entity):
-         rset = self._cw.execute(self.rql, {'b' : entity.eid})
-         for entry in rset.entities():
-             self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
-
- class BlogEntryInBlogView(EntityView):
-     __regid__ = 'inblogcontext'
-     __select__ = implements('BlogEntry')
-
-     def cell_call(self, row, col):
-         entity = self.cw_rset.get_entity(row, col)
-         self.w(u'<a href="%s" title="%s">%s</a>' %
-                entity.absolute_url(),
-                xml_escape(entity.content[:50]),
-                xml_escape(entity.description))
-
-This happens in two places. First we override the
-render_entity_relations method of a Blog's primary view. Here we want
-to display our blog entries in a custom way.
-
-At `line 10`, a simple request is made to build a result set with all
-the entities linked to the current ``Blog`` entity by the relationship
-``entry_of``. The part of the framework handling the request knows
-about the schema and infers that such entities have to be of the
-``BlogEntry`` kind and retrieves them (in the prescribed publish_date
-order).
-
-The request returns a selection of data called a result set. Result
-set objects have an .entities() method returning a generator on
-requested entities (going transparently through the `ORM` layer).
-
-At `line 13` the view 'inblogcontext' is applied to each blog entry to
-output HTML. (Note that the 'inblogcontext' view is not defined
-whatsoever in *CubicWeb*. You are absolutely free to define whole view
-families.) We juste arrange to wrap each blogentry output in a 'p'
-html element.
-
-Next, we define the 'inblogcontext' view. This is NOT a primary view,
-with its well-defined sections (title, metadata, attribtues,
-relations/boxes). All a basic view has to define is cell_call.
-
-Since views are applied to result sets which can be tables of data, we
-have to recover the entity from its (row,col)-coordinates (`line
-20`). Then we can spit some HTML.
-
-.. warning::
-
-  Be careful: all strings manipulated in *CubicWeb* are actually
-  unicode strings. While web browsers are usually tolerant to
-  incoherent encodings they are being served, we should not abuse
-  it. Hence we have to properly escape our data. The xml_escape()
-  function has to be used to safely fill (X)HTML elements from Python
-  unicode strings.
-
-Assuming we added entries to the blog titled `MyLife`, displaying it
-now allows to read its description and all its entries.
-
-.. image:: ../../../images/lax-book.10-blog-with-two-entries.en.png
-   :alt: a blog and all its entries
--- a/doc/book/en/development/devweb/views/startup.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-Startup views
--------------
-
-(:mod:`cubicweb.web.views.startup`)
-
-The usual selectors are no_rset or yes. These views don't apply to a
-result set.
-
-*index*
-    This view defines the home page of your application. It does not require
-    a result set to apply to.
-
-*schema*
-    A view dedicated to the display of the schema of the instance
-
--- a/doc/book/en/development/devweb/views/table.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-Table view
-----------
-
-(:mod:`cubicweb.web.views.tableview`)
-
-*table*
-    Creates a HTML table (`<table>`) and call the view `cell` for each cell of
-    the result set. Applicable on any result set.
-
-*cell*
-    By default redirects to the `final` view if this is a final entity or
-    `outofcontext` view otherwise
-
-
-API
-```
-
-.. autoclass:: cubicweb.web.views.tableview.TableView
-   :members:
--- a/doc/book/en/development/devweb/views/urlpublish.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-URL publishing
---------------
-
-(:mod:`cubicweb.web.views.urlpublishing`)
-
-.. automodule:: cubicweb.web.views.urlpublishing
-
-.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent
-   :members:
-
-URL rewriting
--------------
-
-(:mod:`cubicweb.web.views.urlrewrite`)
-
-.. autoclass:: cubicweb.web.views.urlrewrite.URLRewriter
-   :members:
-
-.. autoclass:: cubicweb.web.views.urlrewrite.SimpleReqRewriter
-   :members:
-
-.. autoclass:: cubicweb.web.views.urlrewrite.SchemaBasedRewriter
-   :members:
-
-
-``SimpleReqRewriter`` is enough for a certain number of simple cases. If it is not sufficient, ``SchemaBasedRewriter`` allows to do more elaborate things.
-
-Here is an example of ``SimpleReqRewriter`` usage with plain string:
-
-.. sourcecode:: python
-
-   from cubicweb.web.views.urlrewrite import SimpleReqRewriter
-   class TrackerSimpleReqRewriter(SimpleReqRewriter):
-       rules = [
-        ('/versions', dict(vid='versionsinfo')),
-        ]
-
-When the url is `<base_url>/versions`, the view with the __regid__ `versionsinfo` is displayed.
-
-Here is an example of ``SimpleReqRewriter`` usage with regular expressions:
-
-.. sourcecode:: python
-
-    from cubicweb.web.views.urlrewrite import (
-        SimpleReqRewriter, rgx)
-
-    class BlogReqRewriter(SimpleReqRewriter):
-        rules = [
-            (rgx('/blogentry/([a-z_]+)\.rss'),
-             dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
-                       'X creation_date CD, X created_by U, '
-                       'U login "%(user)s"'
-                       % {'user': r'\1'}, vid='rss'))),
-            ]
-
-When a url matches the regular expression, the view with the __regid__
-`rss` which match the result set is displayed.
-
-Here is an example of ``SchemaBasedRewriter`` usage:
-
-.. sourcecode:: python
-
-    from cubicweb.web.views.urlrewrite import (
-        SchemaBasedRewriter, rgx, build_rset)
-
-    class TrackerURLRewriter(SchemaBasedRewriter):
-        rules = [
-            (rgx('/project/([^/]+)/([^/]+)/tests'),
-             build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
-                        rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
-            ]
--- a/doc/book/en/development/devweb/views/views.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-
-.. _Views:
-
-Principles
-----------
-
-We'll start with a description of the interface providing a basic
-understanding of the available classes and methods, then detail the
-view selection principle.
-
-A `View` is an object responsible for the rendering of data from the
-model into an end-user consummable form. They typically churn out an
-XHTML stream, but there are views concerned with email other non-html
-outputs.
-
-.. _views_base_class:
-
-Discovering possible views
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is possible to configure the web user interface to have a left box
-showing all the views than can be applied to the current result set.
-
-To enable this, click on your login at the top right corner. Chose
-"user preferences", then "boxes", then "possible views box" and check
-"visible = yes" before validating your changes.
-
-The views listed there we either not selected because of a lower
-score, or they were deliberately excluded by the main template logic.
-
-
-Basic class for views
-~~~~~~~~~~~~~~~~~~~~~
-
-Class `View` (`cubicweb.view`)
-```````````````````````````````
-
-This class is an abstraction of a view class, used as a base class for
-every renderable object such as views, templates and other user
-interface components.
-
-A `View` is instantiated to render a result set or part of a result
-set. `View` subclasses may be parametrized using the following class
-attributes:
-
-* `templatable` indicates if the view may be embedded in a main
-  template or if it has to be rendered standalone (i.e. pure XML views
-  must not be embedded in the main template of HTML pages)
-
-* if the view is not templatable, it should set the `content_type`
-  class attribute to the correct MIME type (text/xhtml being the
-  default)
-
-* the `category` attribute may be used in the interface to regroup
-  related view kinds together
-
-A view writes to its output stream thanks to its attribute `w` (the
-append method of an `UStreamIO`, except for binary views).
-
-At instantiation time, the standard `_cw` and `cw_rset` attributes are
-added and the `w` attribute will be set at rendering time.
-
-The basic interface for views is as follows (remember that the result
-set has a tabular structure with rows and columns, hence cells):
-
-* `render(**context)`, render the view by calling `call` or
-  `cell_call` depending on the context
-
-* `call(**kwargs)`, call the view for a complete result set or null
-  (the default implementation calls `cell_call()` on each cell of the
-  result set)
-
-* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
-  result set (`row` and `col` being integers used to access the cell)
-
-* `url()`, returns the URL enabling us to get the view with the current
-  result set
-
-* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of
-  identifier `__vid` on the given result set. It is possible to give a
-  fallback view identifier that will be used if the requested view is
-  not applicable to the result set.
-
-* `html_headers()`, returns a list of HTML headers to be set by the
-  main template
-
-* `page_title()`, returns the title to use in the HTML header `title`
-
-Other basic view classes
-````````````````````````
-Here are some of the subclasses of `View` defined in `cubicweb.common.view`
-that are more concrete as they relate to data rendering within the application:
-
-* `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
-* `StartupView`, start view that does not require a result set to apply to
-* `AnyRsetView`, view applicable to any result set
-
-Examples of views class
-```````````````````````
-
-- Using `templatable`, `content_type` and HTTP cache configuration
-
-.. sourcecode:: python
-
-    class RSSView(XMLView):
-        __regid__ = 'rss'
-        title = _('rss')
-        templatable = False
-        content_type = 'text/xml'
-        http_cache_manager = MaxAgeHTTPCacheManager
-        cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
-
-
-- Using a custom selector
-
-.. sourcecode:: python
-
-    class SearchForAssociationView(EntityView):
-        """view called by the edition view when the user asks
-        to search for something to link to the edited eid
-        """
-        __regid__ = 'search-associate'
-        title = _('search for association')
-        __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
-
-
-XML views, binaries views...
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-For views generating other formats than HTML (an image generated dynamically
-for example), and which can not simply be included in the HTML page generated
-by the main template (see above), you have to:
-
-* set the attribute `templatable` of the class to `False`
-* set, through the attribute `content_type` of the class, the MIME
-  type generated by the view to `application/octet-stream` or any
-  relevant and more specialised mime type
-
-For views dedicated to binary content creation (like dynamically generated
-images), we have to set the attribute `binary` of the class to `True` (which
-implies that `templatable == False`, so that the attribute `w` of the view could be
-replaced by a binary flow instead of unicode).
--- a/doc/book/en/development/devweb/views/wdoc.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Online documentation system
----------------------------
-
-(:mod:`cubicweb.web.views.wdoc`)
-
-XXX  describe the on-line documentation system
-
--- a/doc/book/en/development/devweb/views/xmlrss.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-.. _XmlAndRss:
-
-XML and RSS views
------------------
-
-(:mod:`cubicweb.web.views.xmlrss`)
-
-Overview
-+++++++++
-
-*rss*
-    Creates a RSS/XML view and call the view `rssitem` for each entity of
-    the result set.
-
-*rssitem*
-    Create a RSS/XML view for each entity based on the results of the dublin core
-    methods of the entity (`dc_*`)
-
-RSS Channel Example
-++++++++++++++++++++
-
-Assuming you have several blog entries, click on the title of the
-search box in the left column. A larger search box should appear. Enter::
-
-   Any X ORDERBY D WHERE X is BlogEntry, X creation_date D
-
-and you get a list of blog entries.
-
-Click on your login at the top right corner. Chose "user preferences",
-then "boxes", then "possible views box" and check "visible = yes"
-before validating your changes.
-
-Enter the same query in the search box and you will see the same list,
-plus a box titled "possible views" in the left column. Click on
-"entityview", then "RSS".
-
-You just applied the "RSS" view to the RQL selection you requested.
-
-That's it, you have a RSS channel for your blog.
-
-Try again with::
-
-    Any X ORDERBY D WHERE X is BlogEntry, X creation_date D,
-    X entry_of B, B title "MyLife"
-
-Another RSS channel, but a bit more focused.
-
-A last one for the road::
-
-    Any C ORDERBY D WHERE C is Comment, C creation_date D LIMIT 15
-
-displayed with the RSS view, that's a channel for the last fifteen
-comments posted.
-
-[WRITE ME]
-
-* show that the RSS view can be used to display an ordered selection
-  of blog entries, thus providing a RSS channel
-
-* show that a different selection (by category) means a different channel
--- a/doc/book/en/development/entityclasses/application-logic.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-How to use entities objects
----------------------------
-
-The previous chapters detailed the classes and methods available to
-the developper at the so-called `ORM`_ level. However they say little
-about the common patterns of usage of these objects.
-
-.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
-
-Entities objects are used in the repository and web sides of
-CubicWeb. On the repository side of things, one should manipulate them
-in Hooks and Operations.
-
-Hooks and Operations provide support for the implementation of rules
-such as computed attributes, coherency invariants, etc (they play the
-same role as database triggers, but in a way that is independant of
-the actual data sources).
-
-So a lot of an application's business rules will be written in Hooks
-(or Operations).
-
-On the web side, views also typically operate using entity
-objects. Obvious entity methods for use in views are the dublin code
-method like dc_title, etc. For separation of concerns reasons, one
-should ensure no ui logic pervades the entities level, and also no
-business logic should creep into the views.
-
-In the duration of a transaction, entities objects can be instantiated
-many times, in views and hooks, even for the same database entity. For
-instance, in a classic CubicWeb deployment setup, the repository and
-the web frontend are separated process communicating over the
-wire. There is no way state can be shared between these processes
-(there is a specific API for that). Hence, it is not possible to use
-entity objects as messengers between these components of an
-application. It means that an attribute set as in `obj.x = 42`,
-whether or not x is actually an entity schema attribute, has a short
-life span, limited to the hook, operation or view within which the
-object was built.
-
-Setting an attribute or relation value can be done in the context of a
-Hook/Operation, using the obj.set_attributes(x=42) notation or a plain
-RQL SET expression.
-
-In views, it would be preferable to encapsulate the necessary logic in
-a method of the concerned entity class(es). But of course, this advice
-is also reasonnable for Hooks/Operations, though the separation of
-concerns here is less stringent than in the case of views.
-
-This leads to the practical role of entity objects: it's where an
-important part of the application logic lie (the other part being
-located in the Hook/Operations).
-
-Anatomy of an entity class
---------------------------
-
-We can look now at a real life example coming from the `tracker`_
-cube. Let us begin to study the entities/project.py content.
-
-.. sourcecode:: python
-
-    class Project(TreeMixIn, AnyEntity):
-        __regid__ = 'Project'
-        __implements__ = AnyEntity.__implements__ + (ITree,)
-        fetch_attrs, fetch_order = fetch_config(('name', 'description',
-                                                 'description_format', 'summary'))
-
-        TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")'
-
-        tree_attribute = 'subproject_of'
-        parent_target = 'subject'
-        children_target = 'object'
-
-        def dc_title(self):
-            return self.name
-
-First we see that it uses an ITree interface and the TreeMixIn default
-implementation. The attributes `tree_attribute`, `parent_target` and
-`children_target` are used by the TreeMixIn code. This is typically
-used in views concerned with the representation of tree-like
-structures (CubicWeb provides several such views).
-
-It is important that the views themselves try not to implement this
-logic, not only because such views would be hardly applyable to other
-tree-like relations, but also because it is perfectly fine and useful
-to use such an interface in Hooks.
-
-In fact, Tree nature is a property of the data model that cannot be
-fully and portably expressed at the level of database entities (think
-about the transitive closure of the child relation). This is a further
-argument to implement it at entity class level.
-
-The `dc_title` method provides a (unicode string) value likely to be
-consummed by views, but note that here we do not care about output
-encodings. We care about providing data in the most universal format
-possible, because the data could be used by a web view (which would be
-responsible of ensuring XHTML compliance), or a console or file
-oriented output (which would have the necessary context about the
-needed byte stream encoding).
-
-The fetch_attrs, fetch_order class attributes are parameters of the
-`ORM`_ layer. They tell which attributes should be loaded at once on
-entity object instantiation (by default, only the eid is known, other
-attributes are loaded on demand), and which attribute is to be used to
-order the .related() and .unrelated() methods output.
-
-Finally, we can observe the big TICKET_DEFAULT_STATE_RESTR is a pure
-application domain piece of data. There is, of course, no limitation
-to the amount of class attributes of this kind.
-
-Let us now dig into more substantial pieces of code.
-
-.. sourcecode:: python
-
-    def latest_version(self, states=('published',), reverse=None):
-        """returns the latest version(s) for the project in one of the given
-        states.
-
-        when no states specified, returns the latest published version.
-        """
-        order = 'DESC'
-        if reverse is not None:
-            warn('reverse argument is deprecated',
-                 DeprecationWarning, stacklevel=1)
-            if reverse:
-                order = 'ASC'
-        rset = self.versions_in_state(states, order, True)
-        if rset:
-            return rset.get_entity(0, 0)
-        return None
-
-    def versions_in_state(self, states, order='ASC', limit=False):
-        """returns version(s) for the project in one of the given states, sorted
-        by version number.
-
-        If limit is true, limit result to one version.
-        If reverse, versions are returned from the smallest to the greatest.
-        """
-        if limit:
-            order += ' LIMIT 1'
-        rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \
-              'WHERE V num N, V in_state S, S name IN (%s), ' \
-              'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states))
-        return self._cw.execute(rql, {'p': self.eid})
-
-.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/
-
-These few lines exhibit the important properties we want to outline:
-
-* entity code is concerned with the application domain
-
-* it is NOT concerned with database coherency (this is the realm of
-  Hooks/Operations); in other words, it assumes a coherent world
-
-* it is NOT concerned with end-user interfaces
-
-* however it can be used in both contexts
-
-* it does not create or manipulate the internal object's state
-
-* it plays freely with RQL expression as needed
-
-* it is not concerned with internationalization
-
-* it does not raise exceptions
-
-
--- a/doc/book/en/development/entityclasses/data-as-objects.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-Access to persistent data
---------------------------
-
-Python-level access to persistent data is provided by the
-:class:`Entity <cubicweb.entity>` class.
-
-An entity class is bound to a schema entity type.  Descriptors are added when
-classes are registered in order to initialize the class according to its schema:
-
-* we can access the defined attributes in the schema thanks to the attributes of
-  the same name on instances (typed value)
-
-* we can access the defined relations in the schema thanks to the relations of
-  the same name on instances (entities instances list)
-
-
-:Formatting and output generation:
-
-  * `view(__vid, __registry='views', **kwargs)`, applies the given view to the entity
-    (and returns an unicode string)
-
-  * `absolute_url(*args, **kwargs)`, returns an absolute URL to access the primary view
-    of an entity
-
-  * `rest_path()`, returns a relative REST URL to get the entity
-
-  * `printable_value(attr, value=_marker, attrtype=None, format='text/html', displaytime=True)`,
-    returns a string enabling the display of an attribute value in a given format
-    (the value is automatically recovered if necessary)
-
-:Data handling:
-
-  * `as_rset()`, converts the entity into an equivalent result set simulating the
-     request `Any X WHERE X eid _eid_`
-
-  * `complete(skip_bytes=True)`, executes a request that recovers at
-    once all the missing attributes of an entity
-
-  * `get_value(name)`, returns the value associated to the attribute name given
-    in parameter
-
-  * `related(rtype, role='subject', limit=None, entities=False)`,
-    returns a list of entities related to the current entity by the
-    relation given in parameter
-
-  * `unrelated(rtype, targettype, role='subject', limit=None)`,
-    returns a result set corresponding to the entities not (yet)
-    related to the current entity by the relation given in parameter
-    and satisfying its constraints
-
-  * `set_attributes(**kwargs)`, updates the attributes list with the corresponding
-    values given named parameters
-
-  * `set_relations(**kwargs)`, add relations to the given object. To
-     set a relation where this entity is the object of the relation,
-     use `reverse_<relation>` as argument name.  Values may be an
-     entity, a list of entities, or None (meaning that all relations of
-     the given type from or to this object should be deleted).
-
-  * `copy_relations(ceid)`, copies the relations of the entities having the eid
-    given in the parameters on the current entity
-
-  * `delete()` allows to delete the entity
-
-
-The :class:`AnyEntity` class
-----------------------------
-
-To provide a specific behavior for each entity, we have to define a class
-inheriting from `cubicweb.entities.AnyEntity`. In general, we define this class
-in `mycube.entities` module (or in a submodule if we want to split code among
-multiple files) so that it will be available on both server and client side.
-
-The class `AnyEntity` is a sub-class of Entity that add methods to it,
-and helps specializing (by further subclassing) the handling of a
-given entity type.
-
-Most methods defined for `AnyEntity`, in addition to `Entity`, add
-support for the `Dublin Core`_ metadata.
-
-.. _`Dublin Core`: http://dublincore.org/
-
-:Standard meta-data (Dublin Core):
-
-  * `dc_title()`, returns a unicode string corresponding to the
-    meta-data `Title` (used by default is the first non-meta attribute
-    of the entity schema)
-
-  * `dc_long_title()`, same as dc_title but can return a more
-    detailed title
-
-  * `dc_description(format='text/plain')`, returns a unicode string
-    corresponding to the meta-data `Description` (looks for a
-    description attribute by default)
-
-  * `dc_authors()`, returns a unicode string corresponding to the meta-data
-    `Authors` (owners by default)
-
-  * `dc_creator()`, returns a unicode string corresponding to the
-    creator of the entity
-
-  * `dc_date(date_format=None)`, returns a unicode string corresponding to
-    the meta-data `Date` (update date by default)
-
-  * `dc_type(form='')`, returns a string to display the entity type by
-    specifying the preferred form (`plural` for a plural form)
-
-  * `dc_language()`, returns the language used by the entity
-
-
-:Misc methods:
-
-  * `after_deletion_path`, return (path, parameters) which should be
-     used as redirect information when this entity is being deleted
-
-  * `pre_web_edit`, callback called by the web editcontroller when an
-    entity will be created/modified, to let a chance to do some entity
-    specific stuff (does nothing by default)
-
-Inheritance
------------
-
-When describing a data model, entities can inherit from other entities as is
-common in object-oriented programming.
-
-You have the possibility to adapt some entity attributes, as follow:
-
-.. sourcecode:: python
-
-    from cubes.OTHER_CUBE import entities
-    class EntityExample(entities.EntityExample):
-        def dc_long_title(self):
-            return '%s (%s)' % (self.name, self.description)
-
-Notice this is different than yams schema inheritance.
-
--- a/doc/book/en/development/entityclasses/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-Data as objects
-===============
-
-In this chapter, we will introduce the objects that are used to handle
-the logic associated to the data stored in the database.
-
-.. toctree::
-   :maxdepth: 1
-
-   data-as-objects
-   load-sort
-   interfaces
-   application-logic
--- a/doc/book/en/development/entityclasses/interfaces.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-Interfaces
-----------
-
-This is the same thing as object-oriented programming `interfaces`_.
-
-.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
-
-Definition of an interface is quite trivial. An example from cubicweb
-itself (found in cubicweb/interfaces.py):
-
-.. sourcecode:: python
-
-    class ITree(Interface):
-
-        def parent(self):
-            """returns the parent entity"""
-
-        def children(self):
-            """returns the item's children"""
-
-        def children_rql(self):
-            """returns RQL to get children"""
-
-        def iterchildren(self):
-            """iterates over the item's children"""
-
-        def is_leaf(self):
-            """returns true if this node as no child"""
-
-        def is_root(self):
-            """returns true if this node has no parent"""
-
-        def root(self):
-            """returns the root object"""
-
-
-Declaration of interfaces implemented by a class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. sourcecode:: python
-
-  from cubicweb.interfaces import ITree
-  from cubicweb.mixins import TreeMixIn
-
-  class MyEntity(TreeMixIn, AnyEntity):
-      __regid__ = 'MyEntity'
-      __implements__ = AnyEntity.__implements__ + ('ITree',)
-
-      tree_attribute = 'filed_under'
-
-The TreeMixIn here provides a default implementation for the
-interface. The tree_attribute class attribute is actually used by this
-implementation to help implement correct behaviour.
-
-Interfaces (and some implementations as mixins) defined in the library
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: cubicweb.interfaces
-   :members:
-
-.. automodule:: cubicweb.mixins
-   :members:
-
-
-
--- a/doc/book/en/development/entityclasses/load-sort.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-
-.. _FetchAttrs:
-
-Loaded attributes and default sorting management
-````````````````````````````````````````````````
-
-* The class attribute `fetch_attrs` allows to define in an entity class a list
-  of names of attributes or relations that should be automatically loaded when
-  entities of this type are fetched from the database. In the case of relations,
-  we are limited to *subject of cardinality `?` or `1`* relations.
-
-* The class method `fetch_order(attr, var)` expects an attribute (or relation)
-  name as a parameter and a variable name, and it should return a string
-  to use in the requirement `ORDERBY` of an RQL query to automatically
-  sort the list of entities of such type according to this attribute, or
-  `None` if we do not want to sort on the attribute given in the parameter.
-  By default, the entities are sorted according to their creation date.
-
-* The class method `fetch_unrelated_order(attr, var)` is similar to
-  the method `fetch_order` except that it is essentially used to
-  control the sorting of drop-down lists enabling relations creation
-  in the editing view of an entity. The default implementation uses
-  the modification date. Here's how to adapt it for one entity (sort
-  on the name attribute): ::
-
-   class MyEntity(AnyEntity):
-       __regid__ = 'MyEntity'
-       fetch_attrs = ('modification_date', 'name')
-
-       @classmethod
-       def fetch_unrelated_order(cls, attr, var):
-           if attr == 'name':
-              return '%s ASC' % var
-           return None
-
-
-The function `fetch_config(fetchattrs, mainattr=None)` simplifies the
-definition of the attributes to load and the sorting by returning a
-list of attributes to pre-load (considering automatically the
-attributes of `AnyEntity`) and a sorting function based on the main
-attribute (the second parameter if specified, otherwise the first
-attribute from the list `fetchattrs`). This function is defined in
-`cubicweb.entities`.
-
-For example: ::
-
-  class Transition(AnyEntity):
-    """..."""
-    __regid__ = 'Transition'
-    fetch_attrs, fetch_order = fetch_config(['name'])
-
-Indicates that for the entity type "Transition", you have to pre-load
-the attribute `name` and sort by default on this attribute.
--- a/doc/book/en/development/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-.. _Part2:
-
------------
-Development
------------
-
-This part is about developing web applications with the *CubicWeb* framework.
-
-.. toctree::
-   :maxdepth: 2
-   :numbered:
-
-   cubes/index
-   vreg.rst
-   datamodel/index
-   entityclasses/index
-   devcore/index
-   devweb/index
-   devrepo/index
-   testing.rst
-   migration.rst
-   profiling.rst
--- a/doc/book/en/development/migration.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _migration:
-
-Migration
-=========
-
-One of the main design goals of *CubicWeb* was to support iterative and agile
-development. For this purpose, multiple actions are provided to facilitate the
-improvement of an instance, and in particular to handle the changes to be
-applied to the data model, without loosing existing data.
-
-The current version of a cube (and of cubicweb itself) is provided in the file
-`__pkginfo__.py` as a tuple of 3 integers.
-
-Migration scripts management
-----------------------------
-
-Migration scripts has to be located in the directory `migration` of your
-cube and named accordingly:
-
-::
-
-  <version n° X.Y.Z>[_<description>]_<mode>.py
-
-in which :
-
-* X.Y.Z is the model version number to which the script enables to migrate.
-
-* *mode* (between the last "_" and the extension ".py") is used for
-  distributed installation. It indicates to which part
-  of the application (RQL server, web server) the script applies.
-  Its value could be :
-
-  * `common`, applies to the RQL server as well as the web server and updates
-    files on the hard drive (configuration files migration for example).
-
-  * `web`, applies only to the web server and updates files on the hard drive.
-
-  * `repository`, applies only to the RQL server and updates files on the
-    hard drive.
-
-  * `Any`, applies only to the RQL server and updates data in the database
-    (schema and data migration for example).
-
-Again in the directory `migration`, the file `depends.map` allows to indicate
-that for the migration to a particular model version, you always have to first
-migrate to a particular *CubicWeb* version. This file can contain comments (lines
-starting by `#`) and a dependancy is listed as follows: ::
-
-  <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
-
-For example: ::
-
-  0.12.0: 2.26.0
-  0.13.0: 2.27.0
-  # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
-  0.15.0: 2.28.0
-
-Base context
-------------
-
-The following identifiers are pre-defined in migration scripts:
-
-* `config`, instance configuration
-
-* `interactive_mode`, boolean indicating that the script is executed in
-  an interactive mode or not
-
-* `versions_map`, dictionary of migrated versions  (key are cubes
-  names, including 'cubicweb', values are (from version, to version)
-
-* `confirm(question)`, function asking the user and returning true
-  if the user answers yes, false otherwise (always returns true in
-  non-interactive mode)
-
-* `_()` is equivalent to `unicode` allowing to flag the strings to
-  internationalize in the migration scripts.
-
-In the `repository` scripts, the following identifiers are also defined:
-
-* `commit(ask_confirm=True)`, request confirming and executing a "commit"
-
-* `schema`, instance schema (readen from the database)
-
-* `fsschema`, installed schema on the file system (e.g. schema of
-  the updated model and cubicweb)
-
-* `repo`, repository object
-
-* `session`, repository session object
-
-
-Schema migration
-----------------
-The following functions for schema migration are available in `repository`
-scripts:
-
-* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
-  attribute to an existing entity type. If the attribute type is not specified,
-  then it is extracted from the updated schema.
-
-* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
-  existing entity type.
-
-* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
-
-* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
-  If `auto` is True, all the relations using this entity type and having a known
-  entity type on the other hand will automatically be added.
-
-* `drop_entity_type(etype, commit=True)`, removes an entity type and all the
-  relations using it.
-
-* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
-
-* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
-  type. If `addrdef` is True, all the relations definitions of this type will
-  be added.
-
-* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
-  definitions of this type.
-
-* `rename_relation(oldname, newname, commit=True)`, renames a relation.
-
-* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
-  relation definition.
-
-* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
-  a relation definition.
-
-* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
-  synchronizes properties and/or permissions on:
-  - the whole schema if ertype is None
-  - an entity or relation type schema if ertype is a string
-  - a relation definition  if ertype is a 3-uple (subject, relation, object)
-
-* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
-  properties of a relation definition by using the named parameters of the properties
-  to change.
-
-* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
-  relation <rtype> of entity type <etype>.
-
-* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
-  for the relation <rtype> of entity type <etype>.
-
-Data migration
---------------
-The following functions for data migration are available in `repository` scripts:
-
-* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
-  query, either to interrogate or update. A result set object is returned.
-
-* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given
-  type. The attribute and relation values are specified using the named and
-  positionned parameters.
-
-Workflow creation
------------------
-
-The following functions for workflow creation are available in `repository`
-scripts:
-
-* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
-  for a given type(s)
-
-You can find more details about workflows in the chapter :ref:`Workflow` .
-
-Configuration migration
------------------------
-
-The following functions for configuration migration are available in all
-scripts:
-
-* `option_renamed(oldname, newname)`, indicates that an option has been renamed
-
-* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
-  belong anymore to the same group.
-
-* `option_added(oldname, newname)`, indicates that an option has been added.
-
-* `option_removed(oldname, newname)`, indicates that an option has been deleted.
-
-
-Others migration functions
---------------------------
-Those functions are only used for low level operations that could not be
-accomplished otherwise or to repair damaged databases during interactive
-session. They are available in `repository` scripts:
-
-* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
-* `add_entity_type_table(etype, commit=True)`
-* `add_relation_type_table(rtype, commit=True)`
-* `uninline_relation(rtype, commit=True)`
-
-
-[FIXME] Add explanation on how to use cubicweb-ctl shell
--- a/doc/book/en/development/profiling.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-Profiling and performance
-=========================
-
-If you feel that one of your pages takes more time than it should to be
-generated, chances are that you're making too many RQL queries.  Obviously,
-there are other reasons but experience tends to show this is the first thing to
-track down. Luckily, CubicWeb provides a configuration option to log RQL
-queries. In your ``all-in-one.conf`` file, set the **query-log-file** option::
-
-    # web application query log file
-    query-log-file=~/myapp-rql.log
-
-Then restart your application, reload your page and stop your application.
-The file ``myapp-rql.log`` now contains the list of RQL queries that were
-executed during your test. It's a simple text file containing lines such as::
-
-    Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec)
-    Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec)
-
-The structure of each line is::
-
-    <RQL QUERY> <QUERY ARGS IF ANY> -- <TIME SPENT>
-
-CubicWeb also provides the **exlog** command to examine and summarize data found
-in such a file:
-
-.. sourcecode:: sh
-
-    $ cubicweb-ctl exlog < ~/myapp-rql.log
-    0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
-    0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
-    0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
-    0.01 1 Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s {, }
-    0.01 1 Any B,T,P ORDERBY lower(T) WHERE B is Bookmark,B title T, B path P, B bookmarked_by U, U eid %(x)s {}
-    0.01 1 Any A,B,C,D WHERE A eid %(x)s,A name B,A creation_date C,A modification_date D {}
-
-This command sorts and uniquifies queries so that it's easy to see where
-is the hot spot that needs optimization.
-
-Do not neglect to set the **fetch_attrs** attribute you can define in your
-entity classes because it can greatly reduce the number of queries executed (see
-:ref:`FetchAttrs`).
-
-You should also know about the **profile** option in the ``all-in-on.conf``. If
-set, this option will make your application run in an `hotshot`_ session and
-store the results in the specified file.
-
-.. _hotshot: http://docs.python.org/library/hotshot.html#module-hotshot
-
-Last but no least, if you're using the PostgreSQL database backend, VACUUMing
-your database can significantly improve the performance of the queries (by
-updating the statistics used by the query optimizer). Nowadays, this is done
-automatically from time to time, but if you've just imported a large amount of
-data in your db, you will want to vacuum it (with the analyse option on). Read
-the documentation of your database for more information.
--- a/doc/book/en/development/testing.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tests
-=====
-
-Unit tests
-----------
-
-The *CubicWeb* framework provides the `CubicWebTC` test base class in
-the module `cubicweb.devtools.testlib`.
-
-Tests shall be put into the mycube/test directory. Additional test
-data shall go into mycube/test/data.
-
-It is much advised to write tests concerning entities methods, hooks
-and operations, security. The CubicWebTC base class has convenience
-methods to help test all of this.
-
-.. note::
-
-  In the realm of views, there is not much to do but check that the
-  views are valid XHTML.  See :ref:`automatic_views_tests` for
-  details. Integration of CubicWeb tests with UI testing tools such as
-  `selenium`_ are currently under invesitgation.
-
-.. _selenium: http://seleniumhq.org/projects/ide/
-
-Most unit tests need a live database to work against. This is achieved
-by CubicWeb using automatically sqlite (bundled with Python, see
-http://docs.python.org/library/sqlite3.html) as a backend.
-
-The database is stored in the mycube/test/tmpdb,
-mycube/test/tmpdb-template files. If it does not (yet) exists, it will
-be built automatically when the test suit starts.
-
-.. warning::
-
-  Whenever the schema changes (new entities, attributes, relations)
-  one must delete these two files. Changes concerned only with entity
-  or relation type properties (constraints, cardinalities,
-  permissions) and generally dealt with using the
-  `sync_schema_props_perms()` fonction of the migration environment
-  need not a database regeneration step.
-
-Unit test by example
-````````````````````
-
-We start with an example extracted from the keyword cube (available
-from http://www.cubicweb.org/project/cubicweb-keyword).
-
-.. sourcecode:: python
-
-    from cubicweb.devtools.testlib import CubicWebTC
-    from cubicweb import ValidationError
-
-    class ClassificationHooksTC(CubicWebTC):
-
-        def setup_database(self):
-            req = self.request()
-            group_etype = req.execute('Any X WHERE X name "CWGroup"').get_entity(0,0)
-            c1 = req.create_entity('Classification', name=u'classif1',
-                                   classifies=group_etype)
-            user_etype = req.execute('Any X WHERE X name "CWUser"').get_entity(0,0)
-            c2 = req.create_entity('Classification', name=u'classif2',
-                                   classifies=user_etype)
-            self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1)
-            self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2)
-
-        def test_cannot_create_cycles(self):
-            # direct obvious cycle
-            self.assertRaises(ValidationError, self.kw1.set_relations,
-                              subkeyword_of=self.kw1)
-            # testing indirect cycles
-            kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
-                               'SK subkeyword_of K WHERE C name "classif1", K eid %s'
-                               % self.kw1.eid).get_entity(0,0)
-            self.kw1.set_relations(subkeyword_of=kw3)
-            self.assertRaises(ValidationError, self.commit)
-
-The test class defines a `setup_database` method which populates the
-database with initial data. Each test of the class runs with this
-pre-populated database.
-
-The test case itself checks that an Operation does it job of
-preventing cycles amongst Keyword entities.
-
-You can see an example of security tests in the
-:ref:`adv_tuto_security`.
-
-It is possible to have these tests run continuously using `apycot`_.
-
-.. _apycot: http://www.logilab.org/project/apycot
-
-Managing connections or users
-+++++++++++++++++++++++++++++
-
-Since unit tests are done with the SQLITE backend and this does not
-support multiple connections at a time, you must be careful when
-simulating security, changing users.
-
-By default, tests run with a user with admin privileges. This
-user/connection must never be closed.
-
-Before a self.login, one has to release the connection pool in use
-with a self.commit, self.rollback or self.close.
-
-The `login` method returns a connection object that can be used as a
-context manager:
-
-.. sourcecode:: python
-
-   with self.login('user1') as user:
-       req = user.req
-       req.execute(...)
-
-On exit of the context manager, either a commit or rollback is issued,
-which releases the connection.
-
-When one is logged in as a normal user and wants to switch back to the
-admin user without committing, one has to use
-self.restore_connection().
-
-Usage with restore_connection:
-
-.. sourcecode:: python
-
-    # execute using default admin connection
-    self.execute(...)
-    # I want to login with another user, ensure to free admin connection pool
-    # (could have used rollback but not close here
-    # we should never close defaut admin connection)
-    self.commit()
-    cnx = self.login('user')
-    # execute using user connection
-    self.execute(...)
-    # I want to login with another user or with admin user
-    self.commit();  cnx.close()
-    # restore admin connection, never use cnx = self.login('admin'), it will return
-    # the default admin connection and one may be tempted to close it
-    self.restore_connection()
-
-.. warning::
-
-   Do not use the references kept to the entities created with a
-   connection from another !
-
-Email notifications tests
--------------------------
-
-When running tests potentially generated e-mails are not really sent
-but is found in the list `MAILBOX` of module
-`cubicweb.devtools.testlib`.
-
-You can test your notifications by analyzing the contents of this list, which
-contains objects with two attributes:
-
-* `recipients`, the list of recipients
-* `msg`, object email.Message
-
-Let us look at simple example from the ``blog`` cube.
-
-.. sourcecode:: python
-
-    from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
-
-    class BlogTestsCubicWebTC(CubicWebTC):
-        """test blog specific behaviours"""
-
-        def test_notifications(self):
-            req = self.request()
-            cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
-                                description=u'cubicweb is beautiful')
-            blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
-                                             content=u'cubicweb hop')
-            blog_entry_1.set_relations(entry_of=cubicweb_blog)
-            blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
-                                             content=u'cubicweb yes')
-            blog_entry_2.set_relations(entry_of=cubicweb_blog)
-            self.assertEquals(len(MAILBOX), 0)
-            self.commit()
-            self.assertEquals(len(MAILBOX), 2)
-            mail = MAILBOX[0]
-            self.assertEquals(mail.subject, '[data] hop')
-            mail = MAILBOX[1]
-            self.assertEquals(mail.subject, '[data] yes')
-
-.. _automatic_views_tests:
-
-Automatic views testing
------------------------
-
-This is done automatically with the AutomaticWebTest class. At cube
-creation time, the mycube/test/test_mycube.py file contains such a
-test. The code here has to be uncommented to be usable, without
-further modification.
-
-The ``auto_populate`` method uses a smart algorithm to create
-pseudo-random data in the database, thus enabling the views to be
-invoked and tested.
-
-Depending on the schema, hooks and operations constraints, it is not
-always possible for the automatic auto_populate to proceed.
-
-It is possible of course to completely redefine auto_populate. A
-lighter solution is to give hints (fill some class attributes) about
-what entities and relations have to be skipped by the auto_populate
-mechanism. These are:
-
-* `no_auto_populate`, may contain a list of entity types to skip
-* `ignored_relations`, may contain a list of relation types to skip
-* `application_rql`, may contain a list of rql expressions that
-  auto_populate cannot guess by itself; these must yield resultsets
-  against which views may be selected.
-
-
-Test APIS
----------
-
-Using Pytest
-````````````
-
-The `pytest` utility (shipping with `logilab-common`_, which is a
-mandatory dependency of CubicWeb) extends the Python unittest
-functionality and is the preferred way to run the CubicWeb test
-suites. Bare unittests also work the usual way.
-
-.. _logilab-common: http://www.logilab.org/project/logilab-common
-
-To use it, you may:
-
-* just launch `pytest` in your cube to execute all tests (it will
-  discover them automatically)
-* launch `pytest unittest_foo.py` to execute one test file
-* launch `pytest unittest_foo.py bar` to execute all test methods and
-  all test cases whose name contain `bar`
-
-Additionally, the `-x` option tells pytest to exit at the first error
-or failure. The `-i` option tells pytest to drop into pdb whenever an
-exception occurs in a test.
-
-When the `-x` option has been used and the run stopped on a test, it
-is possible, after having fixed the test, to relaunch pytest with the
-`-R` option to tell it to start testing again from where it previously
-failed.
-
-Using the `TestCase` base class
-```````````````````````````````
-
-The base class of CubicWebTC is logilab.common.testlib.TestCase, which
-provides a lot of convenient assertion methods.
-
-.. autoclass:: logilab.common.testlib.TestCase
-   :members:
-
-CubicWebTC API
-``````````````
-.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
-   :members:
--- a/doc/book/en/development/vreg.rst	Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-The VRegistry, selectors and application objects
-================================================
-
-This chapter talks about core concepts of the |cubicweb| framework,
-that make it different from other frameworks (and maybe not easy to
-grasp at a first glance). To be able to do advanced development with
-|cubicweb| you need a good understanding of what is explained below.
-
-This chapter goes deep into details. You don't have to remember them
-all but keep it in mind so you can go back there later.
-
-An overview of AppObjects, the VRegistry and Selectors is given in the
-:ref:`VRegistryIntro` chapter.
-
-.. autodocstring:: cubicweb.cwvreg
-.. autodocstring:: cubicweb.selectors
-.. automodule:: cubicweb.appobject
-
-Base selectors
---------------
-
-Selectors are scoring functions that are called by the registry to tell whenever
-an appobject can be selected in a given context. Selector sets are for instance
-the glue that tie views to the data model. Using them appropriately is an
-essential part of the construction of well behaved cubes.
-
-Of course you may have to write your own set of selectors as your needs grows and
-you get familiar with the framework (see :ref:`CustomSelectors`).
-
-Here is a description of generic selectors provided by CubicWeb that should suit
-most of your needs.
-
-Bare selectors
-~~~~~~~~~~~~~~
-Those selectors are somewhat dumb, which doesn't mean they're not (very) useful.
-
-.. autoclass:: cubicweb.appobject.yes
-.. autoclass:: cubicweb.selectors.match_kwargs
-.. autoclass:: cubicweb.selectors.appobject_selectable
-
-
-Result set selectors
-~~~~~~~~~~~~~~~~~~~~~
-Those selectors are looking for a result set in the context ('rset' argument or
-the input context) and match or not according to its shape. Some of these
-selectors have different behaviour if a particular cell of the result set is
-specified using 'row' and 'col' arguments of the input context or not.
-
-.. autoclass:: cubicweb.selectors.none_rset
-.. autoclass:: cubicweb.selectors.any_rset
-.. autoclass:: cubicweb.selectors.nonempty_rset
-.. autoclass:: cubicweb.selectors.empty_rset
-.. autoclass:: cubicweb.selectors.one_line_rset
-.. autoclass:: cubicweb.selectors.multi_lines_rset
-.. autoclass:: cubicweb.selectors.multi_columns_rset
-.. autoclass:: cubicweb.selectors.paginated_rset
-.. autoclass:: cubicweb.selectors.sorted_rset
-.. autoclass:: cubicweb.selectors.one_etype_rset
-.. autoclass:: cubicweb.selectors.multi_etypes_rset
-
-
-Entity selectors
-~~~~~~~~~~~~~~~~
-Those selectors are looking for either an `entity` argument in the input context,
-or entity found in the result set ('rset' argument or the input context) and
-match or not according to entity's (instance or class) properties.
-
-.. autoclass:: cubicweb.selectors.non_final_entity
-.. autoclass:: cubicweb.selectors.implements
-.. autoclass:: cubicweb.selectors.score_entity
-.. autoclass:: cubicweb.selectors.rql_condition
-.. autoclass:: cubicweb.selectors.relation_possible
-.. autoclass:: cubicweb.selectors.partial_relation_possible
-.. autoclass:: cubicweb.selectors.has_related_entities
-.. autoclass:: cubicweb.selectors.partial_has_related_entities
-.. autoclass:: cubicweb.selectors.has_permission
-.. autoclass:: cubicweb.selectors.has_add_permission
-
-
-Logged user selectors
-~~~~~~~~~~~~~~~~~~~~~
-Those selectors are looking for properties of the user issuing the request.
-
-.. autoclass:: cubicweb.selectors.anonymous_user
-.. autoclass:: cubicweb.selectors.authenticated_user
-.. autoclass:: cubicweb.selectors.match_user_groups
-
-
-Web request selectors
-~~~~~~~~~~~~~~~~~~~~~
-Those selectors are looking for properties of *web* request, they can not be
-used on the data repository side.
-
-.. autoclass:: cubicweb.selectors.match_form_params
-.. autoclass:: cubicweb.selectors.match_search_state
-.. autoclass:: cubicweb.selectors.match_context_prop
-.. autoclass:: cubicweb.selectors.match_view
-.. autoclass:: cubicweb.selectors.primary_view
-.. autoclass:: cubicweb.selectors.specified_etype_implements
-
-
-Other selectors
-~~~~~~~~~~~~~~~
-.. autoclass:: cubicweb.selectors.match_transition
-
-You'll also find some other (very) specific selectors hidden in other modules
-than :mod:`cubicweb.selectors`.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/available-cubes.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,64 @@
+
+Available cubes
+---------------
+
+An instance is based on several basic cubes. In the set of available
+basic cubes we can find for example :
+
+Base entity types
+~~~~~~~~~~~~~~~~~
+* addressbook_: PhoneNumber and PostalAddress
+* card_: Card, generic documenting card
+* event_: Event (define events, display them in calendars)
+* file_: File (to allow users to upload and store binary or text files)
+* link_: Link (to collect links to web resources)
+* mailinglist_: MailingList (to reference a mailing-list and the URLs
+  for its archives and its admin interface)
+* person_: Person (easily mixed with addressbook)
+* task_: Task (something to be done between start and stop date)
+* zone_: Zone (to define places within larger places, for example a
+  city in a state in a country)
+
+
+Classification
+~~~~~~~~~~~~~~
+* folder_: Folder (to organize things but grouping them in folders)
+* keyword_: Keyword (to define classification schemes)
+* tag_: Tag (to tag anything)
+
+Other features
+~~~~~~~~~~~~~~
+* basket_: Basket (like a shopping cart)
+* blog_: a blogging system uxing Blog and BlogEntry entity types
+* comment_: system to attach comment threads to entities)
+* email_: archiving management for emails (`Email`, `Emailpart`,
+  `Emailthread`), trigger action in cubicweb through email
+
+
+
+
+
+.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
+.. _basket: http://www.cubicweb.org/project/cubicweb-basket
+.. _card: http://www.cubicweb.org/project/cubicweb-card
+.. _blog: http://www.cubicweb.org/project/cubicweb-blog
+.. _comment: http://www.cubicweb.org/project/cubicweb-comment
+.. _email: http://www.cubicweb.org/project/cubicweb-email
+.. _event: http://www.cubicweb.org/project/cubicweb-event
+.. _file: http://www.cubicweb.org/project/cubicweb-file
+.. _folder: http://www.cubicweb.org/project/cubicweb-folder
+.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
+.. _link: http://www.cubicweb.org/project/cubicweb-link
+.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
+.. _person: http://www.cubicweb.org/project/cubicweb-person
+.. _tag: http://www.cubicweb.org/project/cubicweb-tag
+.. _task: http://www.cubicweb.org/project/cubicweb-task
+.. _zone: http://www.cubicweb.org/project/cubicweb-zone
+
+To declare the use of a component, once installed, add the name of the component
+to the variable `__use__` in the file `__pkginfo__.py` of your own component.
+
+.. note::
+  The listed cubes above are available as debian-packages on `CubicWeb's forge`_.
+
+.. _`CubicWeb's forge`: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/cc-newcube.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,50 @@
+Creating a new cube from scratch using :command:`cubicweb-ctl newcube`
+----------------------------------------------------------------------
+
+Let's start by creating the cube environment in which we will develop ::
+
+  cd ~/cubes
+  # use cubicweb-ctl to generate a template for the cube
+  # will ask some questions, most with nice default
+  cubicweb-ctl newcube mycube
+  # makes the cube source code managed by mercurial
+  cd mycube
+  hg init
+  hg add .
+  hg ci
+
+If all went well, you should see the cube you just created in the list
+returned by ``cubicweb-ctl list`` in the section *Available cubes*,
+and if it is not the case please refer to :ref:`ConfigurationEnv`.
+
+To reuse an existing cube, add it to the list named
+``__depends_cubes__`` and defined in :file:`__pkginfo__.py`.  This
+variable is used for the instance packaging (dependencies handled by
+system utility tools such as APT) and the usable cubes at the time the
+base is created (import_erschema('MyCube') will not properly work
+otherwise).
+
+.. note::
+
+    Please note that if you do not wish to use default directory for your cubes
+    library, you should set the :envvar:`CW_CUBES_PATH` environment variable to
+    add extra directories where cubes will be search, and you'll then have to use
+    the option `--directory` to specify where you would like to place the source
+    code of your cube:
+
+    ``cubicweb-ctl newcube --directory=/path/to/cubes/library mycube``
+
+
+.. XXX resurrect once live-server is back
+.. Usage of :command:`cubicweb-ctl liveserver`
+.. -------------------------------------------
+
+.. To quickly test a new cube, you can also use the `liveserver` command for cubicweb-ctl
+.. which allows to create an instance in memory (using an SQLite database by
+.. default) and make it accessible through a web server ::
+
+..   cubicweb-ctl live-server mycube
+
+.. or by using an existing database (SQLite or Postgres)::
+
+..   cubicweb-ctl live-server -s myfile_sources mycube
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,11 @@
+Cubes
+=====
+
+This chapter describes how to define your own cubes and reuse already available cubes.
+
+.. toctree::
+   :maxdepth: 1
+
+   layout.rst
+   cc-newcube.rst
+   available-cubes.rst
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/layout.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,134 @@
+
+.. _foundationsCube:
+
+.. _cubelayout:
+
+Standard structure for a cube
+-----------------------------
+
+A cube is structured as follows:
+
+::
+
+  mycube/
+  |
+  |-- data/
+  |   |-- cubes.mycube.css
+  |   |-- cubes.mycube.js
+  |   `-- external_resources
+  |
+  |-- debian/
+  |   |-- changelog
+  |   |-- compat
+  |   |-- control
+  |   |-- copyright
+  |   |-- cubicweb-mycube.prerm
+  |   `-- rules
+  |
+  |-- entities.py
+  |
+  |-- i18n/
+  |   |-- en.po
+  |   |-- es.po
+  |   `-- fr.po
+  |
+  |-- __init__.py
+  |
+  |-- MANIFEST.in
+  |
+  |-- migration/
+  |   |-- postcreate.py
+  |   `-- precreate.py
+  |
+  |-- __pkginfo__.py
+  |
+  |-- schema.py
+  |
+  |-- setup.py
+  |
+  |-- site_cubicweb.py
+  |
+  |-- hooks.py
+  |
+  |-- test/
+  |   |-- data/
+  |   |   `-- bootstrap_cubes
+  |   |-- pytestconf.py
+  |   |-- realdb_test_mycube.py
+  |   `-- test_mycube.py
+  |
+  `-- views.py
+
+
+We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
+``schema.py`` or ``hooks.py``. For example, we could have:
+
+::
+
+  mycube/
+  |
+  |-- entities.py
+  |-- hooks.py
+  `-- views/
+      |-- forms.py
+      |-- primary.py
+      `-- widgets.py
+
+
+where :
+
+* ``schema`` contains the schema definition (server side only)
+* ``entities`` contains the entities definition (server side and web interface)
+* ``hooks`` contains hooks and/or views notifications (server side only)
+* ``views`` contains the web interface components (web interface only)
+* ``test`` contains tests related to the cube (not installed)
+* ``i18n`` contains message catalogs for supported languages (server side and
+  web interface)
+* ``data`` contains data files for static content (images, css, javascripts)
+  ...(web interface only)
+* ``migration`` contains initialization files for new instances (``postcreate.py``)
+  and a file containing dependencies of the component depending on the version
+  (``depends.map``)
+* ``debian`` contains all the files managing debian packaging (you will find
+  the usual files ``control``, ``rules``, ``changelog``... not installed)
+* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
+  and the current version (server side and web interface) or sub-cubes used by
+  the cube.
+
+
+At least you should have the file ``__pkginfo__.py``.
+
+
+The :file:`__init__.py` and :file:`site_cubicweb.py` files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :file:`__pkginfo__.py` file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It contains metadata describing your cubes, mostly useful for
+packaging.
+
+
+:file:`migration/precreate.py` and :file:`migration/postcreate.py`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX detail steps of instance creation
+
+
+External resources such as image, javascript and css files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX naming convention external_resources file
+
+
+Out-of the box testing
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
+
+
+Packaging and distribution
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/baseschema.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,43 @@
+.. _pre_defined_entity_types:
+
+Pre-defined entities in the library
+-----------------------------------
+
+The library defines a set of entity schemas that are required by the system
+or commonly used in *CubicWeb* instances.
+
+
+Entity types used to store the schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`CWEType`, entity type
+* _`CWRType`, relation type
+* _`CWRelation`, relation definition
+* _`CWAttribute`, attribute relation definition
+* _`CWConstraint`,  `CWConstraintType`, `RQLExpression`
+
+Entity types used to manage users and permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`CWUser`, system users
+* _`CWGroup`, users groups
+* _`CWPermission`, used to configure the security of the instance
+
+Entity types used to manage workflows
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`Workflow`, workflow entity, linked to some entity types which may use this workflow
+* _`State`, workflow state
+* _`Transition`, workflow transition
+* _`TrInfo`, record of a transition trafic for an entity
+
+Other entity types
+~~~~~~~~~~~~~~~~~~
+* _`CWCache`, cache entities used to improve performances
+* _`CWProperty`, used to configure the instance
+
+* _`EmailAddress`, email address, used by the system to send notifications
+  to the users and also used by others optionnals schemas
+
+* _`Bookmark`, an entity type used to allow a user to customize his links within
+  the instance
+
+* _`ExternalUri`, used for semantic web site to indicate that an entity is the
+  same as another from an external site
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/define-workflows.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,161 @@
+.. -*- coding: utf-8 -*-
+
+.. _Workflow:
+
+Defining a Workflow
+===================
+
+General
+-------
+
+A workflow describes how certain entities have to evolve between
+different states. Hence we have a set of states, and a "transition
+graph", i.e. a set of possible transitions from one state to another
+state.
+
+We will define a simple workflow for a blog, with only the following
+two states: `submitted` and `published`. So first, we create a simple
+|cubicweb| instance in five minutes (see :ref:`BlogFiveMinutes`).
+
+Setting up a workflow
+---------------------
+
+We want to create a workflow to control the quality of the BlogEntry
+submitted on the instance. When a BlogEntry is created by a user
+its state should be `submitted`. To be visible to all, it has to
+be in the state `published`. To move it from `submitted` to `published`,
+we need a transition that we can call `approve_blogentry`.
+
+A BlogEntry state should not be modifiable by every user.
+So we have to define a group of users, `moderators`, and
+this group will have appropriate permissions to publish a BlogEntry.
+
+There are two ways to create a workflow: from the user interface, or
+by defining it in ``migration/postcreate.py``. This script is executed
+each time a new ``cubicweb-ctl db-init`` is done.  We strongly
+recommend to create the workflow in ``migration/postcreate.py`` and we
+will now show you how. Read `Two bits of warning`_ to understand why.
+
+The state of an entity is managed by the `in_state` attribute which
+can be added to your entity schema by inheriting from
+`cubicweb.schema.WorkflowableEntityType`.
+
+
+About our example of BlogEntry, we must have:
+
+.. sourcecode:: python
+
+  from cubicweb.schema import WorkflowableEntityType
+
+  class BlogEntry(WorkflowableEntityType):
+      ...
+
+
+Creating states, transitions and group permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :mod:`postcreate` script is executed in a special environment,
+adding several |cubicweb| primitives that can be used.
+
+They are all defined in the :class:`ServerMigrationHelper` class.
+We will only discuss the methods we use to create a workflow in this example.
+
+A workflow is a collection of entities of type ``State`` and of type
+``Transition`` which are standard *CubicWeb* entity types.
+
+To define a workflow for BlogDemo, please add the following lines
+to ``migration/postcreate.py``:
+
+.. sourcecode:: python
+
+  _ = unicode
+
+  moderators = add_entity('CWGroup', name=u"moderators")
+
+This adds the `moderators` user group.
+
+.. sourcecode:: python
+
+  wf = add_workflow(u'blog publication workflow', 'BlogEntry')
+
+At first, instanciate a new workflow object with a gentle description
+and the concerned entity types (this one can be a tuple for multiple
+value).
+
+.. sourcecode:: python
+
+  submitted = wf.add_state(_('submitted'), initial=True)
+  published = wf.add_state(_('published'))
+
+This will create two entities of type ``State``, one with name
+'submitted', and the other with name 'published'.
+
+``add_state`` expects as first argument the name of the state you want
+to create and an optional argument to say if it is supposed to be the
+initial state of the entity type.
+
+.. sourcecode:: python
+
+  wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
+
+This will create an entity of type ``Transition`` with name
+`approve_blogentry` which will be linked to the ``State`` entities
+created before.
+
+``add_transition`` expects
+
+  * as the first argument: the name of the transition
+  * then the list of states on which the transition can be triggered,
+  * the target state of the transition,
+  * and the permissions
+    (e.g. a list of user groups who can apply the transition; the user
+    has to belong to at least one of the listed group to perform the action).
+
+.. sourcecode:: python
+
+  checkpoint()
+
+.. note::
+  Do not forget to add the `_()` in front of all states and
+  transitions names while creating a workflow so that they will be
+  identified by the i18n catalog scripts.
+
+In addition to the user groups (one of which the user needs to belong
+to), we could have added a RQL condition.  In this case, the user can
+only perform the action if the two conditions are satisfied.
+
+If we use an RQL condition on a transition, we can use the following variables:
+
+* `X`, the entity on which we may pass the transition
+* `U`, the user executing that may pass the transition
+
+
+.. image:: ../../images/03-transitions-view_en.png
+
+You can notice that in the action box of a BlogEntry, the state is now
+listed as well as the possible transitions for the current state
+defined by the workflow.
+
+The transitions will only be displayed for users having the right permissions.
+In our example, the transition `approve_blogentry` will only be displayed
+for the users belonging to the group `moderators` or `managers`.
+
+
+Two bits of warning
+~~~~~~~~~~~~~~~~~~~
+
+We could perfectly use the administration interface to do these
+operations. It is a convenient thing to do at times (when doing
+development, to quick-check things). But it is not recommended beyond
+that because it is a bit complicated to do it right and it will be
+only local to your instance (or, said a bit differently, such a
+workflow only exists in an instance database). Furthermore, you cannot
+write unit tests against deployed instances, and experience shows it
+is mandatory to have tests for any mildly complicated workflow
+setup.
+
+Indeed, if you create the states and transitions through the user
+interface, next time you initialize the database you will have to
+re-create all the workflow entities. The user interface should only be
+a reference for you to view the states and transitions, but is not the
+appropriate interface to define your application workflow.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/definition.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,631 @@
+ .. -*- coding: utf-8 -*-
+
+Yams *schema*
+-------------
+
+The **schema** is the core piece of a *CubicWeb* instance as it
+defines and handles the data model. It is based on entity types that
+are either already defined in `Yams`_ and the *CubicWeb* standard
+library; or more specific types defined in cubes. The schema for a
+cube is defined in a `schema` python module or package.
+
+.. _`Yams`: http://www.logilab.org/project/yams
+
+Overview
+~~~~~~~~
+
+The core idea of the yams schema is not far from the classical
+`Entity-relationship`_ model. But while an E/R model (or `logical
+model`) traditionally has to be manually translated to a lower-level
+data description language (such as the SQL `create table`
+sublanguage), also often described as the `physical model`, no such
+step is required with |yams| and |cubicweb|.
+
+.. _`Entity-relationship`: http://en.wikipedia.org/wiki/Entity-relationship_model
+
+This is because in addition to high-level, logical |yams| models, one
+uses the |rql| data manipulation language to query, insert, update and
+delete data. |rql| abstracts as much of the underlying SQL database as
+a |yams| schema abstracts from the physical layout. The vagaries of
+SQL are avoided.
+
+As a bonus point, such abstraction make it quite comfortable to build
+or use different backends to which |rql| queries apply.
+
+So, as in the E/R formalism, the building blocks are ``entities``
+(:ref:`EntityType`), ``relationships`` (:ref:`RelationType`,
+:ref:`RelationDefinition`) and ``attributes`` (handled like relation
+with |yams|).
+
+Let us detail a little the divergences between E/R and |yams|:
+
+* all relationship are binary which means that to represent a
+  non-binary relationship, one has to use an entity,
+* relationships do not support attributes (yet, see:
+  http://www.cubicweb.org/ticket/341318), hence the need to reify it
+  as an entity if need arises,
+* all entities have an `eid` attribute (an integer) that is its
+  primary key (but it is possible to declare uniqueness on other
+  attributes)
+
+Also |yams| supports the notions of:
+
+* entity inheritance (quite experimental yet, and completely
+  undocumented),
+* relation type: that is, relationships can be established over a set
+  of couple of entity types (henre the distinction made between
+  `RelationType` and `RelationDefinition` below)
+
+Finally |yams| has a few concepts of its own:
+
+* relationships being oriented and binary, we call the left hand
+  entity type the `subject` and the right hand entity type the
+  `object`
+
+.. note::
+
+   The |yams| schema is available at run time through the .schema
+   attribute of the `vregistry`.  It's an instance of
+   :class:`cubicweb.schema.Schema`, which extends
+   :class:`yams.schema.Schema`.
+
+.. _EntityType:
+
+Entity type
+~~~~~~~~~~~
+
+An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
+a set of attributes and relations, and some permissions which define who can add, read,
+update or delete entities of this type.
+
+The following built-in types are available: ``String``, ``Int``,
+``Float``, ``Decimal``, ``Boolean``, ``Date``, ``Datetime``, ``Time``,
+``Interval``, ``Byte`` and ``Password``. They can only be used as
+attributes of an other entity type.
+
+You can find more base entity types in
+:ref:`pre_defined_entity_types`.
+
+.. XXX yams inheritance
+
+.. _RelationType:
+
+Relation type
+~~~~~~~~~~~~~
+
+A relation type is an instance of
+:class:`yams.schema.RelationSchema`. A relation type is simply a
+semantic definition of a kind of relationship that may occur in an
+application.
+
+It may be referenced by zero, one or more relation definitions.
+
+It is important to choose a good name, at least to avoid conflicts
+with some semantically different relation defined in other cubes
+(since there's only a shared name space for these names).
+
+A relation type holds the following properties (which are hence shared
+between all relation definitions of that type):
+
+* `inlined`: boolean handling the physical optimization for archiving
+  the relation in the subject entity table, instead of creating a specific
+  table for the relation. This applies to relations where cardinality
+  of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
+  definitions.
+
+* `symmetric`: boolean indicating that the relation is symmetrical, which
+  means that `X relation Y` implies `Y relation X`.
+
+.. _RelationDefinition:
+
+Relation definition
+~~~~~~~~~~~~~~~~~~~
+
+A relation definition is an instance of
+:class:`yams.schema.RelationDefinition`. It is a complete triplet
+"<subject entity type> <relation type> <object entity type>".
+
+When creating a new instance of that class, the corresponding
+:class:`RelationType` instance is created on the fly if necessary.
+
+Properties
+``````````
+
+The available properties for relation definitions are enumerated
+here. There are several kind of properties, as some relation
+definitions are actually attribute definitions, and other are not.
+
+Some properties may be completely optional, other may have a default
+value.
+
+Common properties for attributes and relations:
+
+* `description`: an unicode string describing an attribute or a
+  relation. By default this string will be used in the editing form of
+  the entity, which means that it is supposed to help the end-user and
+  should be flagged by the function `_` to be properly
+  internationalized.
+
+* `constraints`: a list of conditions/constraints that the relation has to
+  satisfy (c.f. `Constraints`_)
+
+* `cardinality`: a two character string specifying the cardinality of
+  the relation. The first character defines the cardinality of the
+  relation on the subject, and the second on the object. When a
+  relation can have multiple subjects or objects, the cardinality
+  applies to all, not on a one-to-one basis (so it must be
+  consistent...). Default value is '**'. The possible values are
+  inspired from regular expression syntax:
+
+    * `1`: 1..1
+    * `?`: 0..1
+    * `+`: 1..n
+    * `*`: 0..n
+
+Attributes properties:
+
+* `unique`: boolean indicating if the value of the attribute has to be
+  unique or not within all entities of the same type (false by
+  default)
+
+* `indexed`: boolean indicating if an index needs to be created for
+  this attribute in the database (false by default). This is useful
+  only if you know that you will have to run numerous searches on the
+  value of this attribute.
+
+* `default`: default value of the attribute. In case of date types, the values
+  which could be used correspond to the RQL keywords `TODAY` and `NOW`.
+
+Properties for `String` attributes:
+
+* `fulltextindexed`: boolean indicating if the attribute is part of
+  the full text index (false by default) (*applicable on the type
+  `Byte` as well*)
+
+* `internationalizable`: boolean indicating if the value of the
+  attribute is internationalizable (false by default)
+
+Relation properties:
+
+* `composite`: string indicating that the subject (composite ==
+  'subject') is composed of the objects of the relations. For the
+  opposite case (when the object is composed of the subjects of the
+  relation), we just set 'object' as value. The composition implies
+  that when the relation is deleted (so when the composite is deleted,
+  at least), the composed are also deleted.
+
+* `fulltext_container`: string indicating if the value if the full
+  text indexation of the entity on one end of the relation should be
+  used to find the entity on the other end. The possible values are
+  'subject' or 'object'. For instance the use_email relation has that
+  property set to 'subject', since when performing a full text search
+  people want to find the entity using an email address, and not the
+  entity representing the email address.
+
+Constraints
+```````````
+
+By default, the available constraint types are:
+
+General Constraints
+......................
+
+* `SizeConstraint`: allows to specify a minimum and/or maximum size on
+  string (generic case of `maxsize`)
+
+* `BoundConstraint`: allows to specify a minimum and/or maximum value
+  on numeric types and date
+
+.. sourcecode:: python
+
+   from yams.constraints import BoundConstraint, TODAY
+   BoundConstraint('<=', TODAY())
+
+* `IntervalBoundConstraint`: allows to specify an interval with
+  included values
+
+.. sourcecode:: python
+
+     class Node(EntityType):
+         latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
+
+* `UniqueConstraint`: identical to "unique=True"
+
+* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
+
+.. XXX Attribute, NOW
+
+RQL Based Constraints
+......................
+
+RQL based constraints may take three arguments. The first one is the ``WHERE``
+clause of a RQL query used by the constraint. The second argument ``mainvars``
+is the ``Any`` clause of the query. By default this include `S` reserved for the
+subject of the relation and `O` for the object. Additional variables could be
+specified using ``mainvars``. The argument expects a single string with all
+variable's name separated by spaces. The last one, ``msg``, is the error message
+displayed when the constraint fails. As RQLVocabularyConstraint never fails the
+third argument is not available.
+
+* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
+  by the subject and/or the object of relation. In this query the variables
+  `S` and `O` are reserved for the relation subject and object entities.
+
+* `RQLVocabularyConstraint`: similar to the previous type of constraint except
+  that it does not express a "strong" constraint, which means it is only used to
+  restrict the values listed in the drop-down menu of editing form, but it does
+  not prevent another entity to be selected.
+
+* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
+  attribute is unique in a specific context. The Query must **never** return more
+  than a single result to be satisfied. In this query the variables `S` is
+  reserved for the relation subject entity. The other variables should be
+  specified with the second constructor argument (mainvars). This constraints
+  should be used when UniqueConstraint doesn't fit. Here is a simple example.
+
+.. sourcecode:: python
+
+    # Check that in the same Workflow each state's name is unique.  Using
+    # UniqueConstraint (or unique=True) here would prevent states in different
+    # workflows to have the same name.
+
+    # With: State S, Workflow W, String N ; S state_of W, S name N
+
+    RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
+                        mainvars='Y',
+                        msg=_('workflow already has a state of that name'))
+
+.. XXX note about how to add new constraint
+
+.. _securitymodel:
+
+The security model
+~~~~~~~~~~~~~~~~~~
+
+The security model of `CubicWeb` is based on `Access Control List`.
+The main principles are:
+
+* users and groups of users
+* a user belongs to at least one group of user
+* permissions (read, update, create, delete)
+* permissions are assigned to groups (and not to users)
+
+For *CubicWeb* in particular:
+
+* we associate rights at the entities/relations schema level
+* for each entity, we distinguish four kinds of permissions: `read`,
+  `add`, `update` and `delete`
+* for each relation, we distinguish three kinds of permissions: `read`,
+  `add` and `delete` (it is not possible to `modify` a relation)
+* the default groups are: `administrators`, `users` and `guests`
+* by default, users belong to the `users` group
+* there is a virtual group called `owners` to which we
+  can associate only `delete` and `update` permissions
+
+  * we can not add users to the `Owners` group, they are
+    implicitly added to it according to the context of the objects
+    they own
+  * the permissions of this group are only checked on `update`/`delete`
+    actions if all the other groups the user belongs to do not provide
+    those permissions
+
+Setting permissions is done with the attribute `__permissions__` of entities and
+relation types. The value of this attribute is a dictionary where the keys are the access types
+(action), and the values are the authorized groups or expressions.
+
+For an entity type, the possible actions are `read`, `add`, `update` and
+`delete`.
+
+For a relation type, the possible actions are `read`, `add`, and `delete`.
+
+For each access type, a tuple indicates the name of the authorized groups and/or
+one or multiple RQL expressions to satisfy to grant access. The access is
+provided if the user is in one of the listed groups or if one of the RQL condition
+is satisfied.
+
+The standard user groups
+````````````````````````
+
+* `guests`
+
+* `users`
+
+* `managers`
+
+* `owners`: virtual group corresponding to the entity's owner.
+  This can only be used for the actions `update` and `delete` of an entity
+  type.
+
+It is also possible to use specific groups if they are defined in the
+precreate script of the cube (``migration/precreate.py``). Defining groups in
+postcreate script or later makes them unavailable for security
+purposes (in this case, an `sync_schema_props_perms` command has to
+be issued in a CubicWeb shell).
+
+
+Use of RQL expression for write permissions
+```````````````````````````````````````````
+It is possible to define RQL expression to provide update permission
+(`add`, `delete` and `update`) on relation and entity types.
+
+RQL expression for entity type permission:
+
+* you have to use the class `ERQLExpression`
+
+* the used expression corresponds to the WHERE statement of an RQL query
+
+* in this expression, the variables `X` and `U` are pre-defined references
+  respectively on the current entity (on which the action is verified) and
+  on the user who send the request
+
+* it is possible to use, in this expression, a special relation
+  "has_<ACTION>_permission" where the subject is the user and the
+  object is any variable, meaning that the user needs to have
+  permission to execute the action <ACTION> on the entities related
+  to this variable
+
+For RQL expressions on a relation type, the principles are the same except
+for the following:
+
+* you have to use the class `RRQLExpression` in the case of a non-final relation
+
+* in the expression, the variables `S`, `O` and `U` are pre-defined references
+  to respectively the subject and the object of the current relation (on
+  which the action is being verified) and the user who executed the query
+
+* we can also define rights over attributes of an entity (non-final relation),
+  knowing that:
+
+  - to define RQL expression, we have to use the class `ERQLExpression`
+    in which `X` represents the entity the attribute belongs to
+
+  - the permissions `add` and `delete` are equivalent. Only `add`/`read`
+    are actually taken in consideration.
+
+.. note::
+
+  Potentially, the `use of an RQL expression to add an entity or a
+  relation` can cause problems for the user interface, because if the
+  expression uses the entity or the relation to create, then we are
+  not able to verify the permissions before we actually add the entity
+  (please note that this is not a problem for the RQL server at all,
+  because the permissions checks are done after the creation). In such
+  case, the permission check methods (CubicWebEntitySchema.check_perm
+  and has_perm) can indicate that the user is not allowed to create
+  this entity but can obtain the permission.  To compensate this
+  problem, it is usually necessary, for such case, to use an action
+  that reflects the schema permissions but which enables to check
+  properly the permissions so that it would show up if necessary.
+
+
+Use of RQL expression for reading rights
+````````````````````````````````````````
+
+The principles are the same but with the following restrictions:
+
+* we can not use `RRQLExpression` on relation types for reading
+
+* special relations "has_<ACTION>_permission" can not be used
+
+
+
+
+Defining your schema using yams
+-------------------------------
+
+Entity type definition
+~~~~~~~~~~~~~~~~~~~~~~
+
+An entity type is defined by a Python class which inherits from
+:class:`yams.buildobjs.EntityType`.  The class definition contains the
+description of attributes and relations for the defined entity type.
+The class name corresponds to the entity type name. It is expected to
+be defined in the module ``mycube.schema``.
+
+:Note on schema definition:
+
+ The code in ``mycube.schema`` is not meant to be executed. The class
+ EntityType mentioned above is different from the EntitySchema class
+ described in the previous chapter. EntityType is a helper class to
+ make Entity definition easier. Yams will process EntityType classes
+ and create EntitySchema instances from these class definitions. Similar
+ manipulation happen for relations.
+
+When defining a schema using python files, you may use the following shortcuts:
+
+- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
+
+- `vocabulary`: specify static possible values of an attribute
+
+- `maxsize`: integer providing the maximum size of a string (no limit by default)
+
+For example:
+
+.. sourcecode:: python
+
+  class Person(EntityType):
+    """A person with the properties and the relations necessary for my
+    application"""
+
+    last_name = String(required=True, fulltextindexed=True)
+    first_name = String(required=True, fulltextindexed=True)
+    title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
+    date_of_birth = Date()
+    works_for = SubjectRelation('Company', cardinality='?*')
+
+
+The entity described above defines three attributes of type String,
+last_name, first_name and title, an attribute of type Date for the date of
+birth and a relation that connects a `Person` to another entity of type
+`Company` through the semantic `works_for`.
+
+:Naming convention:
+
+ Entity class names must start with an uppercase letter. The common
+ usage is to use ``CamelCase`` names.
+
+ Attribute and relation names must start with a lowercase letter. The
+ common usage is to use ``underscore_separated_words``. Attribute and
+ relation names starting with a single underscore are permitted, to
+ denote a somewhat "protected" or "private" attribute.
+
+ In any case, identifiers starting with "CW" or "cw" are reserved for
+ internal use by the framework.
+
+
+The name of the Python attribute corresponds to the name of the attribute
+or the relation in *CubicWeb* application.
+
+An attribute is defined in the schema as follows::
+
+    attr_name = attr_type(properties)
+
+where `attr_type` is one of the type listed above and `properties` is
+a list of the attribute needs to satisfy (see `Properties`_
+for more details).
+
+* it is possible to use the attribute `meta` to flag an entity type as a `meta`
+  (e.g. used to describe/categorize other entities)
+
+.. XXX the paragraph below needs clarification and / or moving out in
+.. another place
+
+*Note*: if you end up with an `if` in the definition of your entity, this probably
+means that you need two separate entities that implement the `ITree` interface and
+get the result from `.children()` which ever entity is concerned.
+
+Inheritance
+```````````
+XXX feed me
+
+
+Definition of relations
+~~~~~~~~~~~~~~~~~~~~~~~
+
+XXX add note about defining relation type / definition
+
+A relation is defined by a Python class heriting `RelationType`. The name
+of the class corresponds to the name of the type. The class then contains
+a description of the properties of this type of relation, and could as well
+contain a string for the subject and a string for the object. This allows to create
+new definition of associated relations, (so that the class can have the
+definition properties from the relation) for example ::
+
+  class locked_by(RelationType):
+    """relation on all entities indicating that they are locked"""
+    inlined = True
+    cardinality = '?*'
+    subject = '*'
+    object = 'CWUser'
+
+If provided, the `subject` and `object` attributes denote the subject
+and object of the various relation definitions related to the relation
+type. Allowed values for these attributes are:
+
+* a string corresponding to an entity type
+* a tuple of string corresponding to multiple entity types
+* special string such as follows:
+
+  - "**": all types of entities
+  - "*": all types of non-meta entities
+  - "@": all types of meta entities but not system entities (e.g. used for
+    the basic schema description)
+
+When a relation is not inlined and not symmetrical, and it does not require
+specific permissions, it can be defined using a `SubjectRelation`
+attribute in the EntityType class. The first argument of `SubjectRelation` gives
+the entity type for the object of the relation.
+
+:Naming convention:
+
+ Although this way of defining relations uses a Python class, the
+ naming convention defined earlier prevails over the PEP8 conventions
+ used in the framework: relation type class names use
+ ``underscore_separated_words``.
+
+:Historical note:
+
+   It has been historically possible to use `ObjectRelation` which
+   defines a relation in the opposite direction. This feature is soon to be
+   deprecated and therefore should not be used in newly written code.
+
+:Future deprecation note:
+
+  In an even more remote future, it is quite possible that the
+  SubjectRelation shortcut will become deprecated, in favor of the
+  RelationType declaration which offers some advantages in the context
+  of reusable cubes.
+
+Definition of permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+The entity type `CWPermission` from the standard library
+allows to build very complex and dynamic security architectures. The schema of
+this entity type is as follow:
+
+.. sourcecode:: python
+
+    class CWPermission(EntityType):
+        """entity type that may be used to construct some advanced security configuration
+        """
+        name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
+        require_group = SubjectRelation('CWGroup', cardinality='+*',
+                                        description=_('groups to which the permission is granted'))
+        require_state = SubjectRelation('State',
+                                        description=_("entity's state in which the permission is applicable"))
+        # can be used on any entity
+        require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
+                                            description=_("link a permission to the entity. This "
+                                                          "permission should be used in the security "
+                                                          "definition of the entity's type to be useful."))
+
+
+Example of configuration:
+
+.. sourcecode:: python
+
+    class Version(EntityType):
+        """a version is defining the content of a particular project's release"""
+
+        __permissions__ = {'read':   ('managers', 'users', 'guests',),
+                           'update': ('managers', 'logilab', 'owners',),
+                           'delete': ('managers', ),
+                           'add':    ('managers', 'logilab',
+                                       ERQLExpression('X version_of PROJ, U in_group G,'
+                                                 'PROJ require_permission P, P name "add_version",'
+                                                 'P require_group G'),)}
+
+
+    class version_of(RelationType):
+        """link a version to its project. A version is necessarily linked to one and only one project.
+        """
+        __permissions__ = {'read':   ('managers', 'users', 'guests',),
+                           'delete': ('managers', ),
+                           'add':    ('managers', 'logilab',
+                                  RRQLExpression('O require_permission P, P name "add_version",'
+                                                 'U in_group G, P require_group G'),)
+                       }
+        inlined = True
+
+
+This configuration indicates that an entity `CWPermission` named
+"add_version" can be associated to a project and provides rights to create
+new versions on this project to specific groups. It is important to notice that:
+
+* in such case, we have to protect both the entity type "Version" and the relation
+  associating a version to a project ("version_of")
+
+* because of the genericity of the entity type `CWPermission`, we have to execute
+  a unification with the groups and/or the states if necessary in the expression
+  ("U in_group G, P require_group G" in the above example)
+
+
+
+Handling schema changes
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Also, it should be clear that to properly handle data migration, an
+instance's schema is stored in the database, so the python schema file
+used to defined it is only read when the instance is created or
+upgraded.
+
+.. XXX complete me
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,12 @@
+Data model
+==========
+
+This chapter describes how you define a schema and how to make it evolves as the time goes.
+
+.. toctree::
+   :maxdepth: 1
+
+   definition
+   metadata
+   baseschema
+   define-workflows
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/metadata.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,37 @@
+
+Metadata
+--------
+
+.. index::
+   schema: meta-data;
+   schema: eid; creation_date; modification_data; cwuri
+   schema: created_by; owned_by; is; is_instance;
+
+Each entity type in |cubicweb| has at least the following meta-data attributes and relations:
+
+`eid`
+  entity's identifier which is unique in an instance. We usually call this identifier `eid` for historical reason.
+
+`creation_date`
+  Date and time of the creation of the entity.
+
+`modification_date`
+  Date and time of the latest modification of an entity.
+
+`cwuri`
+  Reference URL of the entity, which is not expected to change.
+
+`created_by`
+  Relation to the :ref:`users <CWUser>` who has created the entity
+
+`owned_by`
+  Relation to :ref:`users <CWUser>` whom the entity belongs; usually the creator but not
+  necessary, and it could have multiple owners notably for permission control
+
+`is`
+  Relation to the :ref:`entity type <CWEType>` of which type the entity is.
+
+`is_instance`
+  Relation to the :ref:`entity types <CWEType>` of which type the
+  entity is an instance of.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/cwconfig.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,5 @@
+Configuration
+-------------
+
+.. automodule:: cubicweb.cwconfig
+      :members:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/dbapi.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,121 @@
+.. _dbapi:
+
+Python/RQL API
+~~~~~~~~~~~~~~
+
+The Python API developped to interface with RQL is inspired from the standard db-api,
+with a Connection object having the methods cursor, rollback and commit essentially.
+The most important method is the `execute` method of a cursor.
+
+.. sourcecode:: python
+
+   execute(rqlstring, args=None, build_descr=True)
+
+:rqlstring: the RQL query to execute (unicode)
+:args: if the query contains substitutions, a dictionary containing the values to use
+
+The `Connection` object owns the methods `commit` and `rollback`. You
+*should never need to use them* during the development of the web
+interface based on the *CubicWeb* framework as it determines the end
+of the transaction depending on the query execution success. They are
+however useful in other contexts such as tests or custom controllers.
+
+.. note::
+
+  While executing update queries (SET, INSERT, DELETE), if a query generates
+  an error related to security, a rollback is automatically done on the current
+  transaction.
+
+Executing RQL queries from a view or a hook
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you're within code of the web interface, the db-api like connexion is
+handled by the request object. You should not have to access it directly, but
+use the `execute` method directly available on the request, eg:
+
+.. sourcecode:: python
+
+   rset = self._cw.execute(rqlstring, kwargs)
+
+Similarly, on the server side (eg in hooks), there is no db-api connexion (since
+you're directly inside the data-server), so you'll have to use the execute method
+of the session object.
+
+
+Proper usage of `.execute`
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's say you want to get T which is in configuration C, this translates to:
+
+.. sourcecode:: python
+
+   self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
+
+But it must be written in a syntax that will benefit from the use
+of a cache on the RQL server side:
+
+.. sourcecode:: python
+
+   self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
+
+The syntax tree is built once for the "generic" RQL and can be re-used
+with a number of different eids. There rql IN operator is an exception
+to this rule.
+
+.. sourcecode:: python
+
+   self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
+                    % ','.join(['foo', 'bar']))
+
+Alternativelly, some of the common data related to an entity can be
+obtained from the `entity.related()` method (which is used under the
+hood by the orm when you use attribute access notation on an entity to
+get a relation. The initial request would then be translated to:
+
+.. sourcecode:: python
+
+   entity.related('in_conf', 'object')
+
+Additionnaly this benefits from the fetch_attrs policy (see
+:ref:`FetchAttrs`) eventually defined on the class element, which says
+which attributes must be also loaded when the entity is loaded through
+the orm.
+
+
+.. _resultset:
+
+The `ResultSet` API
+~~~~~~~~~~~~~~~~~~~
+
+ResultSet instances are a very commonly manipulated object. They have
+a rich API as seen below, but we would like to highlight a bunch of
+methods that are quite useful in day-to-day practice:
+
+* `__str__()` (applied by `print`) gives a very useful overview of both
+  the underlying RQL expression and the data inside; unavoidable for
+  debugging purposes
+
+* `printable_rql()` produces back a well formed RQL expression as a
+  string; it is very useful to build views
+
+* `entities()` returns a generator on all entities of the result set
+
+* `get_entity(row, col)` gets the entity at row, col coordinates; one
+  of the most used result set method
+
+.. autoclass:: cubicweb.rset.ResultSet
+   :members:
+
+
+The `Cursor` API
+~~~~~~~~~~~~~~~~
+
+The whole cursor API is developped below.
+
+.. note::
+
+  In practice we use the `.execute` method on the _cw object of
+  appobjects. Usage of other methods is quite rare.
+
+.. autoclass:: cubicweb.dbapi.Cursor
+   :members:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,10 @@
+Core APIs
+=========
+
+.. toctree::
+   :maxdepth: 1
+
+   dbapi.rst
+   reqbase.rst
+   cwconfig.rst
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/reqbase.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,40 @@
+Request and ResultSet methods
+-----------------------------
+
+Those are methods you'll find on both request objects and on
+repository session.
+
+Request methods
+~~~~~~~~~~~~~~~
+
+`URL handling`:
+
+* `build_url(*args, **kwargs)`, returns an absolute URL based on the
+  given arguments. The *controller* supposed to handle the response,
+  can be specified through the first positional parameter (the
+  connection is theoretically done automatically :).
+
+`Data formatting`:
+
+* `format_date(date, date_format=None, time=False)` returns a string for a
+  date time according to instance's configuration
+
+* `format_time(time)` returns a string for a date time according to
+  instance's configuration
+
+`And more...`:
+
+* `tal_render(template, variables)`, renders a precompiled page template with
+  variables in the given dictionary as context
+
+
+Result set methods
+~~~~~~~~~~~~~~~~~~
+
+* `get_entity(row, col)`, returns the entity corresponding to the data position
+  in the *result set*
+
+* `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but
+  also call the method `complete()` on the entity before returning it
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/application-logic.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,166 @@
+How to use entities objects
+---------------------------
+
+The previous chapters detailed the classes and methods available to
+the developper at the so-called `ORM`_ level. However they say little
+about the common patterns of usage of these objects.
+
+.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
+
+Entities objects are used in the repository and web sides of
+CubicWeb. On the repository side of things, one should manipulate them
+in Hooks and Operations.
+
+Hooks and Operations provide support for the implementation of rules
+such as computed attributes, coherency invariants, etc (they play the
+same role as database triggers, but in a way that is independant of
+the actual data sources).
+
+So a lot of an application's business rules will be written in Hooks
+(or Operations).
+
+On the web side, views also typically operate using entity
+objects. Obvious entity methods for use in views are the dublin code
+method like dc_title, etc. For separation of concerns reasons, one
+should ensure no ui logic pervades the entities level, and also no
+business logic should creep into the views.
+
+In the duration of a transaction, entities objects can be instantiated
+many times, in views and hooks, even for the same database entity. For
+instance, in a classic CubicWeb deployment setup, the repository and
+the web frontend are separated process communicating over the
+wire. There is no way state can be shared between these processes
+(there is a specific API for that). Hence, it is not possible to use
+entity objects as messengers between these components of an
+application. It means that an attribute set as in `obj.x = 42`,
+whether or not x is actually an entity schema attribute, has a short
+life span, limited to the hook, operation or view within which the
+object was built.
+
+Setting an attribute or relation value can be done in the context of a
+Hook/Operation, using the obj.set_attributes(x=42) notation or a plain
+RQL SET expression.
+
+In views, it would be preferable to encapsulate the necessary logic in
+a method of the concerned entity class(es). But of course, this advice
+is also reasonnable for Hooks/Operations, though the separation of
+concerns here is less stringent than in the case of views.
+
+This leads to the practical role of entity objects: it's where an
+important part of the application logic lie (the other part being
+located in the Hook/Operations).
+
+Anatomy of an entity class
+--------------------------
+
+We can look now at a real life example coming from the `tracker`_
+cube. Let us begin to study the entities/project.py content.
+
+.. sourcecode:: python
+
+    class Project(TreeMixIn, AnyEntity):
+        __regid__ = 'Project'
+        __implements__ = AnyEntity.__implements__ + (ITree,)
+        fetch_attrs, fetch_order = fetch_config(('name', 'description',
+                                                 'description_format', 'summary'))
+
+        TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")'
+
+        tree_attribute = 'subproject_of'
+        parent_target = 'subject'
+        children_target = 'object'
+
+        def dc_title(self):
+            return self.name
+
+First we see that it uses an ITree interface and the TreeMixIn default
+implementation. The attributes `tree_attribute`, `parent_target` and
+`children_target` are used by the TreeMixIn code. This is typically
+used in views concerned with the representation of tree-like
+structures (CubicWeb provides several such views).
+
+It is important that the views themselves try not to implement this
+logic, not only because such views would be hardly applyable to other
+tree-like relations, but also because it is perfectly fine and useful
+to use such an interface in Hooks.
+
+In fact, Tree nature is a property of the data model that cannot be
+fully and portably expressed at the level of database entities (think
+about the transitive closure of the child relation). This is a further
+argument to implement it at entity class level.
+
+The `dc_title` method provides a (unicode string) value likely to be
+consummed by views, but note that here we do not care about output
+encodings. We care about providing data in the most universal format
+possible, because the data could be used by a web view (which would be
+responsible of ensuring XHTML compliance), or a console or file
+oriented output (which would have the necessary context about the
+needed byte stream encoding).
+
+The fetch_attrs, fetch_order class attributes are parameters of the
+`ORM`_ layer. They tell which attributes should be loaded at once on
+entity object instantiation (by default, only the eid is known, other
+attributes are loaded on demand), and which attribute is to be used to
+order the .related() and .unrelated() methods output.
+
+Finally, we can observe the big TICKET_DEFAULT_STATE_RESTR is a pure
+application domain piece of data. There is, of course, no limitation
+to the amount of class attributes of this kind.
+
+Let us now dig into more substantial pieces of code.
+
+.. sourcecode:: python
+
+    def latest_version(self, states=('published',), reverse=None):
+        """returns the latest version(s) for the project in one of the given
+        states.
+
+        when no states specified, returns the latest published version.
+        """
+        order = 'DESC'
+        if reverse is not None:
+            warn('reverse argument is deprecated',
+                 DeprecationWarning, stacklevel=1)
+            if reverse:
+                order = 'ASC'
+        rset = self.versions_in_state(states, order, True)
+        if rset:
+            return rset.get_entity(0, 0)
+        return None
+
+    def versions_in_state(self, states, order='ASC', limit=False):
+        """returns version(s) for the project in one of the given states, sorted
+        by version number.
+
+        If limit is true, limit result to one version.
+        If reverse, versions are returned from the smallest to the greatest.
+        """
+        if limit:
+            order += ' LIMIT 1'
+        rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \
+              'WHERE V num N, V in_state S, S name IN (%s), ' \
+              'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states))
+        return self._cw.execute(rql, {'p': self.eid})
+
+.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/
+
+These few lines exhibit the important properties we want to outline:
+
+* entity code is concerned with the application domain
+
+* it is NOT concerned with database coherency (this is the realm of
+  Hooks/Operations); in other words, it assumes a coherent world
+
+* it is NOT concerned with end-user interfaces
+
+* however it can be used in both contexts
+
+* it does not create or manipulate the internal object's state
+
+* it plays freely with RQL expression as needed
+
+* it is not concerned with internationalization
+
+* it does not raise exceptions
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/data-as-objects.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,143 @@
+Access to persistent data
+--------------------------
+
+Python-level access to persistent data is provided by the
+:class:`Entity <cubicweb.entity>` class.
+
+An entity class is bound to a schema entity type.  Descriptors are added when
+classes are registered in order to initialize the class according to its schema:
+
+* we can access the defined attributes in the schema thanks to the attributes of
+  the same name on instances (typed value)
+
+* we can access the defined relations in the schema thanks to the relations of
+  the same name on instances (entities instances list)
+
+
+`Formatting and output generation`:
+
+* `view(__vid, __registry='views', **kwargs)`, applies the given view to the entity
+  (and returns an unicode string)
+
+* `absolute_url(*args, **kwargs)`, returns an absolute URL to access the primary view
+  of an entity
+
+* `rest_path()`, returns a relative REST URL to get the entity
+
+* `printable_value(attr, value=_marker, attrtype=None, format='text/html', displaytime=True)`,
+  returns a string enabling the display of an attribute value in a given format
+  (the value is automatically recovered if necessary)
+
+`Data handling`:
+
+* `as_rset()`, converts the entity into an equivalent result set simulating the
+   request `Any X WHERE X eid _eid_`
+
+* `complete(skip_bytes=True)`, executes a request that recovers at
+  once all the missing attributes of an entity
+
+* `get_value(name)`, returns the value associated to the attribute name given
+  in parameter
+
+* `related(rtype, role='subject', limit=None, entities=False)`,
+  returns a list of entities related to the current entity by the
+  relation given in parameter
+
+* `unrelated(rtype, targettype, role='subject', limit=None)`,
+  returns a result set corresponding to the entities not (yet)
+  related to the current entity by the relation given in parameter
+  and satisfying its constraints
+
+* `set_attributes(**kwargs)`, updates the attributes list with the corresponding
+  values given named parameters
+
+* `set_relations(**kwargs)`, add relations to the given object. To
+   set a relation where this entity is the object of the relation,
+   use `reverse_<relation>` as argument name.  Values may be an
+   entity, a list of entities, or None (meaning that all relations of
+   the given type from or to this object should be deleted).
+
+* `copy_relations(ceid)`, copies the relations of the entities having the eid
+  given in the parameters on the current entity
+
+* `delete()` allows to delete the entity
+
+
+The :class:`AnyEntity` class
+----------------------------
+
+To provide a specific behavior for each entity, we have to define a class
+inheriting from `cubicweb.entities.AnyEntity`. In general, we define this class
+in `mycube.entities` module (or in a submodule if we want to split code among
+multiple files) so that it will be available on both server and client side.
+
+The class `AnyEntity` is a sub-class of Entity that add methods to it,
+and helps specializing (by further subclassing) the handling of a
+given entity type.
+
+Most methods defined for `AnyEntity`, in addition to `Entity`, add
+support for the `Dublin Core`_ metadata.
+
+.. _`Dublin Core`: http://dublincore.org/
+
+`Standard meta-data (Dublin Core)`:
+
+* `dc_title()`, returns a unicode string corresponding to the
+  meta-data `Title` (used by default is the first non-meta attribute
+  of the entity schema)
+
+* `dc_long_title()`, same as dc_title but can return a more
+  detailed title
+
+* `dc_description(format='text/plain')`, returns a unicode string
+  corresponding to the meta-data `Description` (looks for a
+  description attribute by default)
+
+* `dc_authors()`, returns a unicode string corresponding to the meta-data
+  `Authors` (owners by default)
+
+* `dc_creator()`, returns a unicode string corresponding to the
+  creator of the entity
+
+* `dc_date(date_format=None)`, returns a unicode string corresponding to
+  the meta-data `Date` (update date by default)
+
+* `dc_type(form='')`, returns a string to display the entity type by
+  specifying the preferred form (`plural` for a plural form)
+
+* `dc_language()`, returns the language used by the entity
+
+
+`Misc methods`:
+
+* `after_deletion_path`, return (path, parameters) which should be
+   used as redirect information when this entity is being deleted
+
+* `pre_web_edit`, callback called by the web editcontroller when an
+  entity will be created/modified, to let a chance to do some entity
+  specific stuff (does nothing by default)
+
+Inheritance
+-----------
+
+When describing a data model, entities can inherit from other entities as is
+common in object-oriented programming.
+
+You have the possibility to redefine whatever pleases you, as follow:
+
+.. sourcecode:: python
+
+    from cubes.OTHER_CUBE import entities
+
+    class EntityExample(entities.EntityExample):
+
+        def dc_long_title(self):
+            return '%s (%s)' % (self.name, self.description)
+
+The most specific entity definition will always the one used by the
+ORM. For instance, the new EntityExample above in mycube replaces the
+one in OTHER_CUBE. These types are stored in the `etype` section of
+the `vregistry`.
+
+Notice this is different than yams schema inheritance.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,13 @@
+Data as objects
+===============
+
+In this chapter, we will introduce the objects that are used to handle
+the logic associated to the data stored in the database.
+
+.. toctree::
+   :maxdepth: 1
+
+   data-as-objects
+   load-sort
+   interfaces
+   application-logic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/interfaces.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,65 @@
+Interfaces
+----------
+
+This is the same thing as object-oriented programming `interfaces`_.
+
+.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
+
+Definition of an interface is quite trivial. An example from cubicweb
+itself (found in cubicweb/interfaces.py):
+
+.. sourcecode:: python
+
+    class ITree(Interface):
+
+        def parent(self):
+            """returns the parent entity"""
+
+        def children(self):
+            """returns the item's children"""
+
+        def children_rql(self):
+            """returns RQL to get children"""
+
+        def iterchildren(self):
+            """iterates over the item's children"""
+
+        def is_leaf(self):
+            """returns true if this node as no child"""
+
+        def is_root(self):
+            """returns true if this node has no parent"""
+
+        def root(self):
+            """returns the root object"""
+
+
+Declaration of interfaces implemented by a class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. sourcecode:: python
+
+  from cubicweb.interfaces import ITree
+  from cubicweb.mixins import TreeMixIn
+
+  class MyEntity(TreeMixIn, AnyEntity):
+      __regid__ = 'MyEntity'
+      __implements__ = AnyEntity.__implements__ + ('ITree',)
+
+      tree_attribute = 'filed_under'
+
+The TreeMixIn here provides a default implementation for the
+interface. The tree_attribute class attribute is actually used by this
+implementation to help implement correct behaviour.
+
+Interfaces (and some implementations as mixins) defined in the library
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: cubicweb.interfaces
+   :members:
+
+.. automodule:: cubicweb.mixins
+   :members:
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/load-sort.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,53 @@
+
+.. _FetchAttrs:
+
+Loaded attributes and default sorting management
+````````````````````````````````````````````````
+
+* The class attribute `fetch_attrs` allows to define in an entity class a list
+  of names of attributes or relations that should be automatically loaded when
+  entities of this type are fetched from the database. In the case of relations,
+  we are limited to *subject of cardinality `?` or `1`* relations.
+
+* The class method `fetch_order(attr, var)` expects an attribute (or relation)
+  name as a parameter and a variable name, and it should return a string
+  to use in the requirement `ORDERBY` of an RQL query to automatically
+  sort the list of entities of such type according to this attribute, or
+  `None` if we do not want to sort on the attribute given in the parameter.
+  By default, the entities are sorted according to their creation date.
+
+* The class method `fetch_unrelated_order(attr, var)` is similar to
+  the method `fetch_order` except that it is essentially used to
+  control the sorting of drop-down lists enabling relations creation
+  in the editing view of an entity. The default implementation uses
+  the modification date. Here's how to adapt it for one entity (sort
+  on the name attribute): ::
+
+   class MyEntity(AnyEntity):
+       __regid__ = 'MyEntity'
+       fetch_attrs = ('modification_date', 'name')
+
+       @classmethod
+       def fetch_unrelated_order(cls, attr, var):
+           if attr == 'name':
+              return '%s ASC' % var
+           return None
+
+
+The function `fetch_config(fetchattrs, mainattr=None)` simplifies the
+definition of the attributes to load and the sorting by returning a
+list of attributes to pre-load (considering automatically the
+attributes of `AnyEntity`) and a sorting function based on the main
+attribute (the second parameter if specified, otherwise the first
+attribute from the list `fetchattrs`). This function is defined in
+`cubicweb.entities`.
+
+For example: ::
+
+  class Transition(AnyEntity):
+    """..."""
+    __regid__ = 'Transition'
+    fetch_attrs, fetch_order = fetch_config(['name'])
+
+Indicates that for the entity type "Transition", you have to pre-load
+the attribute `name` and sort by default on this attribute.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,23 @@
+.. _Part2:
+
+----------------------
+Repository development
+----------------------
+
+This part is about developing applications with the *CubicWeb*
+framework. It is not concerned with the web system, which is a
+separate layer and has its own whole chapter.
+
+.. toctree::
+   :maxdepth: 2
+   :numbered:
+
+   cubes/index
+   vreg.rst
+   datamodel/index
+   entityclasses/index
+   devcore/index
+   repo/index
+   testing.rst
+   migration.rst
+   profiling.rst
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/migration.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,198 @@
+.. -*- coding: utf-8 -*-
+
+.. _migration:
+
+Migration
+=========
+
+One of the main design goals of *CubicWeb* was to support iterative and agile
+development. For this purpose, multiple actions are provided to facilitate the
+improvement of an instance, and in particular to handle the changes to be
+applied to the data model, without loosing existing data.
+
+The current version of a cube (and of cubicweb itself) is provided in the file
+`__pkginfo__.py` as a tuple of 3 integers.
+
+Migration scripts management
+----------------------------
+
+Migration scripts has to be located in the directory `migration` of your
+cube and named accordingly:
+
+::
+
+  <version n° X.Y.Z>[_<description>]_<mode>.py
+
+in which :
+
+* X.Y.Z is the model version number to which the script enables to migrate.
+
+* *mode* (between the last "_" and the extension ".py") is used for
+  distributed installation. It indicates to which part
+  of the application (RQL server, web server) the script applies.
+  Its value could be :
+
+  * `common`, applies to the RQL server as well as the web server and updates
+    files on the hard drive (configuration files migration for example).
+
+  * `web`, applies only to the web server and updates files on the hard drive.
+
+  * `repository`, applies only to the RQL server and updates files on the
+    hard drive.
+
+  * `Any`, applies only to the RQL server and updates data in the database
+    (schema and data migration for example).
+
+Again in the directory `migration`, the file `depends.map` allows to indicate
+that for the migration to a particular model version, you always have to first
+migrate to a particular *CubicWeb* version. This file can contain comments (lines
+starting by `#`) and a dependancy is listed as follows: ::
+
+  <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
+
+For example: ::
+
+  0.12.0: 2.26.0
+  0.13.0: 2.27.0
+  # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
+  0.15.0: 2.28.0
+
+Base context
+------------
+
+The following identifiers are pre-defined in migration scripts:
+
+* `config`, instance configuration
+
+* `interactive_mode`, boolean indicating that the script is executed in
+  an interactive mode or not
+
+* `versions_map`, dictionary of migrated versions  (key are cubes
+  names, including 'cubicweb', values are (from version, to version)
+
+* `confirm(question)`, function asking the user and returning true
+  if the user answers yes, false otherwise (always returns true in
+  non-interactive mode)
+
+* `_()` is equivalent to `unicode` allowing to flag the strings to
+  internationalize in the migration scripts.
+
+In the `repository` scripts, the following identifiers are also defined:
+
+* `commit(ask_confirm=True)`, request confirming and executing a "commit"
+
+* `schema`, instance schema (readen from the database)
+
+* `fsschema`, installed schema on the file system (e.g. schema of
+  the updated model and cubicweb)
+
+* `repo`, repository object
+
+* `session`, repository session object
+
+
+Schema migration
+----------------
+The following functions for schema migration are available in `repository`
+scripts:
+
+* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
+  attribute to an existing entity type. If the attribute type is not specified,
+  then it is extracted from the updated schema.
+
+* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
+  existing entity type.
+
+* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
+
+* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
+  If `auto` is True, all the relations using this entity type and having a known
+  entity type on the other hand will automatically be added.
+
+* `drop_entity_type(etype, commit=True)`, removes an entity type and all the
+  relations using it.
+
+* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
+
+* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
+  type. If `addrdef` is True, all the relations definitions of this type will
+  be added.
+
+* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
+  definitions of this type.
+
+* `rename_relation(oldname, newname, commit=True)`, renames a relation.
+
+* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
+  relation definition.
+
+* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
+  a relation definition.
+
+* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
+  synchronizes properties and/or permissions on:
+  - the whole schema if ertype is None
+  - an entity or relation type schema if ertype is a string
+  - a relation definition  if ertype is a 3-uple (subject, relation, object)
+
+* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
+  properties of a relation definition by using the named parameters of the properties
+  to change.
+
+* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
+  relation <rtype> of entity type <etype>.
+
+* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
+  for the relation <rtype> of entity type <etype>.
+
+Data migration
+--------------
+The following functions for data migration are available in `repository` scripts:
+
+* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
+  query, either to interrogate or update. A result set object is returned.
+
+* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given
+  type. The attribute and relation values are specified using the named and
+  positionned parameters.
+
+Workflow creation
+-----------------
+
+The following functions for workflow creation are available in `repository`
+scripts:
+
+* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
+  for a given type(s)
+
+You can find more details about workflows in the chapter :ref:`Workflow` .
+
+Configuration migration
+-----------------------
+
+The following functions for configuration migration are available in all
+scripts:
+
+* `option_renamed(oldname, newname)`, indicates that an option has been renamed
+
+* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
+  belong anymore to the same group.
+
+* `option_added(oldname, newname)`, indicates that an option has been added.
+
+* `option_removed(oldname, newname)`, indicates that an option has been deleted.
+
+
+Others migration functions
+--------------------------
+Those functions are only used for low level operations that could not be
+accomplished otherwise or to repair damaged databases during interactive
+session. They are available in `repository` scripts:
+
+* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
+* `add_entity_type_table(etype, commit=True)`
+* `add_relation_type_table(rtype, commit=True)`
+* `uninline_relation(rtype, commit=True)`
+
+
+[FIXME] Add explanation on how to use cubicweb-ctl shell
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/profiling.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,55 @@
+Profiling and performance
+=========================
+
+If you feel that one of your pages takes more time than it should to be
+generated, chances are that you're making too many RQL queries.  Obviously,
+there are other reasons but experience tends to show this is the first thing to
+track down. Luckily, CubicWeb provides a configuration option to log RQL
+queries. In your ``all-in-one.conf`` file, set the **query-log-file** option::
+
+    # web application query log file
+    query-log-file=~/myapp-rql.log
+
+Then restart your application, reload your page and stop your application.
+The file ``myapp-rql.log`` now contains the list of RQL queries that were
+executed during your test. It's a simple text file containing lines such as::
+
+    Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec)
+    Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec)
+
+The structure of each line is::
+
+    <RQL QUERY> <QUERY ARGS IF ANY> -- <TIME SPENT>
+
+CubicWeb also provides the **exlog** command to examine and summarize data found
+in such a file:
+
+.. sourcecode:: sh
+
+    $ cubicweb-ctl exlog < ~/myapp-rql.log
+    0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
+    0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
+    0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
+    0.01 1 Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s {, }
+    0.01 1 Any B,T,P ORDERBY lower(T) WHERE B is Bookmark,B title T, B path P, B bookmarked_by U, U eid %(x)s {}
+    0.01 1 Any A,B,C,D WHERE A eid %(x)s,A name B,A creation_date C,A modification_date D {}
+
+This command sorts and uniquifies queries so that it's easy to see where
+is the hot spot that needs optimization.
+
+Do not neglect to set the **fetch_attrs** attribute you can define in your
+entity classes because it can greatly reduce the number of queries executed (see
+:ref:`FetchAttrs`).
+
+You should also know about the **profile** option in the ``all-in-on.conf``. If
+set, this option will make your application run in an `hotshot`_ session and
+store the results in the specified file.
+
+.. _hotshot: http://docs.python.org/library/hotshot.html#module-hotshot
+
+Last but no least, if you're using the PostgreSQL database backend, VACUUMing
+your database can significantly improve the performance of the queries (by
+updating the statistics used by the query optimizer). Nowadays, this is done
+automatically from time to time, but if you've just imported a large amount of
+data in your db, you will want to vacuum it (with the analyse option on). Read
+the documentation of your database for more information.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/hooks.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,436 @@
+.. -*- coding: utf-8 -*-
+
+.. _hooks:
+
+Hooks and Operations
+====================
+
+Generalities
+------------
+
+Paraphrasing the `emacs`_ documentation, let us say that hooks are an
+important mechanism for customizing an application. A hook is
+basically a list of functions to be called on some well-defined
+occasion (this is called `running the hook`).
+
+.. _`emacs`: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
+
+In CubicWeb, hooks are subclasses of the Hook class in
+`server/hook.py`, implementing their own `call` method, and selected
+over a set of pre-defined `events` (and possibly more conditions,
+hooks being selectable AppObjects like views and components).
+
+There are two families of events: data events and server events. In a
+typical application, most of the Hooks are defined over data
+events.
+
+The purpose of data hooks is to complement the data model as defined
+in the schema.py, which is static by nature, with dynamic or value
+driven behaviours. It is functionally equivalent to a `database
+trigger`_, except that database triggers definition languages are not
+standardized, hence not portable (for instance, PL/SQL works with
+Oracle and PostgreSQL but not SqlServer nor Sqlite).
+
+.. _`database trigger`: http://en.wikipedia.org/wiki/Database_trigger
+
+Data hooks can serve the following purposes:
+
+* enforcing constraints that the static schema cannot express
+  (spanning several entities/relations, exotic value ranges and
+  cardinalities, etc.)
+
+* implement computed attributes
+
+Operations are Hook-like objects that may be created by Hooks and
+scheduled to happen just before (or after) the `commit` event. Hooks
+being fired immediately on data operations, it is sometime necessary
+to delay the actual work down to a time where all other Hooks have
+run, for instance a validation check which needs that all relations be
+already set on an entity. Also while the order of execution of Hooks
+is data dependant (and thus hard to predict), it is possible to force
+an order on Operations.
+
+Operations also may be used to process various side effects associated
+with a transaction such as filesystem udpates, mail notifications,
+etc.
+
+Operations are subclasses of the Operation class in `server/hook.py`,
+implementing `precommit_event` and other standard methods (wholly
+described in :ref:`operations_api`).
+
+Events
+------
+
+Hooks are mostly defined and used to handle `dataflow`_ operations. It
+means as data gets in (entities added, updated, relations set or
+unset), specific events are issued and the Hooks matching these events
+are called.
+
+.. _`dataflow`: http://en.wikipedia.org/wiki/Dataflow
+
+Below comes a list of the dataflow events related to entities operations:
+
+* before_add_entity
+
+* before_update_entity
+
+* before_delete_entity
+
+* after_add_entity
+
+* after_update_entity
+
+* after_delete_entity
+
+These define ENTTIES HOOKS. RELATIONS HOOKS are defined
+over the following events:
+
+* after_add_relation
+
+* after_delete_relation
+
+* before_add_relation
+
+* before_delete_relation
+
+This is an occasion to remind us that relations support the add/delete
+operation, but no update.
+
+Non data events also exist. These are called SYSTEM HOOKS.
+
+* server_startup
+
+* server_shutdown
+
+* server_maintenance
+
+* server_backup
+
+* server_restore
+
+* session_open
+
+* session_close
+
+
+Using dataflow Hooks
+--------------------
+
+Dataflow hooks either automate data operations or maintain the
+consistency of the data model. In the later case, we must use a
+specific exception named ValidationError
+
+Validation Errors
+~~~~~~~~~~~~~~~~~
+
+When a condition is not met in a Hook/Operation, it must raise a
+`ValidationError`. Raising anything but a (subclass of)
+ValidationError is a programming error. Raising a ValidationError
+entails aborting the current transaction.
+
+The ValidationError exception is used to convey enough information up
+to the user interface. Hence its constructor is different from the
+default Exception constructor. It accepts, positionally:
+
+* an entity eid,
+
+* a dict whose keys represent attribute (or relation) names and values
+  an end-user facing message (hence properly translated) relating the
+  problem.
+
+An entity hook
+~~~~~~~~~~~~~~
+
+We will use a very simple example to show hooks usage. Let us start
+with the following schema.
+
+.. sourcecode:: python
+
+   class Person(EntityType):
+       age = Int(required=True)
+
+We would like to add a range constraint over a person's age. Let's
+write an hook. It shall be placed into mycube/hooks.py. If this file
+were to grow too much, we can easily have a mycube/hooks/... package
+containing hooks in various modules.
+
+.. sourcecode:: python
+
+   from cubicweb import ValidationError
+   from cubicweb.selectors import implements
+   from cubicweb.server.hook import Hook
+
+   class PersonAgeRange(Hook):
+        __regid__ = 'person_age_range'
+        events = ('before_add_entity', 'before_update_entity')
+        __select__ = Hook.__select__ & implements('Person')
+
+        def __call__(self):
+            if 0 >= self.entity.age <= 120:
+               return
+            msg = self._cw._('age must be between 0 and 120')
+            raise ValidationError(self.entity.eid, {'age': msg})
+
+Hooks being AppObjects like views, they have a __regid__ and a
+__select__ class attribute. The base __select__ is augmented with an
+`implements` selector matching the desired entity type. The `events`
+tuple is used by the Hook.__select__ base selector to dispatch the
+hook on the right events. In an entity hook, it is possible to
+dispatch on any entity event (e.g. 'before_add_entity',
+'before_update_entity') at once if needed.
+
+Like all appobjects, hooks have the `self._cw` attribute which
+represents the current session. In entity hooks, a `self.entity`
+attribute is also present.
+
+
+A relation hook
+~~~~~~~~~~~~~~~
+
+Let us add another entity type with a relation to person (in
+mycube/schema.py).
+
+.. sourcecode:: python
+
+   class Company(EntityType):
+        name = String(required=True)
+        boss = SubjectRelation('Person', cardinality='1*')
+
+We would like to constrain the company's bosses to have a minimum
+(legal) age. Let's write an hook for this, which will be fired when
+the `boss` relation is established.
+
+.. sourcecode:: python
+
+   class CompanyBossLegalAge(Hook):
+        __regid__ = 'company_boss_legal_age'
+        events = ('before_add_relation',)
+        __select__ = Hook.__select__ & match_rtype('boss')
+
+        def __call__(self):
+            boss = self._cw.entity_from_eid(self.eidto)
+            if boss.age < 18:
+                msg = self._cw._('the minimum age for a boss is 18')
+                raise ValidationError(self.eidfrom, {'boss': msg})
+
+We use the `match_rtype` selector to select the proper relation type.
+
+The essential difference with respect to an entity hook is that there
+is no self.entity, but `self.eidfrom` and `self.eidto` hook attributes
+which represent the subject and object eid of the relation.
+
+
+Using Operations
+----------------
+
+Let's augment our example with a new `subsidiary_of` relation on Company.
+
+.. sourcecode:: python
+
+   class Company(EntityType):
+        name = String(required=True)
+        boss = SubjectRelation('Person', cardinality='1*')
+        subsidiary_of = SubjectRelation('Company', cardinality='*?')
+
+Base example
+~~~~~~~~~~~~
+
+We would like to check that there is no cycle by the `subsidiary_of`
+relation. This is best achieved in an Operation since all relations
+are likely to be set at commit time.
+
+.. sourcecode:: python
+
+    def check_cycle(self, session, eid, rtype, role='subject'):
+        parents = set([eid])
+        parent = session.entity_from_eid(eid)
+        while parent.related(rtype, role):
+            parent = parent.related(rtype, role)[0]
+            if parent.eid in parents:
+                msg = session._('detected %s cycle' % rtype)
+                raise ValidationError(eid, {rtype: msg})
+            parents.add(parent.eid)
+
+    class CheckSubsidiaryCycleOp(Operation):
+
+        def precommit_event(self):
+            check_cycle(self.session, self.eidto, 'subsidiary_of')
+
+
+    class CheckSubsidiaryCycleHook(Hook):
+        __regid__ = 'check_no_subsidiary_cycle'
+        events = ('after_add_relation',)
+        __select__ = Hook.__select__ & match_rtype('subsidiary_of')
+
+        def __call__(self):
+            CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
+
+The operation is instantiated in the Hook.__call__ method.
+
+An operation always takes a session object as first argument
+(accessible as `.session` from the operation instance), and optionally
+all keyword arguments needed by the operation. These keyword arguments
+will be accessible as attributes from the operation instance.
+
+Like in Hooks, ValidationError can be raised in Operations. Other
+exceptions are programming errors.
+
+Notice how our hook will instantiate an operation each time the Hook
+is called, i.e. each time the `subsidiary_of` relation is set.
+
+Using set_operation
+~~~~~~~~~~~~~~~~~~~
+
+There is an alternative method to schedule an Operation from a Hook,
+using the `set_operation` function.
+
+.. sourcecode:: python
+
+   from cubicweb.server.hook import set_operation
+
+   class CheckSubsidiaryCycleHook(Hook):
+       __regid__ = 'check_no_subsidiary_cycle'
+       events = ('after_add_relation',)
+       __select__ = Hook.__select__ & match_rtype('subsidiary_of')
+
+       def __call__(self):
+           set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto,
+                         CheckSubsidiaryCycleOp, rtype=self.rtype)
+
+   class CheckSubsidiaryCycleOp(Operation):
+
+       def precommit_event(self):
+           for eid in self._cw.transaction_data['subsidiary_cycle_detection']:
+               check_cycle(self.session, eid, self.rtype)
+
+Here, we call set_operation with a session object, a specially forged
+key, a value that is the actual payload of an individual operation (in
+our case, the object of the subsidiary_of relation) , the class of the
+Operation, and more optional parameters to give to the operation (here
+the rtype which do not vary accross operations).
+
+The body of the operation must then iterate over the values that have
+been mapped in the transaction_data dictionary to the forged key.
+
+This mechanism is especially useful on two occasions (not shown in our
+example):
+
+* massive data import (reduced memory consumption within a large
+  transaction)
+
+* when several hooks need to instantiate the same operation (e.g. an
+  entity and a relation hook).
+
+.. note::
+
+  A more realistic example can be found in the advanced tutorial
+  chapter :ref:`adv_tuto_security_propagation`.
+
+.. _operations_api:
+
+Operation: a small API overview
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: cubicweb.server.hook.Operation
+.. autoclass:: cubicweb.server.hook.LateOperation
+.. autofunction:: cubicweb.server.hook.set_operation
+
+Hooks writing rules
+-------------------
+
+Remainder
+~~~~~~~~~
+
+Never, ever use the `entity.foo = 42` notation to update an entity. It
+will not work.
+
+How to choose between a before and an after event ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before hooks give you access to the old attribute (or relation)
+values. By definition the database is not yet updated in a before
+hook.
+
+To access old and new values in an before_update_entity hook, one can
+use the `server.hook.entity_oldnewvalue` function which returns a
+tuple of the old and new values. This function takes an entity and an
+attribute name as parameters.
+
+In a 'before_add|update_entity' hook the self.entity contains the new
+values. One is allowed to further modify them before database
+operations, using the dictionary notation.
+
+.. sourcecode:: python
+
+   self.entity['age'] = 42
+
+This is because using self.entity.set_attributes(age=42) will
+immediately update the database (which does not make sense in a
+pre-database hook), and will trigger any existing
+before_add|update_entity hook, thus leading to infinite hook loops or
+such awkward situations.
+
+Beyond these specific cases, updating an entity attribute or relation
+must *always* be done using `set_attributes` and `set_relations`
+methods.
+
+(Of course, ValidationError will always abort the current transaction,
+whetever the event).
+
+Peculiarities of inlined relations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some relations are defined in the schema as `inlined` (see
+:ref:`RelationType` for details). In this case, they are inserted in
+the database at the same time as entity attributes.
+
+Hence in the case of before_add_relation, such relations already exist
+in the database.
+
+Edited attributes
+~~~~~~~~~~~~~~~~~
+
+On udpates, it is possible to ask the `entity.edited_attributes`
+variable whether one attribute has been updated.
+
+.. sourcecode:: python
+
+  if 'age' not in entity.edited_attribute:
+      return
+
+Deleted in transaction
+~~~~~~~~~~~~~~~~~~~~~~
+
+The session object has a deleted_in_transaction method, which can help
+writing deletion Hooks.
+
+.. sourcecode:: python
+
+   if self._cw.deleted_in_transaction(self.eidto):
+      return
+
+Given this predicate, we can avoid scheduling an operation.
+
+Disabling hooks
+~~~~~~~~~~~~~~~
+
+It is sometimes convenient to disable some hooks. For instance to
+avoid infinite Hook loops. One uses the `hooks_control` context
+manager.
+
+This can be controlled more finely through the `category` Hook class
+attribute, which is a string.
+
+.. sourcecode:: python
+
+   with hooks_control(self.session, self.session.HOOKS_ALLOW_ALL, <category>):
+       # ... do stuff
+
+.. autoclass:: cubicweb.server.session.hooks_control
+
+The existing categories are: ``email``, ``syncsession``,
+``syncschema``, ``bookmark``, ``security``, ``worfklow``,
+``metadata``, ``notification``, ``integrity``, ``activeintegrity``.
+
+Nothing precludes one to invent new categories and use the
+hooks_control context manager to filter them (in or out).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,13 @@
+.. -*- coding: utf-8 -*-
+
+Repository customization
+++++++++++++++++++++++++
+.. toctree::
+   :maxdepth: 1
+
+   sessions
+   hooks
+   notifications
+   tasks
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/notifications.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,6 @@
+.. -*- coding: utf-8 -*-
+
+Notifications management
+========================
+
+.. XXX FILLME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/sessions.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,27 @@
+.. -*- coding: utf-8 -*-
+
+Sessions
+========
+
+There are three kinds of sessions.
+
+* `user sessions` are the most common: they are related to users and
+  carry security checks coming with user credentials
+
+* `super sessions` are children of ordinary user sessions and allow to
+  bypass security checks (they are created by calling unsafe_execute
+  on a user session); this is often convenient in hooks which may
+  touch data that is not directly updatable by users
+
+* `internal sessions` have all the powers; they are also used in only a
+  few situations where you don't already have an adequate session at
+  hand, like: user authentication, data synchronisation in
+  multi-source contexts
+
+.. note::
+  Do not confuse the session type with their connection mode, for
+  instance : 'in memory' or 'pyro'.
+
+[WRITE ME]
+
+* authentication and management of sessions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/tasks.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Tasks
+=========
+
+[WRITE ME]
+
+* repository tasks
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/testing.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,258 @@
+.. -*- coding: utf-8 -*-
+
+Tests
+=====
+
+Unit tests
+----------
+
+The *CubicWeb* framework provides the `CubicWebTC` test base class in
+the module `cubicweb.devtools.testlib`.
+
+Tests shall be put into the mycube/test directory. Additional test
+data shall go into mycube/test/data.
+
+It is much advised to write tests concerning entities methods, hooks
+and operations, security. The CubicWebTC base class has convenience
+methods to help test all of this.
+
+.. note::
+
+  In the realm of views, there is not much to do but check that the
+  views are valid XHTML.  See :ref:`automatic_views_tests` for
+  details. Integration of CubicWeb tests with UI testing tools such as
+  `selenium`_ are currently under invesitgation.
+
+.. _selenium: http://seleniumhq.org/projects/ide/
+
+Most unit tests need a live database to work against. This is achieved
+by CubicWeb using automatically sqlite (bundled with Python, see
+http://docs.python.org/library/sqlite3.html) as a backend.
+
+The database is stored in the mycube/test/tmpdb,
+mycube/test/tmpdb-template files. If it does not (yet) exists, it will
+be built automatically when the test suit starts.
+
+.. warning::
+
+  Whenever the schema changes (new entities, attributes, relations)
+  one must delete these two files. Changes concerned only with entity
+  or relation type properties (constraints, cardinalities,
+  permissions) and generally dealt with using the
+  `sync_schema_props_perms()` fonction of the migration environment
+  need not a database regeneration step.
+
+Unit test by example
+````````````````````
+
+We start with an example extracted from the keyword cube (available
+from http://www.cubicweb.org/project/cubicweb-keyword).
+
+.. sourcecode:: python
+
+    from cubicweb.devtools.testlib import CubicWebTC
+    from cubicweb import ValidationError
+
+    class ClassificationHooksTC(CubicWebTC):
+
+        def setup_database(self):
+            req = self.request()
+            group_etype = req.execute('Any X WHERE X name "CWGroup"').get_entity(0,0)
+            c1 = req.create_entity('Classification', name=u'classif1',
+                                   classifies=group_etype)
+            user_etype = req.execute('Any X WHERE X name "CWUser"').get_entity(0,0)
+            c2 = req.create_entity('Classification', name=u'classif2',
+                                   classifies=user_etype)
+            self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1)
+            self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2)
+
+        def test_cannot_create_cycles(self):
+            # direct obvious cycle
+            self.assertRaises(ValidationError, self.kw1.set_relations,
+                              subkeyword_of=self.kw1)
+            # testing indirect cycles
+            kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
+                               'SK subkeyword_of K WHERE C name "classif1", K eid %s'
+                               % self.kw1.eid).get_entity(0,0)
+            self.kw1.set_relations(subkeyword_of=kw3)
+            self.assertRaises(ValidationError, self.commit)
+
+The test class defines a `setup_database` method which populates the
+database with initial data. Each test of the class runs with this
+pre-populated database.
+
+The test case itself checks that an Operation does it job of
+preventing cycles amongst Keyword entities.
+
+You can see an example of security tests in the
+:ref:`adv_tuto_security`.
+
+It is possible to have these tests run continuously using `apycot`_.
+
+.. _apycot: http://www.logilab.org/project/apycot
+
+Managing connections or users
++++++++++++++++++++++++++++++
+
+Since unit tests are done with the SQLITE backend and this does not
+support multiple connections at a time, you must be careful when
+simulating security, changing users.
+
+By default, tests run with a user with admin privileges. This
+user/connection must never be closed.
+
+Before a self.login, one has to release the connection pool in use
+with a self.commit, self.rollback or self.close.
+
+The `login` method returns a connection object that can be used as a
+context manager:
+
+.. sourcecode:: python
+
+   with self.login('user1') as user:
+       req = user.req
+       req.execute(...)
+
+On exit of the context manager, either a commit or rollback is issued,
+which releases the connection.
+
+When one is logged in as a normal user and wants to switch back to the
+admin user without committing, one has to use
+self.restore_connection().
+
+Usage with restore_connection:
+
+.. sourcecode:: python
+
+    # execute using default admin connection
+    self.execute(...)
+    # I want to login with another user, ensure to free admin connection pool
+    # (could have used rollback but not close here
+    # we should never close defaut admin connection)
+    self.commit()
+    cnx = self.login('user')
+    # execute using user connection
+    self.execute(...)
+    # I want to login with another user or with admin user
+    self.commit();  cnx.close()
+    # restore admin connection, never use cnx = self.login('admin'), it will return
+    # the default admin connection and one may be tempted to close it
+    self.restore_connection()
+
+.. warning::
+
+   Do not use the references kept to the entities created with a
+   connection from another !
+
+Email notifications tests
+-------------------------
+
+When running tests potentially generated e-mails are not really sent
+but is found in the list `MAILBOX` of module
+`cubicweb.devtools.testlib`.
+
+You can test your notifications by analyzing the contents of this list, which
+contains objects with two attributes:
+
+* `recipients`, the list of recipients
+* `msg`, object email.Message
+
+Let us look at simple example from the ``blog`` cube.
+
+.. sourcecode:: python
+
+    from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
+
+    class BlogTestsCubicWebTC(CubicWebTC):
+        """test blog specific behaviours"""
+
+        def test_notifications(self):
+            req = self.request()
+            cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
+                                description=u'cubicweb is beautiful')
+            blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
+                                             content=u'cubicweb hop')
+            blog_entry_1.set_relations(entry_of=cubicweb_blog)
+            blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
+                                             content=u'cubicweb yes')
+            blog_entry_2.set_relations(entry_of=cubicweb_blog)
+            self.assertEquals(len(MAILBOX), 0)
+            self.commit()
+            self.assertEquals(len(MAILBOX), 2)
+            mail = MAILBOX[0]
+            self.assertEquals(mail.subject, '[data] hop')
+            mail = MAILBOX[1]
+            self.assertEquals(mail.subject, '[data] yes')
+
+.. _automatic_views_tests:
+
+Automatic views testing
+-----------------------
+
+This is done automatically with the AutomaticWebTest class. At cube
+creation time, the mycube/test/test_mycube.py file contains such a
+test. The code here has to be uncommented to be usable, without
+further modification.
+
+The ``auto_populate`` method uses a smart algorithm to create
+pseudo-random data in the database, thus enabling the views to be
+invoked and tested.
+
+Depending on the schema, hooks and operations constraints, it is not
+always possible for the automatic auto_populate to proceed.
+
+It is possible of course to completely redefine auto_populate. A
+lighter solution is to give hints (fill some class attributes) about
+what entities and relations have to be skipped by the auto_populate
+mechanism. These are:
+
+* `no_auto_populate`, may contain a list of entity types to skip
+* `ignored_relations`, may contain a list of relation types to skip
+* `application_rql`, may contain a list of rql expressions that
+  auto_populate cannot guess by itself; these must yield resultsets
+  against which views may be selected.
+
+
+Test APIS
+---------
+
+Using Pytest
+````````````
+
+The `pytest` utility (shipping with `logilab-common`_, which is a
+mandatory dependency of CubicWeb) extends the Python unittest
+functionality and is the preferred way to run the CubicWeb test
+suites. Bare unittests also work the usual way.
+
+.. _logilab-common: http://www.logilab.org/project/logilab-common
+
+To use it, you may:
+
+* just launch `pytest` in your cube to execute all tests (it will
+  discover them automatically)
+* launch `pytest unittest_foo.py` to execute one test file
+* launch `pytest unittest_foo.py bar` to execute all test methods and
+  all test cases whose name contain `bar`
+
+Additionally, the `-x` option tells pytest to exit at the first error
+or failure. The `-i` option tells pytest to drop into pdb whenever an
+exception occurs in a test.
+
+When the `-x` option has been used and the run stopped on a test, it
+is possible, after having fixed the test, to relaunch pytest with the
+`-R` option to tell it to start testing again from where it previously
+failed.
+
+Using the `TestCase` base class
+```````````````````````````````
+
+The base class of CubicWebTC is logilab.common.testlib.TestCase, which
+provides a lot of convenient assertion methods.
+
+.. autoclass:: logilab.common.testlib.TestCase
+   :members:
+
+CubicWebTC API
+``````````````
+.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
+   :members:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/vreg.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,107 @@
+The VRegistry, selectors and application objects
+================================================
+
+This chapter talks about core concepts of the |cubicweb| framework,
+that make it different from other frameworks (and maybe not easy to
+grasp at a first glance). To be able to do advanced development with
+|cubicweb| you need a good understanding of what is explained below.
+
+This chapter goes deep into details. You don't have to remember them
+all but keep it in mind so you can go back there later.
+
+An overview of AppObjects, the VRegistry and Selectors is given in the
+:ref:`VRegistryIntro` chapter.
+
+.. autodocstring:: cubicweb.cwvreg
+.. autodocstring:: cubicweb.selectors
+.. automodule:: cubicweb.appobject
+
+Base selectors
+--------------
+
+Selectors are scoring functions that are called by the registry to tell whenever
+an appobject can be selected in a given context. Selector sets are for instance
+the glue that tie views to the data model. Using them appropriately is an
+essential part of the construction of well behaved cubes.
+
+Of course you may have to write your own set of selectors as your needs grows and
+you get familiar with the framework (see :ref:`CustomSelectors`).
+
+Here is a description of generic selectors provided by CubicWeb that should suit
+most of your needs.
+
+Bare selectors
+~~~~~~~~~~~~~~
+Those selectors are somewhat dumb, which doesn't mean they're not (very) useful.
+
+.. autoclass:: cubicweb.appobject.yes
+.. autoclass:: cubicweb.selectors.match_kwargs
+.. autoclass:: cubicweb.selectors.appobject_selectable
+
+
+Result set selectors
+~~~~~~~~~~~~~~~~~~~~~
+Those selectors are looking for a result set in the context ('rset' argument or
+the input context) and match or not according to its shape. Some of these
+selectors have different behaviour if a particular cell of the result set is
+specified using 'row' and 'col' arguments of the input context or not.
+
+.. autoclass:: cubicweb.selectors.none_rset
+.. autoclass:: cubicweb.selectors.any_rset
+.. autoclass:: cubicweb.selectors.nonempty_rset
+.. autoclass:: cubicweb.selectors.empty_rset
+.. autoclass:: cubicweb.selectors.one_line_rset
+.. autoclass:: cubicweb.selectors.multi_lines_rset
+.. autoclass:: cubicweb.selectors.multi_columns_rset
+.. autoclass:: cubicweb.selectors.paginated_rset
+.. autoclass:: cubicweb.selectors.sorted_rset
+.. autoclass:: cubicweb.selectors.one_etype_rset
+.. autoclass:: cubicweb.selectors.multi_etypes_rset
+
+
+Entity selectors
+~~~~~~~~~~~~~~~~
+Those selectors are looking for either an `entity` argument in the input context,
+or entity found in the result set ('rset' argument or the input context) and
+match or not according to entity's (instance or class) properties.
+
+.. autoclass:: cubicweb.selectors.non_final_entity
+.. autoclass:: cubicweb.selectors.implements
+.. autoclass:: cubicweb.selectors.score_entity
+.. autoclass:: cubicweb.selectors.rql_condition
+.. autoclass:: cubicweb.selectors.relation_possible
+.. autoclass:: cubicweb.selectors.partial_relation_possible
+.. autoclass:: cubicweb.selectors.has_related_entities
+.. autoclass:: cubicweb.selectors.partial_has_related_entities
+.. autoclass:: cubicweb.selectors.has_permission
+.. autoclass:: cubicweb.selectors.has_add_permission
+
+
+Logged user selectors
+~~~~~~~~~~~~~~~~~~~~~
+Those selectors are looking for properties of the user issuing the request.
+
+.. autoclass:: cubicweb.selectors.anonymous_user
+.. autoclass:: cubicweb.selectors.authenticated_user
+.. autoclass:: cubicweb.selectors.match_user_groups
+
+
+Web request selectors
+~~~~~~~~~~~~~~~~~~~~~
+Those selectors are looking for properties of *web* request, they can not be
+used on the data repository side.
+
+.. autoclass:: cubicweb.selectors.match_form_params
+.. autoclass:: cubicweb.selectors.match_search_state
+.. autoclass:: cubicweb.selectors.match_context_prop
+.. autoclass:: cubicweb.selectors.match_view
+.. autoclass:: cubicweb.selectors.primary_view
+.. autoclass:: cubicweb.selectors.specified_etype_implements
+
+
+Other selectors
+~~~~~~~~~~~~~~~
+.. autoclass:: cubicweb.selectors.match_transition
+
+You'll also find some other (very) specific selectors hidden in other modules
+than :mod:`cubicweb.selectors`.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/controllers.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,201 @@
+.. _controllers:
+
+Controllers
+-----------
+
+Overview
+++++++++
+
+Controllers are responsible for taking action upon user requests
+(loosely following the terminology of the MVC meta pattern).
+
+The following controllers are provided out-of-the box in CubicWeb. We
+list them by category. They are all defined in
+(:mod:`cubicweb.web.views.basecontrollers`).
+
+`Browsing`:
+
+* the View controlleris associated with most browsing actions within a
+  CubicWeb application: it always instantiates a
+  :ref:`the_main_template` and lets the ResultSet/Views dispatch
+  system build up the whole content; it handles ObjectNotFound and
+  NoSelectableObject errors that may bubble up to its entry point, in
+  an end-user-friendly way (but other programming errors will slip
+  through)
+
+* the JSon controller (same module) provides services for Ajax calls,
+  typically using JSON as a serialization format for input, and
+  sometimes using either JSON or XML for output;
+
+* the Login/Logout controllers make effective user login or logout
+  requests
+
+`Edition`:
+
+* the Edit controller (see :ref:`edit_controller`) handles CRUD
+  operations in response to a form being submitted; it works in close
+  association with the Forms, to which it delegates some of the work
+
+* the Form validator controller provides form validation from Ajax
+  context, using the Edit controller, to implement the classic form
+  handling loop (user edits, hits 'submit/apply', validation occurs
+  server-side by way of the Form validator controller, and the UI is
+  decorated with failure information, either global or per-field ,
+  until it is valid)
+
+`Other`:
+
+* the SendMail controller (web/views/basecontrollers.py) is reponsible
+  for outgoing email notifications
+
+* the MailBugReport controller (web/views/basecontrollers.py) allows
+  to quickly have a `repotbug` feature in one's application
+
+Registration
+++++++++++++
+
+All controllers (should) live in the 'controllers' namespace within
+the global registry.
+
+API
++++
+
+Most API details should be resolved by source code inspection, as the
+various controllers have differing goals.
+
+`web/controller.py` contains the top-level abstract Controller class and
+its (NotImplemented) entry point `publish(rset=None)` method.
+
+A handful of helpers are also provided there:
+
+* process_rql builds a result set from an rql query typically issued
+  from the browser (and available through _cw.form['rql'])
+
+* validate_cache will force cache validation handling with respect to
+  the HTTP Cache directives (that were typically originally issued
+  from a previous server -> client response); concrete Controller
+  implementations dealing with HTTP (thus, for instance, not the
+  SendMail controller) may very well call this in their publication
+  process.
+
+
+.. _edit_controller:
+
+The `edit controller`
++++++++++++++++++++++
+
+It can be found in (:mod:`cubicweb.web.views.editcontroller`).
+
+Editing control
+~~~~~~~~~~~~~~~~
+
+.. XXX this look obsolete
+
+The parameters related to entities to edit are specified as follows ::
+
+  <field name>:<entity eid>
+
+where entity eid could be a letter in case of an entity to create. We
+name those parameters as *qualified*.
+
+1. Retrieval of entities to edit by looking for the forms parameters
+   starting by `eid:` and also having a parameter `__type` associated
+   (also *qualified* by eid)
+
+2. For all the attributes and the relations of an entity to edit:
+
+   1. search for a parameter `edits-<relation name>` or `edito-<relation name>`
+      qualified in the case of a relation where the entity is object
+   2. if found, the value returned is considered as the initial value
+      for this relaiton and we then look for the new value(s)  in the parameter
+      <relation name> (qualified)
+   3. if the value returned is different from the initial value, an database update
+      request is done
+
+3. For each entity to edit:
+
+   1. if a qualified parameter `__linkto` is specified, its value has to be
+      a string (or a list of string) such as: ::
+
+        <relation type>:<eids>:<target>
+
+      where <target> is either `subject` or `object` and each eid could be
+      separated from the others by a `_`. Target specifies if the *edited entity*
+      is subject or object of the relation and each relation specified will
+      be inserted.
+
+    2. if a qualified parameter `__clone_eid` is specified for an entity, the
+       relations of the specified entity passed as value of this parameter are
+       copied on the edited entity.
+
+    3. if a qualified parameter `__delete` is specified, its value must be
+       a string or a list of string such as follows: ::
+
+          <ssubjects eids>:<relation type>:<objects eids>
+
+       where each eid subject or object can be seperated from the other
+       by `_`. Each relation specified will be deleted.
+
+    4. if a qualified parameter `__insert` is specified, its value should
+       follow the same pattern as `__delete`, but each relation specified is
+       inserted.
+
+4. If the parameters `__insert` and/or `__delete` are found not qualified,
+   they are interpreted as explained above (independantly from the number
+   of entities edited).
+
+5. If no entity is edited but the form contains the parameters `__linkto`
+   and `eid`, this one is interpreted by using the value specified for `eid`
+   to designate the entity on which to add the relations.
+
+
+.. note::
+
+   * If the parameter `__action_delete` is found, all the entities specified
+     as to be edited will be deleted.
+
+   * If the parameter `__action_cancel` is found, no action is completed.
+
+   * If the parameter `__action_apply` is found, the editing is
+     applied normally but the redirection is done on the form (see
+     :ref:`RedirectionControl`).
+
+   * The parameter `__method` is also supported as for the main template
+
+   * If no entity is found to be edited and if there is no parameter
+     `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or
+     `__insert`, an error is raised.
+
+   * Using the parameter `__message` in the form will allow to use its value
+     as a message to provide the user once the editing is completed.
+
+
+.. _RedirectionControl:
+
+Redirection control
+~~~~~~~~~~~~~~~~~~~
+Once editing is completed, there is still an issue left: where should we go
+now? If nothing is specified, the controller will do his job but it does not
+mean we will be happy with the result. We can control that by using the
+following parameters:
+
+* `__redirectpath`: path of the URL (relative to the root URL of the site,
+  no form parameters
+
+* `__redirectparams`: forms parameters to add to the path
+
+* `__redirectrql`: redirection RQL request
+
+* `__redirectvid`: redirection view identifier
+
+* `__errorurl`: initial form URL, used for redirecting in case a validation
+  error is raised during editing. If this one is not specified, an error page
+  is displayed instead of going back to the form (which is, if necessary,
+  responsible for displaying the errors)
+
+* `__form_id`: initial view form identifier, used if `__action_apply` is
+  found
+
+In general we use either `__redirectpath` and `__redirectparams` or
+`__redirectrql` and `__redirectvid`.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/css.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,30 @@
+.. -*- coding: utf-8 -*-
+
+CSS Stylesheet
+---------------
+Conventions
+~~~~~~~~~~~
+
+.. XXX external_resources variable
+..    naming convention
+..    request.add_css
+
+
+Extending / overriding existing styles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We cannot modify the order in which the application is reading the CSS. In
+the case we want to create new CSS style, the best is to define it a in a new
+CSS located under ``myapp/data/`` and use those new styles while writing
+customized views and templates.
+
+If you want to modify an existing CSS styling property, you will have to use
+``!important`` declaration to override the existing property. The application
+apply a higher priority on the default CSS and you can not change that.
+Customized CSS will not be read first.
+
+
+CubicWeb stylesheets
+~~~~~~~~~~~~~~~~~~~~
+
+.. XXX explain diffenrent files and main classes
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/facets.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,172 @@
+The facets system
+-----------------
+
+Facets allow to restrict searches according to some criteria. CubicWeb
+has a builtin `facet`_ system to define restrictions `filters`_ really
+as easily as possible. A few base classes for facets are provided in
+``cubicweb.web.facet.py``. All classes inherits from the base class
+``AbstractFacet``.
+
+Here is an overview of the facets rendering pick from the `tracker` cube:
+
+.. image:: ../images/facet_overview.png
+
+Facets will appear on each page presenting more than one entity.
+
+
+
+VocabularyFacet
+~~~~~~~~~~~~~~~~
+The ``VocabularyFacet`` inherits from the ``AbstractFacet``.
+A class which inherits from VocabularyFacets must redefine these methods:
+
+.. automethod:: cubicweb.web.facet.VocabularyFacet.vocabulary
+.. automethod:: cubicweb.web.facet.VocabularyFacet.possible_values
+
+RelationFacet
+~~~~~~~~~~~~~~
+
+The ``RelationFacet`` inherits from the ``VocabularyFacet``. It allows to filter entities according to certain relation's values. Generally, you just have to define some class attributes like:
+
+- rtype: the name of the relation
+- role: the default value is set to `subject`
+- target_attr: needed if it is not the default attribute of the entity
+
+
+To illustrate this facet, let's take for example an *excerpt* of the schema of an office location search application:
+
+.. sourcecode:: python
+
+  class Office(WorkflowableEntityType):
+      price = Int(description='euros / m2 / HC / HT')
+      surface = Int(description='m2')
+      description = RichString(fulltextindexed=True)
+      has_address = SubjectRelation('PostalAddress',
+                                    cardinality='1?',
+                                    composite='subject')
+      proposed_by = SubjectRelation('Agency')
+      comments = ObjectRelation('Comment',
+                                cardinality='1*',
+                                composite='object')
+      screenshots = SubjectRelation(('File', 'Image'),
+                                    cardinality='*1',
+                                    composite='subject')
+
+
+We define a facet to filter offices according to the attribute
+`postalcode` of their associated `PostalAdress`.
+
+.. sourcecode:: python
+
+  class PostalCodeFacet(RelationFacet):
+      __regid__ = 'postalcode-facet'      # every registered class must have an id
+      __select__ = implements('Office')   # this facet should only be selected when
+                                          # visualizing offices
+      rtype = 'has_address'               # this facet is a filter on the entity linked to
+                                          # the office thrhough the relation
+                                          # has_address
+      target_attr = 'postalcode'          # the filter's key is the attribute "postal_code"
+                                          # of the target PostalAddress entity
+
+
+AttributeFacet
+~~~~~~~~~~~~~~
+
+The ``AttributeFacet`` inherits from the ``RelationFacet``. It allows to filter entities according to certain attribute's values.
+
+The example below resumes the former schema. We define now a filter based on the `surface` attribute of the
+`Office`.
+
+.. sourcecode:: python
+
+  class SurfaceFacet(AttributeFacet):
+      __regid__ = 'surface-facet'       # every registered class must have an id
+      __select__ = implements('Office') # this facet should only be selected when
+                                        # visualizing offices
+      rtype = 'surface'                 # the filter's key is the attribute "surface"
+      comparator = '>='                 # override the default value of operator since
+                                        # we want to filter according to a
+                                        # minimal
+                                        # value, not an exact one
+
+      def rset_vocabulary(self, ___):
+          """override the default vocabulary method since we want to hard-code
+          our threshold values.
+          Not overriding would generate a filter box with all existing surfaces
+          defined in the database.
+          """
+          return [('> 200', '200'), ('> 250', '250'),
+                  ('> 275', '275'), ('> 300', '300')]
+
+RangeFacet
+~~~~~~~~~~
+The ``RangeFacet`` inherits from the ``AttributeFacet``. It allows to filter entities according to certain attributes of numerical type.
+
+The ``RangeFacet`` displays a slider using `jquery`_ to choose a lower bound and an upper bound.
+
+The example below defines a facet to filter a selection of books according to their number of pages.
+
+.. sourcecode:: python
+
+   class BookPagesFacet(RangeFacet):
+       __regid__ = 'priority-facet'
+       __select__ = RangeFacet.__select__ & implements('Book')
+       rtype = 'pages'
+
+The image below display the rendering of the ``RangeFacet``:
+
+.. image:: ../images/facet_range.png
+
+DateRangeFacet
+~~~~~~~~~~~~~~
+The ``DateRangeFacet`` inherits from the ``RangeFacet``. It allows to filter entities according to certain attributes of date type.
+
+Here is an example of code that defines a facet to filter
+musical works according to their composition date:
+
+.. sourcecode:: python
+
+    class CompositionDateFacet(DateRangeFacet):
+        # 1. make sure this facet is displayed only on Track selection
+        __select__ = DateRangeFacet.__select__ & implements('Track')
+        # 2. give the facet an id required by CubicWeb)
+        __regid__ = 'compdate-facet'
+        # 3. specify the attribute name that actually stores the date in the DB
+        rtype = 'composition_date'
+
+With this facet, on each page displaying tracks, you'll be able to filter them
+according to their composition date with a jquery slider.
+
+The image below display the rendering of the ``DateRangeFacet``:
+
+.. image:: ../images/facet_date_range.png
+
+
+HasRelationFacet
+~~~~~~~~~~~~~~~~
+
+The ``DateRangeFacet`` inherits from the ``AbstractFacet``. It will
+display a simple checkbox and lets you refine your selection in order
+to get only entities that actually use this relation.
+
+Here is an example of the rendering of the ``HasRelationFacet`` to
+filter entities with image and the corresponding code:
+
+.. image:: ../images/facet_has_image.png
+
+.. sourcecode:: python
+
+  class HasImageFacet(HasRelationFacet):
+      __regid__ = 'hasimage-facet'
+      __select__ = HasRelationFacet.__select__ & implements('Book')
+      rtype = 'has_image'
+
+
+
+To use ``HasRelationFacet`` on a reverse relation add ``role = 'object'`` in
+it's definitions.
+
+.. _facet: http://en.wikipedia.org/wiki/Faceted_browser
+.. _filters: http://www.cubicweb.org/blogentry/154152
+.. _jquery: http://www.jqueryui.com/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/form.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,213 @@
+HTML form construction
+----------------------
+
+CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
+to provide generic building blocks which will greatly help you in building forms
+properly integrated with CubicWeb (coherent display, error handling, etc...),
+while keeping things as flexible as possible.
+
+A **form** basically only holds a set of **fields**, and has te be bound to a
+**renderer** which is responsible to layout them. Each field is bound to a
+**widget** that will be used to fill in value(s) for that field (at form
+generation time) and 'decode' (fetch and give a proper Python type to) values
+sent back by the browser.
+
+The **field** should be used according to the type of what you want to edit.
+E.g. if you want to edit some date, you'll have to use the
+:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple
+widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a
+bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
+calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
+calendar).  You can of course also write your own widget.
+
+
+.. automodule:: cubicweb.web.formfields
+.. automodule:: cubicweb.web.formwidgets
+.. automodule:: cubicweb.web.views.forms
+.. automodule:: cubicweb.web.views.autoform
+.. automodule:: cubicweb.web.views.formrenderers
+
+
+Now what ? Example of bare fields form
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We want to define a form doing something else than editing an entity. The idea is
+to propose a form to send an email to entities in a resultset which implements
+:class:`IEmailable`.  Let's take a simplified version of what you'll find in
+:mod:`cubicweb.web.views.massmailing`.
+
+Here is the source code:
+
+.. sourcecode:: python
+
+    def sender_value(form):
+	return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
+
+    def recipient_choices(form, field):
+	return [(e.get_email(), e.eid) for e in form.cw_rset.entities()
+		 if e.get_email()]
+
+    def recipient_value(form):
+	return [e.eid for e in form.cw_rset.entities() if e.get_email()]
+
+    class MassMailingForm(forms.FieldsForm):
+	__regid__ = 'massmailing'
+
+	needs_js = ('cubicweb.widgets.js',)
+	domid = 'sendmail'
+	action = 'sendmail'
+
+	sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
+				label=_('From:'),
+				value=sender_value)
+
+	recipient = ff.StringField(widget=CheckBox(),
+	                           label=_('Recipients:'),
+				   choices=recipient_choices,
+				   value=recipients_value)
+
+	subject = ff.StringField(label=_('Subject:'), max_length=256)
+
+	mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
+						    inputid='mailbody'))
+
+	form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
+				  _('send email'), 'SEND_EMAIL_ICON'),
+			ImgButton('cancelbutton', "javascript: history.back()",
+				  stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
+
+Let's detail what's going on up there. Our form will hold four fields:
+
+* a sender field, which is disabled and will simply contains the user's name and
+  email
+
+* a recipients field, which will be displayed as a list of users in the context
+  result set with checkboxes so user can still choose who will receive his mailing
+  by checking or not the checkboxes. By default all of them will be checked since
+  field's value return a list containing same eids as those returned by the
+  vocabulary function.
+
+* a subject field, limited to 256 characters (hence we know a
+  :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
+  :class:`~cubicweb.web.formfields.StringField`)
+
+* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
+  and whose definition won't be shown here. Notice though that we tell this form
+  need this javascript file by using `needs_js`
+
+Last but not least, we add two buttons control: one to post the form using
+javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
+set to 'sendmail', which is our form DOM id as specified by its `domid`
+attribute), another to cancel the form which will go back to the previous page
+using another javascript call. Also we specify an image to use as button icon as a
+resource identifier (see :ref:`external_resources`) given as last argument to
+:class:`cubicweb.web.formwidgets.ImgButton`.
+
+To see this form, we still have to wrap it in a view. This is pretty simple:
+
+.. sourcecode:: python
+
+    class MassMailingFormView(form.FormViewMixIn, EntityView):
+	__regid__ = 'massmailing'
+	__select__ = implements(IEmailable) & authenticated_user()
+
+	def call(self):
+	    form = self._cw.vreg['forms'].select('massmailing', self._cw,
+	                                         rset=self.cw_rset)
+	    self.w(form.render())
+
+As you see, we simply define a view with proper selector so it only apply to a
+result set containing :class:`IEmailable` entities, and so that only users in the
+managers or users group can use it. Then in the `call()` method for this view we
+simply select the above form and write what its `.render()` method returns.
+
+When this form is submitted, a controller with id 'sendmail' will be called (as
+specified using `action`). This controller will be responsible to actually send
+the mail to specified recipients.
+
+Here is what it looks like:
+
+.. sourcecode:: python
+
+   class SendMailController(Controller):
+       __regid__ = 'sendmail'
+       __select__ = authenticated_user() & match_form_params('recipient', 'mailbody', 'subject')
+
+       def publish(self, rset=None):
+           body = self._cw.form['mailbody']
+           subject = self._cw.form['subject']
+           eids = self._cw.form['recipient']
+           # eids may be a string if only one recipient was specified
+           if isinstance(eids, basestring):
+               rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
+           else:
+               rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
+           recipients = list(rset.entities())
+           msg = format_mail({'email' : self._cw.user.get_email(),
+                              'name' : self._cw.user.dc_title()},
+                             recipients, body, subject)
+           if not self._cw.vreg.config.sendmails([(msg, recipients]):
+               msg = self._cw._('could not connect to the SMTP server')
+           else:
+               msg = self._cw._('emails successfully sent')
+           raise Redirect(self._cw.build_url(__message=msg))
+
+
+The entry point of a controller is the publish method. In that case we simply get
+back post values in request's `form` attribute, get user instances according
+to eids found in the 'recipient' form value, and send email after calling
+:func:`format_mail` to get a proper email message. If we can't send email or
+if we successfully sent email, we redirect to the index page with proper message
+to inform the user.
+
+Also notice that our controller has a selector that deny access to it to
+anonymous users (we don't want our instance to be used as a spam relay), but also
+check expected parameters are specified in forms. That avoids later defensive
+programming (though it's not enough to handle all possible error cases).
+
+To conclude our example, suppose we wish a different form layout and that existent
+renderers are not satisfying (we would check that first of course :). We would then
+have to define our own renderer:
+
+.. sourcecode:: python
+
+    class MassMailingFormRenderer(formrenderers.FormRenderer):
+        __regid__ = 'massmailing'
+
+        def _render_fields(self, fields, w, form):
+            w(u'<table class="headersform">')
+            for field in fields:
+                if field.name == 'mailbody':
+                    w(u'</table>')
+                    w(u'<div id="toolbar">')
+                    w(u'<ul>')
+                    for button in form.form_buttons:
+                        w(u'<li>%s</li>' % button.render(form))
+                    w(u'</ul>')
+                    w(u'</div>')
+                    w(u'<div>')
+                    w(field.render(form, self))
+                    w(u'</div>')
+                else:
+                    w(u'<tr>')
+                    w(u'<td class="hlabel">%s</td>' % self.render_label(form, field))
+                    w(u'<td class="hvalue">')
+                    w(field.render(form, self))
+                    w(u'</td></tr>')
+
+        def render_buttons(self, w, form):
+            pass
+
+We simply override the `_render_fields` and `render_buttons` method of the base form renderer
+to arrange fields as we desire it: here we'll have first a two columns table with label and
+value of the sender, recipients and subject field (form order respected), then form controls,
+then a div containing the textarea for the email's content.
+
+To bind this renderer to our form, we should add to our form definition above:
+
+.. sourcecode:: python
+
+    form_renderer_id = 'massmailing'
+
+
+.. Example of entity fields form
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/httpcaching.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,3 @@
+HTTP cache management
+---------------------
+XXX feedme
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,21 @@
+Web side development
+====================
+
+In this chapter, we will describe the core APIs for web development in
+the *CubicWeb* framework.
+
+.. toctree::
+   :maxdepth: 2
+
+   publisher
+   controllers
+   request
+   views/index
+   rtags
+   js
+   css
+   form
+   facets
+   internationalization
+..   property
+   httpcaching
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/internationalization.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,222 @@
+.. -*- coding: utf-8 -*-
+
+.. _internationalization:
+
+Internationalization
+---------------------
+
+Cubicweb fully supports the internalization of its content and interface.
+
+Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
+
+.. _`GNU gettext`: http://www.gnu.org/software/gettext/
+
+Cubicweb' internalization involves two steps:
+
+* in your Python code and cubicweb-tal templates : mark translatable strings
+
+* in your instance : handle the translation catalog, edit translations
+
+String internationalization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+User defined string
+```````````````````
+
+In the Python code and cubicweb-tal templates translatable strings can be
+marked in one of the following ways :
+
+ * by using the *built-in* function `_` ::
+
+     class PrimaryView(EntityView):
+         """the full view of an non final entity"""
+         __regid__ = 'primary'
+         title = _('primary')
+
+  OR
+
+ * by using the equivalent request's method ::
+
+     class NoResultView(View):
+         """default view when no result has been found"""
+         __regid__ = 'noresult'
+
+         def call(self, **kwargs):
+             self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
+                 % self._cw._('No result matching query'))
+
+The goal of the *built-in* function `_` is only **to mark the
+translatable strings**, it will only return the string to translate
+itself, but not its translation (it's actually another name for the
+`unicode` builtin).
+
+In the other hand the request's method `self._cw._` is also meant to
+retrieve the proper translation of translation strings in the
+requested language.
+
+Finally you can also use the `__` attribute of request object to get a
+translation for a string *which should not itself added to the catalog*,
+usually in case where the actual msgid is created by string interpolation ::
+
+  self._cw.__('This %s' % etype)
+
+In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
+messages catalogs.
+
+Translations in cubicweb-tal template can also be done with TAL tags
+`i18n:content` and `i18n:replace`.
+
+If you need to add messages on top of those that can be found in the source,
+you can create a file named `i18n/static-messages.pot`.
+
+You could put there messages not found in the python sources or
+overrides for some messages of used cubes.
+
+Generated string
+````````````````
+
+We do not need to mark the translation strings of entities/relations used by a
+particular instance's schema as they are generated automatically. String for
+various actions are also generated.
+
+For exemple the following schema ::
+
+  Class EntityA(EntityType):
+      relation_a2b = SubjectRelation('EntityB')
+
+  class EntityB(EntityType):
+      pass
+
+May generate the following message ::
+
+  add EntityA relation_a2b EntityB subject
+
+This message will be used in views of ``EntityA`` for creation of a new
+``EntityB`` with a preset relation ``relation_a2b`` between the current
+``EntityA`` and the new ``EntityB``. The opposite message ::
+
+  add EntityA relation_a2b EntityB object
+
+Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
+title of they respective creation form will be ::
+
+  creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
+
+  creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
+
+In the translated string you can use ``%(linkto)s`` for reference to the source
+``entity``.
+
+Handling the translation catalog
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once the internationalization is done in your code, you need to populate and
+update the translation catalog. Cubicweb provides the following commands for this
+purpose:
+
+
+* `i18ncubicweb` updates Cubicweb framework's translation
+  catalogs. Unless you actually work on the framework itself, you
+  don't need to use this command.
+
+* `i18ncube` updates the translation catalogs of *one particular cube*
+  (or of all cubes). After this command is executed you must update
+  the translation files *.po* in the "i18n" directory of your
+  cube. This command will of course not remove existing translations
+  still in use. It will mark unused translation but not remove them.
+
+* `i18ninstance` recompiles the translation catalogs of *one particular
+  instance* (or of all instances) after the translation catalogs of
+  its cubes have been updated. This command is automatically
+  called every time you create or update your instance. The compiled
+  catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
+  instance where `lang` is the language identifier ('en' or 'fr'
+  for exemple).
+
+
+Example
+```````
+
+You have added and/or modified some translation strings in your cube
+(after creating a new view or modifying the cube's schema for exemple).
+To update the translation catalogs you need to do:
+
+1. `cubicweb-ctl i18ncube <cube>`
+2. Edit the <cube>/i18n/xxx.po  files and add missing translations (empty `msgstr`)
+3. `hg ci -m "updated i18n catalogs"`
+4. `cubicweb-ctl i18ninstance <myinstance>`
+
+Editing po files
+~~~~~~~~~~~~~~~~
+
+Using a PO aware editor
+````````````````````````
+
+Many tools exist to help maintain .po (PO) files. Common editors or
+development environment provides modes for these. One can also find
+dedicated PO files editor, such as `poedit`_.
+
+.. _`poedit`:  http://www.poedit.net/
+
+While usage of such a tool is commendable, PO files are perfectly
+editable with a (unicode aware) plain text editor. It is also useful
+to know their structure for troubleshooting purposes.
+
+Structure of a PO file
+``````````````````````
+
+In this section, we selectively quote passages of the `GNU gettext`_
+manual chapter on PO files, available there::
+
+ http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
+
+One PO file entry has the following schematic structure::
+
+     white-space
+     #  translator-comments
+     #. extracted-comments
+     #: reference...
+     #, flag...
+     #| msgid previous-untranslated-string
+     msgid untranslated-string
+     msgstr translated-string
+
+
+A simple entry can look like this::
+
+     #: lib/error.c:116
+     msgid "Unknown system error"
+     msgstr "Error desconegut del sistema"
+
+It is also possible to have entries with a context specifier. They
+look like this::
+
+     white-space
+     #  translator-comments
+     #. extracted-comments
+     #: reference...
+     #, flag...
+     #| msgctxt previous-context
+     #| msgid previous-untranslated-string
+     msgctxt context
+     msgid untranslated-string
+     msgstr translated-string
+
+
+The context serves to disambiguate messages with the same
+untranslated-string. It is possible to have several entries with the
+same untranslated-string in a PO file, provided that they each have a
+different context. Note that an empty context string and an absent
+msgctxt line do not mean the same thing.
+
+Contexts and CubicWeb
+`````````````````````
+
+CubicWeb PO files have both non-contextual and contextual msgids.
+
+Contextual entries are automatically used in some cases. For instance,
+entity.dc_type(), eschema.display_name(req) or display_name(etype,
+req, form, context) methods/function calls will use them.
+
+It is also possible to explicitly use the with _cw.pgettext(context,
+msgid).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/js.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,355 @@
+.. -*- coding: utf-8 -*-
+
+Javascript
+----------
+
+*CubicWeb* uses quite a bit of javascript in its user interface and
+ships with jquery (1.3.x) and parts of the jquery UI library, plus a
+number of homegrown files and also other third party libraries.
+
+All javascript files are stored in cubicweb/web/data/. There are
+around thirty js files there. In a cube it goes to data/.
+
+Obviously one does not want javascript pieces to be loaded all at
+once, hence the framework provides a number of mechanisms and
+conventions to deal with javascript resources.
+
+Conventions
+~~~~~~~~~~~
+
+It is good practice to name cube specific js files after the name of
+the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
+
+.. XXX external_resources variable (which needs love)
+
+CubicWeb javascript API
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Javascript resources are typically loaded on demand, from views. The
+request object (available as self._cw from most application objects,
+for instance views and entities objects) has a few methods to do that:
+
+* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
+  javascript files and writes proper entries into the HTML header
+  section. The localfile parameter allows to declare resources which
+  are not from web/data (for instance, residing on a content delivery
+  network).
+
+* `add_onload(self, jscode)` which adds one raw javascript code
+  snippet inline in the html headers. This is quite useful for setting
+  up early jQuery(document).ready(...) initialisations.
+
+CubicWeb javascript events
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* ``server-response``: this event is triggered on HTTP responses (both
+  standard and ajax). The two following extra parameters are passed
+  to callbacks :
+
+  - ``ajax``: a boolean that says if the reponse was issued by an
+    ajax request
+
+  - ``node``: the DOM node returned by the server in case of an
+    ajax request, otherwise the document itself for standard HTTP
+    requests.
+
+Important AJAX APIS
+~~~~~~~~~~~~~~~~~~~
+
+* `asyncRemoteExec` and `remoteExec` are the base building blocks for
+  doing arbitrary async (resp. sync) communications with the server
+
+* `reloadComponent` is a convenience function to replace a DOM node
+  with server supplied content coming from a specific registry (this
+  is quite handy to refresh the content of some boxes for instances)
+
+* `jQuery.fn.loadxhtml` is an important extension to jQuery which
+  allows proper loading and in-place DOM update of xhtml views. It is
+  suitably augmented to trigger necessary events, and process CubicWeb
+  specific elements such as the facet system, fckeditor, etc.
+
+
+A simple example with asyncRemoteExec
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the python side, we have to extend the BaseController class. The
+@jsonize decorator ensures that the `return value` of the method is
+encoded as JSON data. By construction, the JSonController inputs
+everything in JSON format.
+
+.. sourcecode: python
+
+    from cubicweb.web.views.basecontrollers import JSonController, jsonize
+
+    @monkeypatch(JSonController)
+    @jsonize
+    def js_say_hello(self, name):
+        return u'hello %s' % name
+
+In the javascript side, we do the asynchronous call. Notice how it
+creates a `deferred` object. Proper treatment of the return value or
+error handling has to be done through the addCallback and addErrback
+methods.
+
+.. sourcecode: javascript
+
+    function asyncHello(name) {
+        var deferred = asyncRemoteExec('say_hello', name);
+        deferred.addCallback(function (response) {
+            alert(response);
+        });
+        deferred.addErrback(function (error) {
+            alert('something fishy happened');
+        });
+     }
+
+     function syncHello(name) {
+         alert( remoteExec('say_hello', name) );
+     }
+
+Anatomy of a reloadComponent call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`reloadComponent` allows to dynamically replace some DOM node with new
+elements. It has the following signature:
+
+* `compid` (mandatory) is the name of the component to be reloaded
+
+* `rql` (optional) will be used to generate a result set given as
+  argument to the selected component
+
+* `registry` (optional) defaults to 'components' but can be any other
+  valid registry name
+
+* `nodeid` (optional) defaults to compid + 'Component' but can be any
+  explicitly specified DOM node id
+
+* `extraargs` (optional) should be a dictionary of values that will be
+  given to the cell_call method of the component
+
+A simple reloadComponent example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server side implementation of `reloadComponent` is the
+js_component method of the JSonController.
+
+The following function implements a two-steps method to delete a
+standard bookmark and refresh the UI, while keeping the UI responsive.
+
+.. sourcecode:: javascript
+
+    function removeBookmark(beid) {
+        d = asyncRemoteExec('delete_bookmark', beid);
+        d.addCallback(function(boxcontent) {
+	    reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
+            document.location.hash = '#header';
+            updateMessage(_("bookmark has been removed"));
+         });
+    }
+
+`reloadComponent` is called with the id of the bookmark box as
+argument, no rql expression (because the bookmarks display is actually
+independant of any dataset context), a reference to the 'boxes'
+registry (which hosts all left, right and contextual boxes) and
+finally an explicit 'bookmarks_box' nodeid argument that stipulates
+the target DOM node.
+
+Anatomy of a loadxhtml call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
+proper loading and in-place DOM update of xhtml views. The existing
+`jQuery.load`_ function does not handle xhtml, hence the addition. The
+API of loadxhtml is roughly similar to that of `jQuery.load`_.
+
+.. _`jQuery.load`: http://api.jquery.com/load/
+
+
+* `url` (mandatory) should be a complete url (typically referencing
+  the JSonController, but this is not strictly mandatory)
+
+* `data` (optional) is a dictionary of values given to the
+  controller specified through an `url` argument; some keys may have a
+  special meaning depending on the choosen controller (such as `fname`
+  for the JSonController); the `callback` key, if present, must refer
+  to a function to be called at the end of loadxhtml (more on this
+  below)
+
+* `reqtype` (optional) specifies the request method to be used (get or
+  post); if the argument is 'post', then the post method is used,
+  otherwise the get method is used
+
+* `mode` (optional) is one of `replace` (the default) which means the
+  loaded node will replace the current node content, `swap` to replace
+  the current node with the loaded node, and `append` which will
+  append the loaded node to the current node content
+
+About the `callback` option:
+
+* it is called with two parameters: the current node, and a list
+  containing the loaded (and post-processed node)
+
+* whenever is returns another function, this function is called in
+  turn with the same parameters as above
+
+This mechanism allows callback chaining.
+
+
+A simple example with loadxhtml
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we are concerned with the retrieval of a specific view to be
+injected in the live DOM. The view will be of course selected
+server-side using an entity eid provided by the client side.
+
+.. sourcecode:: python
+
+    from cubicweb import typed_eid
+    from cubicweb.web.views.basecontrollers import JSonController, xhtmlize
+
+    @monkeypatch(JSonController)
+    @xhtmlize
+    def js_frob_status(self, eid, frobname):
+        entity = self._cw.entity_from_eid(typed_eid(eid))
+        return entity.view('frob', name=frobname)
+
+.. sourcecode:: javascript
+
+    function update_some_div(divid, eid, frobname) {
+        var params = {fname:'frob_status', eid: eid, frobname:frobname};
+        jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
+     }
+
+In this example, the url argument is the base json url of a cube
+instance (it should contain something like
+`http://myinstance/json?`). The actual JSonController method name is
+encoded in the `params` dictionary using the `fname` key.
+
+A more real-life example from CubicWeb
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A frequent use case of Web 2 applications is the delayed (or
+on-demand) loading of pieces of the DOM. This is typically achieved
+using some preparation of the initial DOM nodes, jQuery event handling
+and proper use of loadxhtml.
+
+We present here a skeletal version of the mecanism used in CubicWeb
+and available in web/views/tabs.py, in the `LazyViewMixin` class.
+
+.. sourcecode:: python
+
+    def lazyview(self, vid, rql=None):
+        """ a lazy version of wview """
+        w = self.w
+        self._cw.add_js('cubicweb.lazy.js')
+        urlparams = {'vid' : vid, 'fname' : 'view'}
+        if rql is not None:
+            urlparams['rql'] = rql
+        w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
+            vid, xml_escape(self._cw.build_url('json', **urlparams))))
+        w(u'</div>')
+        self._cw.add_onload(u"""
+            jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
+                   load_now('#lazy-%(vid)s');});"""
+            % {'event': 'load_%s' % vid, 'vid': vid})
+
+This creates a `div` with a specific event associated to it.
+
+The full version deals with:
+
+* optional parameters such as an entity eid, an rset
+
+* the ability to further reload the fragment
+
+* the ability to display a spinning wheel while the fragment is still
+  not loaded
+
+* handling of browsers that do not support ajax (search engines,
+  text-based browsers such as lynx, etc.)
+
+The javascript side is quite simple, due to loadxhtml awesomeness.
+
+.. sourcecode:: javascript
+
+    function load_now(eltsel) {
+        var lazydiv = jQuery(eltsel);
+        lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
+    }
+
+This is all significantly different of the previous `simple example`
+(albeit this example actually comes from real-life code).
+
+Notice how the `cubicweb:loadurl` is used to convey the url
+information. The base of this url is similar to the global javascript
+JSON_BASE_URL. According to the pattern described earlier,
+the `fname` parameter refers to the standard `js_view` method of the
+JSonController. This method renders an arbitrary view provided a view
+id (or `vid`) is provided, and most likely an rql expression yielding
+a result set against which a proper view instance will be selected.
+
+The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML
+in a specific cubicweb namespace. It is a means to pass information
+without breaking HTML nor XHTML compliance and without resorting to
+ungodly hacks.
+
+Given all this, it is easy to add a small nevertheless useful feature
+to force the loading of a lazy view (for instance, a very
+computation-intensive web page could be scinded into one fast-loading
+part and a delayed part).
+
+On the server side, a simple call to a javascript function is
+sufficient.
+
+.. sourcecode:: python
+
+    def forceview(self, vid):
+        """trigger an event that will force immediate loading of the view
+        on dom readyness
+        """
+        self._cw.add_onload("trigger_load('%s');" % vid)
+
+The browser-side definition follows.
+
+.. sourcecode:: javascript
+
+    function trigger_load(divid) {
+        jQuery('#lazy-' + divd).trigger('load_' + divid);
+    }
+
+
+
+
+.. XXX reloadComponent
+.. XXX userCallback / user_callback
+
+Javascript library: overview
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* jquery.* : jquery and jquery UI library
+
+* cubicweb.ajax.js : concentrates all ajax related facilities (it
+  extends jQuery with the loahxhtml function, provides a handfull of
+  high-level ajaxy operations like asyncRemoteExec, reloadComponent,
+  replacePageChunk, getDomFromResponse)
+
+* cubicweb.python.js : adds a number of practical extension to stdanrd
+  javascript objects (on Date, Array, String, some list and dictionary
+  operations), and a pythonesque way to build classes. Defines a
+  CubicWeb namespace.
+
+* cubicweb.htmlhelpers.js : a small bag of convenience functions used
+  in various other cubicweb javascript resources (baseuri, progress
+  cursor handling, popup login box, html2dom function, etc.)
+
+* cubicweb.widgets.js : provides a widget namespace and constructors
+  and helpers for various widgets (mainly facets and timeline)
+
+* cubicweb.edition.js : used by edition forms
+
+* cubicweb.preferences.js : used by the preference form
+
+* cubicweb.facets.js : used by the facets mechanism
+
+There is also javascript support for massmailing, gmap (google maps),
+fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
+AppEngine), flot (charts drawing), tabs and bookmarks.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/property.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,13 @@
+The property mecanism
+---------------------
+
+.. XXX CWProperty and co
+
+
+Property API
+~~~~~~~~~~~~
+.. XXX feed me
+
+Registering and using your own property
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. XXX feed me
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/publisher.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,65 @@
+.. _publisher:
+
+Publisher
+---------
+
+What happens when an HTTP request is issued ?
+
+The story begins with the ``CubicWebPublisher.main_publish``
+method. We do not get upper in the bootstrap process because it is
+dependant on the used HTTP library. With `twisted`_ however,
+``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the
+real entry point.
+
+.. _`twisted`: http://twistedmatrix.com/trac/
+
+What main_publish does:
+
+* get a controller id and a result set from the path (this is actually
+  delegated to the `urlpublisher` component)
+
+* the controller is then selected (if not, this is considered an
+  authorization failure and signaled as such) and called
+
+* then either a proper result is returned, in which case the
+  request/connection object issues a ``commit`` and returns the result
+
+* or error handling must happen:
+
+  * ``ValidationErrors`` pop up there and may lead to a redirect to a
+    previously arranged url or standard error handling applies
+  * an HTTP 500 error (`Internal Server Error`) is issued
+
+
+Now, let's turn to the controller. There are many of them in
+:mod:`cubicweb.web.views.basecontrollers`. We can just follow the
+default `view` controller that is selected on a `view` path. See the
+:ref:`controllers` chapter for more information on controllers.
+
+The `View` controller's entry point is the `publish` method. It does
+the following:
+
+* compute the `main` view to be applied, using either the given result
+  set or building one from a user provided rql string (`rql` and `vid`
+  can be forced from the url GET parameters), that is:
+
+    * compute the `vid` using the result set and the schema (see
+      `cubicweb.web.views.vid_from_rset`)
+    * handle all error cases that could happen in this phase
+
+* do some cache management chores
+
+* select a main template (typically `TheMainTemplate`, see chapter
+  :ref:`templates`)
+
+* call it with the result set and the computed view.
+
+What happens next actually depends on the template and the view, but
+in general this is the rendering phase.
+
+
+CubicWebPublisher API
+`````````````````````
+
+.. autoclass:: cubicweb.web.application.CubicWebPublisher
+   :members:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/request.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,79 @@
+The `Request` class (`cubicweb.web`)
+------------------------------------
+
+Overview
+````````
+
+A request instance is created when an HTTP request is sent to the web server.
+It contains informations such as form parameters, user authenticated, etc.
+
+**Globally, a request represents a user query, either through HTTP or not
+(we also talk about RQL queries on the server side for example).**
+
+An instance of `Request` has the following attributes:
+
+* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
+  user
+* `form`, dictionary containing the values of a web form
+* `encoding`, character encoding to use in the response
+
+But also:
+
+* `Session data handling`
+
+  * `session_data()`, returns a dictionary containing all the session data
+  * `get_session_data(key, default=None)`, returns a value associated to the given
+    key or the value `default` if the key is not defined
+  * `set_session_data(key, value)`, assign a value to a key
+  * `del_session_data(key)`,  suppress the value associated to a key
+
+*  `Cookies handling`
+
+  * `get_cookie()`, returns a dictionary containing the value of the header
+    HTTP 'Cookie'
+  * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
+    with a minimal 5 minutes length of duration by default (`maxage` = None
+    returns a *session* cookie which will expire when the user closes the browser
+    window)
+  * `remove_cookie(cookie, key)`, forces a value to expire
+
+* `URL handling`
+
+  * `url()`, returns the full URL of the HTTP request
+  * `base_url()`, returns the root URL of the web application
+  * `relative_path()`, returns the relative path of the request
+
+* `And more...`
+
+  * `set_content_type(content_type, filename=None)`, adds the header HTTP
+    'Content-Type'
+  * `get_header(header)`, returns the value associated to an arbitrary header
+    of the HTTP request
+  * `set_header(header, value)`, adds an arbitrary header in the response
+  * `cursor()` returns a RQL cursor on the session
+  * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
+  * `property_value(key)`, properties management (`CWProperty`)
+  * dictionary `data` to store data to share informations between components
+    *while a request is executed*
+
+Please note that this class is abstract and that a concrete implementation
+will be provided by the *frontend* web used (in particular *twisted* as of
+today). For the views or others that are executed on the server side,
+most of the interface of `Request` is defined in the session associated
+to the client.
+
+API
+```
+
+The elements we gave in overview for above are built in three layers,
+from ``cubicweb.req.RequestSessionBase``, ``cubicweb.dbapi.DBAPIRequest`` and
+``cubicweb.web.CubicWebRequestBase``.
+
+.. autoclass:: cubicweb.req.RequestSessionBase
+   :members:
+
+.. autoclass:: cubicweb.dbapi.DBAPIRequest
+   :members:
+
+.. autoclass:: cubicweb.web.request.CubicWebRequestBase
+   :members:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/rtags.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,21 @@
+Configuring the user interface
+------------------------------
+
+.. _relation_tags:
+
+Relation tags
+~~~~~~~~~~~~~
+.. automodule:: cubicweb.rtags
+
+.. _uicfg:
+
+The ``uicfg`` module
+~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+
+ The part of uicfg that deals with primary views is in the
+ :ref:`primary_view_configuration` chapter.
+
+.. automodule:: cubicweb.web.uicfg
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/basetemplates.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,115 @@
+.. -*- coding: utf-8 -*-
+
+.. |cubicweb| replace:: *CubicWeb*
+
+.. _templates:
+
+Templates
+=========
+
+Templates are the entry point for the |cubicweb| view system. As seen
+in :ref:`views_base_class`, there are two kinds of views: the
+templatable and non-templatable.
+
+Non-templatable views are standalone. They are responsible for all the
+details such as setting a proper content type (or mime type), the
+proper document headers, namespaces, etc. Examples are pure xml views
+such as RSS or Semantic Web views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked
+Data`_, etc.).
+
+.. _`SIOC`: http://sioc-project.org/
+.. _`DOAP`: http://trac.usefulinc.com/doap
+.. _`FOAF`: http://www.foaf-project.org/
+.. _`Linked Data`: http://linkeddata.org/
+
+Templatable views are not concerned with such pesky details. They
+leave it to the template. Conversely, the template's main job is to:
+
+* set up the proper document header and content type
+* define the general layout of a document
+* invoke adequate views in the various sections of the document
+
+
+Look at :mod:`cubicweb.web.views.basetemplates` and you will find the
+base templates used to generate (X)HTML for your application. The most
+important template there is `TheMainTemplate`.
+
+.. _the_main_template_layout:
+
+TheMainTemplate
+---------------
+
+.. _the_main_template_sections:
+
+Layout and sections
+```````````````````
+
+A page is composed as indicated on the schema below :
+
+.. image:: ../../images/main_template.png
+
+The sections dispatches specific views:
+
+* `header`: the rendering of the header is delegated to the
+  `htmlheader` view, whose default implementation can be found in
+  ``basetemplates.py`` and which does the following things:
+
+    * inject the favicon if there is one
+    * inject the global style sheets and javascript resources
+    * call and display a link to an rss component if there is one available
+
+  it also sets up the page title, and fills the actual
+  `header` section with top-level components, using the `header` view, which:
+
+    * tries to display a logo, the name of the application and the `breadcrumbs`
+    * provides a login status area
+    * provides a login box (hiden by default)
+
+* `left column`: this is filled with all selectable boxes matching the
+  `left` context (there is also a right column but nowadays it is
+  seldom used due to bad usability)
+
+* `contentcol`: this is the central column; it is filled with:
+
+    * the `rqlinput` view (hidden by default)
+    * the `applmessages` component
+    * the `contentheader` view which in turns dispatches all available
+      content navigation components having the `navtop` context (this
+      is used to navigate through entities implementing the IPrevNext
+      interface)
+    * the view that was given as input to the template's `call`
+      method, also dealing with pagination concerns
+    * the `contentfooter`
+
+* `footer`: adds all footer actions
+
+.. note::
+
+  How and why a view object is given to the main template is explained
+  in the :ref:`publisher` chapter.
+
+Class attributes
+````````````````
+
+We can also control certain aspects of the main template thanks to the following
+forms parameters:
+
+* `__notemplate`, if present (whatever the value assigned), only the content view
+  is returned
+* `__force_display`, if present and its value is not null, no navigation
+  whatever the number of entities to display
+* `__method`, if the result set to render contains only one entity and this
+  parameter is set, it refers to a method to call on the entity by passing it
+  the dictionary of the forms parameters, before going the classic way (through
+  step 1 and 2 described juste above)
+
+Other templates
+---------------
+
+Other standard templates include:
+
+* `login` and `logout`
+
+* `error-template` specializes TheMainTemplate to do proper end-user
+  output if an error occurs during the computation of TheMainTemplate
+  (it is a fallback view).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/baseviews.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,84 @@
+.. -*- coding: utf-8 -*-
+
+Base views
+----------
+
+*CubicWeb* provides a lot of standard views, that can be found in
+ :mod:`cubicweb.web.views` and :mod:`cubicweb.web.views.baseviews`.
+
+A certain number of views are used to build the web interface, which
+apply to one or more entities. Their identifier is what distinguish
+them from each others and the main ones are:
+
+HTML views
+~~~~~~~~~~
+
+Special views
+`````````````
+
+*noresult*
+    This view is the default view used when no result has been found
+    (e.g. empty result set).
+
+*final*
+    Display the value of a cell without trasnformation (in case of a non final
+    entity, we see the eid). Applicable on any result set.
+
+.. note::
+
+   `final` entities are merely attributes.
+
+*null*
+    This view is the default view used when nothing needs to be rendered.
+    It is always applicable.
+
+Entity views
+````````````
+
+*incontext, outofcontext*
+    Those are used to display a link to an entity, depending on the
+    entity having to be displayed in or out of context
+    (of another entity).  By default it respectively produces the
+    result of `textincontext` and `textoutofcontext` wrapped in a link
+    leading to the primary view of the entity.
+
+*oneline*
+    This view is used when we can't tell if the entity should be considered as
+    displayed in or out of context.  By default it produces the result of `text`
+    in a link leading to the primary view of the entity.
+
+List
+`````
+
+*list*
+    This view displays a list of entities by creating a HTML list (`<ul>`)
+    and call the view `listitem` for each entity of the result set.
+
+*listitem*
+    This view redirects by default to the `outofcontext` view.
+
+*sameetypelist*
+    This view displays a list of entities of the same type, in HTML section (`<div>`)
+    and call the view `sameetypelistitem` for each entity of the result set.
+
+*sameetypelistitem*
+    This view redirects by default to the `listitem` view.
+
+*csv*
+    This view applies to entity groups, which are individually
+    displayed using the `incontext` view. It displays each entity as a
+    coma separated list. It is NOT related to the well-known text file
+    format.
+
+Text entity views
+~~~~~~~~~~~~~~~~~
+
+*text*
+    This is the simplest text view for an entity. By default it returns the
+    result of the `.dc_title` method, which is cut to fit the
+    `navigation.short-line-size` property if necessary.
+
+*textincontext, textoutofcontext*
+    Similar to the `text` view, but called when an entity is considered out or
+    in context. By default it returns respectively the result of the
+    methods `.dc_title` and `.dc_long_title` of the entity.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/boxes.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,36 @@
+Boxes
+-----
+
+(:mod:`cubicweb.web.views.boxes`)
+
+*sidebox*
+  This view displays usually a side box of some related entities
+  in a primary view.
+
+The action box
+~~~~~~~~~~~~~~~
+
+The ``add_related`` is an automatic menu in the action box that allows to create
+an entity automatically related to the initial entity (context in
+which the box is displayed). By default, the links generated in this
+box are computed from the schema properties of the displayed entity,
+but it is possible to explicitly specify them thanks to the
+`cubicweb.web.uicfg.rmode` *relation tag*:
+
+* `link`, indicates that a relation is in general created pointing
+  to an existing entity and that we should not to display a link
+  for this relation
+
+* `create`, indicates that a relation is in general created pointing
+  to new entities and that we should display a link to create a new
+  entity and link to it automatically
+
+
+If necessary, it is possible to overwrite the method
+`relation_mode(rtype, targettype, x='subject')` to dynamically
+compute a relation creation category.
+
+Please note that if at least one action belongs to the `addrelated` category,
+the automatic behavior is desactivated in favor of an explicit behavior
+(e.g. display of `addrelated` category actions only).
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/breadcrumbs.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,58 @@
+Breadcrumbs
+-----------
+
+Breadcrumbs are a navigation component to help the user locate himself
+along a path of entities.
+
+Display
+~~~~~~~
+
+Breadcrumbs are displayed by default in the header section (see
+:ref:`the_main_template_sections`).  With the default main
+template, the header section is composed by the logo, the application
+name, breadcrumbs and, at the most right, the login box. Breadcrumbs
+are displayed just next to the application name, thus breadcrumbs
+begin with a separator.
+
+Here is the header section of the CubicWeb's forge:
+
+.. image:: ../../images/breadcrumbs_header.png
+
+There are three breadcrumbs components defined in
+:mod:`cubicweb.web.views.ibreadcrumbs`:
+
+- `BreadCrumbEntityVComponent`: displayed for a result set with one line
+  if the entity implements the ``IBreadCrumbs`` interface.
+- `BreadCrumbETypeVComponent`: displayed for a result set with more than
+  one line, but with all entities of the same type which implement the
+  ``IBreadCrumbs`` interface.
+- `BreadCrumbAnyRSetVComponent`: displayed for any other result set.
+
+Building breadcrumbs
+~~~~~~~~~~~~~~~~~~~~
+
+The ``IBreadCrumbs`` interface is defined in the
+:mod:`cubicweb.interfaces` module. It specifies that an entity which
+implements this interface must have a ``breadcrumbs`` method.
+
+.. note::
+
+   Redefining the breadcrumbs is the hammer way to do it. Another way
+   is to define the `parent` method on an entity (as defined in the
+   `ITree` interface). If available, it will be used to compute
+   breadcrumbs.
+
+Here is the API of the ``breadcrumbs`` method:
+
+.. automethod:: cubicweb.interfaces.IBreadCrumbs.breadcrumbs
+
+If the breadcrumbs method return a list of entities, the
+``cubicweb.web.views.ibreadcrumbs.BreadCrumbView`` is used to display
+the elements.
+
+By default, for any entity, if recurs=True, breadcrumbs method returns
+a list of entities, else a list of a simple string.
+
+In order to see a hierarchical breadcrumbs, entities must have a
+``parent`` method which returns the parent entity. By default this
+method doesn't exist on entity, given that it can not be guessed.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/editforms.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,6 @@
+Standard forms
+--------------
+
+ (:mod:`cubicweb.web.views.editforms`)
+
+XXX feed me
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/embedding.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Embedding external pages
+------------------------
+
+(:mod:`cubicweb.web.views.embedding`)
+
+including external content
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/idownloadable.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,5 @@
+The 'download' view
+-------------------
+
+(:mod:`cubicweb.web.views.idownloadable`)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,30 @@
+The View system
+===============
+
+This chapter aims to describe the concept of a `view` used all along
+the development of a web application and how it has been implemented
+in |cubicweb|.
+
+
+.. toctree::
+   :maxdepth: 3
+
+   views
+   basetemplates
+   primary
+   baseviews
+   startup
+   boxes
+   table
+   xmlrss
+..   editforms
+
+.. toctree::
+   :maxdepth: 3
+
+   urlpublish
+   breadcrumbs
+..   wdoc
+..   embedding
+..   idownloadable
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/primary.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,314 @@
+.. _primary_view:
+
+The Primary View
+-----------------
+
+By default, *CubicWeb* provides a view that fits every available
+entity type. This is the first view you might be interested in
+modifying. It is also one of the richest and most complex.
+
+It is automatically selected on a one line result set containing an
+entity.
+
+This view is supposed to render a maximum of informations about the
+entity.
+
+It lives in the :mod:`cubicweb.web.views.primary` module.
+
+.. _primary_view_layout:
+
+Layout
+``````
+
+The primary view has the following layout.
+
+.. image:: ../../images/primaryview_template.png
+
+.. _primary_view_configuration:
+
+Primary view configuration
+``````````````````````````
+
+If you want to customize the primary view of an entity, overriding the primary
+view class may not be necessary. For simple adjustments (attributes or relations
+display locations and styles), a much simpler way is to use uicfg.
+
+Attributes/relations display location
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the primary view, there are 3 sections where attributes and
+relations can be displayed (represented in pink in the image above):
+
+* attributes
+* relations
+* sideboxes
+
+**Attributes** can only be displayed in the attributes section (default
+  behavior). They can also be hidden.
+
+For instance, to hide the ``title`` attribute of the ``Blog`` entity:
+
+.. sourcecode:: python
+
+   from cubicweb.web import uicfg
+   uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
+
+**Relations** can be either displayed in one of the three sections or hidden.
+
+For relations, there are two methods:
+
+* ``tag_object_of`` for modifying the primary view of the object
+* ``tag_subject_of`` for modifying the primary view of the subject
+
+These two methods take two arguments:
+
+* a triplet ``(subject, relation_name, object)``, where subject or object can be replaced with ``'*'``
+* the section name or ``hidden``
+
+.. sourcecode:: python
+
+   pv_section = uicfg.primaryview_section
+   # hide every relation `entry_of` in the `Blog` primary view
+   pv_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
+
+   # display `entry_of` relations in the `relations`
+   # section in the `BlogEntry` primary view
+   pv_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations')
+
+
+Display content
+^^^^^^^^^^^^^^^
+
+You can use ``primaryview_display_ctrl`` to customize the display of attributes
+or relations. Values of ``primaryview_display_ctrl`` are dictionaries.
+
+
+Common keys for attributes and relations are:
+
+* ``vid``: specifies the regid of the view for displaying the attribute or the relation.
+
+  If ``vid`` is not specified, the default value depends on the section:
+    * ``attributes`` section: 'reledit' view
+    * ``relations`` section: 'autolimited' view
+    * ``sideboxes`` section: 'sidebox' view
+
+* ``order``: int used to control order within a section. When not specified,
+  automatically set according to order in which tags are added.
+
+.. sourcecode:: python
+
+   # let us remind the schema of a blog entry
+   class BlogEntry(EntityType):
+       title = String(required=True, fulltextindexed=True, maxsize=256)
+       publish_date = Date(default='TODAY')
+       content = String(required=True, fulltextindexed=True)
+       entry_of = SubjectRelation('Blog', cardinality='?*')
+
+   # now, we want to show attributes
+   # with an order different from that in the schema definition
+   view_ctrl = uicfg.primaryview_display_ctrl
+   for index, attr in enumerate('title', 'content', 'publish_date'):
+       view_ctrl.tag_attribute(('BlogEntry', attr), {'order': index})
+
+Keys for relations only:
+
+* ``label``: label for the relations section or side box
+
+* ``showlabel``: boolean telling whether the label is displayed
+
+* ``limit``: boolean telling if the results should be limited. If so, a link to all results is displayed
+
+* ``filter``: callback taking the related result set as argument and returning it filtered
+
+.. sourcecode:: python
+
+   pv_section = uicfg.primaryview_section
+   # in `CWUser` primary view, display `created_by`
+   # relations in relations section
+   pv_section.tag_object_of(('*', 'created_by', 'CWUser'), 'relations')
+
+   # display this relation as a list, sets the label,
+   # limit the number of results and filters on comments
+   def filter_comment(rset):
+       return rset.filtered_rset(lambda x: x.e_schema == 'Comment')
+   pv_ctrl = uicfg.primaryview_display_ctrl
+   pv_ctrl.tag_object_of(('*', 'created_by', 'CWUser'),
+                         {'vid': 'list', 'label': _('latest comment(s):'),
+                          'limit': True,
+                          'filter': filter_comment})
+
+.. warning:: with the ``primaryview_display_ctrl`` rtag, the subject or the
+   object of the relation is ignored for respectively ``tag_object_of`` or
+   ``tag_subject_of``. To avoid warnings during execution, they should be set to
+   ``'*'``.
+
+Rendering methods and attributes
+````````````````````````````````
+
+The basic layout of a primary view is as in the
+:ref:`primary_view_layout` section. This layout is actually drawn by
+the `render_entity` method.
+
+The methods you may want to modify while customizing a ``PrimaryView``
+are:
+
+*render_entity_title(self, entity)*
+    Renders the entity title using the ``def dc_title(self)`` method.
+
+*render_entity_metadata(self, entity)*
+    Renders the entity metadata by calling the ``metadata`` view on the
+    entity. This generic view is in cubicweb.views.baseviews.
+
+*render_entity_attributes(self, entity)*
+    Renders all the attribute of an entity with the exception of
+    attribute of type `Password` and `Bytes`. The skip_none class
+    attribute controls the display of None valued attributes.
+
+*render_entity_relations(self, entity)*
+    Renders all the relations of the entity in the main section of the page.
+
+*render_side_boxes(self, entity, boxes)*
+    Renders relations of the entity in a side box.
+
+The placement of relations in the relations section or in side boxes
+can be controlled through the :ref:`primary_view_configuration` mechanism.
+
+*content_navigation_components(self, context)*
+    This method is applicable only for entity type implementing the interface
+    `IPrevNext`. This interface is for entities which can be linked to a previous
+    and/or next entity. This method will render the navigation links between
+    entities of this type, either at the top or at the bottom of the page
+    given the context (navcontent{top|bottom}).
+
+Also, please note that by setting the following attributes in your
+subclass, you can already customize some of the rendering:
+
+*show_attr_label*
+    Renders the attribute label next to the attribute value if set to True.
+    Otherwise, does only display the attribute value.
+
+*show_rel_label*
+    Renders the relation label next to the relation value if set to True.
+    Otherwise, does only display the relation value.
+
+*skip_none*
+    Does not render an attribute value that is None if set to True.
+
+*main_related_section*
+    Renders the relations of the entity if set to True.
+
+A good practice is for you to identify the content of your entity type for which
+the default rendering does not answer your need so that you can focus on the specific
+method (from the list above) that needs to be modified. We do not advise you to
+overwrite ``render_entity`` unless you want a completely different layout.
+
+Example of customization and creation
+`````````````````````````````````````
+
+We'll show you now an example of a ``primary`` view and how to customize it.
+
+We continue along the basic tutorial :ref:`tuto_blog`.
+
+If you want to change the way a ``BlogEntry`` is displayed, just
+override the method ``cell_call()`` of the view ``primary`` in
+``BlogDemo/views.py``.
+
+.. sourcecode:: python
+
+   from cubicweb.selectors import implements
+   from cubicweb.web.views.primary import Primaryview
+
+   class BlogEntryPrimaryView(PrimaryView):
+     __select__ = PrimaryView.__select__ & implements('BlogEntry')
+
+       def render_entity_attributes(self, entity):
+           self.w(u'<p>published on %s</p>' %
+                  entity.publish_date.strftime('%Y-%m-%d'))
+           super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
+
+
+The above source code defines a new primary view for
+``BlogEntry``. The `id` class attribute is not repeated there since it
+is inherited through the `primary.PrimaryView` class.
+
+The selector for this view chains the selector of the inherited class
+with its own specific criterion.
+
+The view method ``self.w()`` is used to output data. Here `lines
+08-09` output HTML for the publication date of the entry.
+
+.. image:: ../../images/lax-book_09-new-view-blogentry_en.png
+   :alt: blog entries now look much nicer
+
+Let us now improve the primary view of a blog
+
+.. sourcecode:: python
+
+ from logilab.mtconverter import xml_escape
+ from cubicweb.selectors import implements, one_line_rset
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogPrimaryView(PrimaryView):
+     __regid__ = 'primary'
+     __select__ = PrimaryView.__select__ & implements('Blog')
+     rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
+
+     def render_entity_relations(self, entity):
+         rset = self._cw.execute(self.rql, {'b' : entity.eid})
+         for entry in rset.entities():
+             self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
+
+ class BlogEntryInBlogView(EntityView):
+     __regid__ = 'inblogcontext'
+     __select__ = implements('BlogEntry')
+
+     def cell_call(self, row, col):
+         entity = self.cw_rset.get_entity(row, col)
+         self.w(u'<a href="%s" title="%s">%s</a>' %
+                entity.absolute_url(),
+                xml_escape(entity.content[:50]),
+                xml_escape(entity.description))
+
+This happens in two places. First we override the
+render_entity_relations method of a Blog's primary view. Here we want
+to display our blog entries in a custom way.
+
+At `line 10`, a simple request is made to build a result set with all
+the entities linked to the current ``Blog`` entity by the relationship
+``entry_of``. The part of the framework handling the request knows
+about the schema and infers that such entities have to be of the
+``BlogEntry`` kind and retrieves them (in the prescribed publish_date
+order).
+
+The request returns a selection of data called a result set. Result
+set objects have an .entities() method returning a generator on
+requested entities (going transparently through the `ORM` layer).
+
+At `line 13` the view 'inblogcontext' is applied to each blog entry to
+output HTML. (Note that the 'inblogcontext' view is not defined
+whatsoever in *CubicWeb*. You are absolutely free to define whole view
+families.) We juste arrange to wrap each blogentry output in a 'p'
+html element.
+
+Next, we define the 'inblogcontext' view. This is NOT a primary view,
+with its well-defined sections (title, metadata, attribtues,
+relations/boxes). All a basic view has to define is cell_call.
+
+Since views are applied to result sets which can be tables of data, we
+have to recover the entity from its (row,col)-coordinates (`line
+20`). Then we can spit some HTML.
+
+.. warning::
+
+  Be careful: all strings manipulated in *CubicWeb* are actually
+  unicode strings. While web browsers are usually tolerant to
+  incoherent encodings they are being served, we should not abuse
+  it. Hence we have to properly escape our data. The xml_escape()
+  function has to be used to safely fill (X)HTML elements from Python
+  unicode strings.
+
+Assuming we added entries to the blog titled `MyLife`, displaying it
+now allows to read its description and all its entries.
+
+.. image:: ../../images/lax-book_10-blog-with-two-entries_en.png
+   :alt: a blog and all its entries
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/startup.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,15 @@
+Startup views
+-------------
+
+(:mod:`cubicweb.web.views.startup`)
+
+The usual selectors are no_rset or yes. These views don't apply to a
+result set.
+
+*index*
+    This view defines the home page of your application. It does not require
+    a result set to apply to.
+
+*schema*
+    A view dedicated to the display of the schema of the instance
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/table.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,19 @@
+Table view
+----------
+
+(:mod:`cubicweb.web.views.tableview`)
+
+*table*
+    Creates a HTML table (`<table>`) and call the view `cell` for each cell of
+    the result set. Applicable on any result set.
+
+*cell*
+    By default redirects to the `final` view if this is a final entity or
+    `outofcontext` view otherwise
+
+
+API
+```
+
+.. autoclass:: cubicweb.web.views.tableview.TableView
+   :members:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/urlpublish.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,73 @@
+.. -*- coding: utf-8 -*-
+
+URL publishing
+--------------
+
+(:mod:`cubicweb.web.views.urlpublishing`)
+
+.. automodule:: cubicweb.web.views.urlpublishing
+
+.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent
+   :members:
+
+URL rewriting
+-------------
+
+(:mod:`cubicweb.web.views.urlrewrite`)
+
+.. autoclass:: cubicweb.web.views.urlrewrite.URLRewriter
+   :members:
+
+.. autoclass:: cubicweb.web.views.urlrewrite.SimpleReqRewriter
+   :members:
+
+.. autoclass:: cubicweb.web.views.urlrewrite.SchemaBasedRewriter
+   :members:
+
+
+``SimpleReqRewriter`` is enough for a certain number of simple cases. If it is not sufficient, ``SchemaBasedRewriter`` allows to do more elaborate things.
+
+Here is an example of ``SimpleReqRewriter`` usage with plain string:
+
+.. sourcecode:: python
+
+   from cubicweb.web.views.urlrewrite import SimpleReqRewriter
+   class TrackerSimpleReqRewriter(SimpleReqRewriter):
+       rules = [
+        ('/versions', dict(vid='versionsinfo')),
+        ]
+
+When the url is `<base_url>/versions`, the view with the __regid__ `versionsinfo` is displayed.
+
+Here is an example of ``SimpleReqRewriter`` usage with regular expressions:
+
+.. sourcecode:: python
+
+    from cubicweb.web.views.urlrewrite import (
+        SimpleReqRewriter, rgx)
+
+    class BlogReqRewriter(SimpleReqRewriter):
+        rules = [
+            (rgx('/blogentry/([a-z_]+)\.rss'),
+             dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
+                       'X creation_date CD, X created_by U, '
+                       'U login "%(user)s"'
+                       % {'user': r'\1'}, vid='rss'))),
+            ]
+
+When a url matches the regular expression, the view with the __regid__
+`rss` which match the result set is displayed.
+
+Here is an example of ``SchemaBasedRewriter`` usage:
+
+.. sourcecode:: python
+
+    from cubicweb.web.views.urlrewrite import (
+        SchemaBasedRewriter, rgx, build_rset)
+
+    class TrackerURLRewriter(SchemaBasedRewriter):
+        rules = [
+            (rgx('/project/([^/]+)/([^/]+)/tests'),
+             build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
+                        rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
+            ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/views.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,142 @@
+
+.. _Views:
+
+Principles
+----------
+
+We'll start with a description of the interface providing a basic
+understanding of the available classes and methods, then detail the
+view selection principle.
+
+A `View` is an object responsible for the rendering of data from the
+model into an end-user consummable form. They typically churn out an
+XHTML stream, but there are views concerned with email other non-html
+outputs.
+
+.. _views_base_class:
+
+Discovering possible views
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is possible to configure the web user interface to have a left box
+showing all the views than can be applied to the current result set.
+
+To enable this, click on your login at the top right corner. Chose
+"user preferences", then "boxes", then "possible views box" and check
+"visible = yes" before validating your changes.
+
+The views listed there we either not selected because of a lower
+score, or they were deliberately excluded by the main template logic.
+
+
+Basic class for views
+~~~~~~~~~~~~~~~~~~~~~
+
+Class `View` (`cubicweb.view`)
+```````````````````````````````
+
+This class is an abstraction of a view class, used as a base class for
+every renderable object such as views, templates and other user
+interface components.
+
+A `View` is instantiated to render a result set or part of a result
+set. `View` subclasses may be parametrized using the following class
+attributes:
+
+* `templatable` indicates if the view may be embedded in a main
+  template or if it has to be rendered standalone (i.e. pure XML views
+  must not be embedded in the main template of HTML pages)
+
+* if the view is not templatable, it should set the `content_type`
+  class attribute to the correct MIME type (text/xhtml being the
+  default)
+
+* the `category` attribute may be used in the interface to regroup
+  related view kinds together
+
+A view writes to its output stream thanks to its attribute `w` (the
+append method of an `UStreamIO`, except for binary views).
+
+At instantiation time, the standard `_cw` and `cw_rset` attributes are
+added and the `w` attribute will be set at rendering time.
+
+The basic interface for views is as follows (remember that the result
+set has a tabular structure with rows and columns, hence cells):
+
+* `render(**context)`, render the view by calling `call` or
+  `cell_call` depending on the context
+
+* `call(**kwargs)`, call the view for a complete result set or null
+  (the default implementation calls `cell_call()` on each cell of the
+  result set)
+
+* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
+  result set (`row` and `col` being integers used to access the cell)
+
+* `url()`, returns the URL enabling us to get the view with the current
+  result set
+
+* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of
+  identifier `__vid` on the given result set. It is possible to give a
+  fallback view identifier that will be used if the requested view is
+  not applicable to the result set.
+
+* `html_headers()`, returns a list of HTML headers to be set by the
+  main template
+
+* `page_title()`, returns the title to use in the HTML header `title`
+
+Other basic view classes
+````````````````````````
+Here are some of the subclasses of `View` defined in `cubicweb.common.view`
+that are more concrete as they relate to data rendering within the application:
+
+* `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
+* `StartupView`, start view that does not require a result set to apply to
+* `AnyRsetView`, view applicable to any result set
+
+Examples of views class
+```````````````````````
+
+- Using `templatable`, `content_type` and HTTP cache configuration
+
+.. sourcecode:: python
+
+    class RSSView(XMLView):
+        __regid__ = 'rss'
+        title = _('rss')
+        templatable = False
+        content_type = 'text/xml'
+        http_cache_manager = MaxAgeHTTPCacheManager
+        cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
+
+- Using a custom selector
+
+.. sourcecode:: python
+
+    class SearchForAssociationView(EntityView):
+        """view called by the edition view when the user asks
+        to search for something to link to the edited eid
+        """
+        __regid__ = 'search-associate'
+        title = _('search for association')
+        __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
+
+
+XML views, binaries views...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For views generating other formats than HTML (an image generated dynamically
+for example), and which can not simply be included in the HTML page generated
+by the main template (see above), you have to:
+
+* set the attribute `templatable` of the class to `False`
+* set, through the attribute `content_type` of the class, the MIME
+  type generated by the view to `application/octet-stream` or any
+  relevant and more specialised mime type
+
+For views dedicated to binary content creation (like dynamically generated
+images), we have to set the attribute `binary` of the class to `True` (which
+implies that `templatable == False`, so that the attribute `w` of the view could be
+replaced by a binary flow instead of unicode).
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/wdoc.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Online documentation system
+---------------------------
+
+(:mod:`cubicweb.web.views.wdoc`)
+
+XXX  describe the on-line documentation system
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/xmlrss.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,60 @@
+.. _XmlAndRss:
+
+XML and RSS views
+-----------------
+
+(:mod:`cubicweb.web.views.xmlrss`)
+
+Overview
++++++++++
+
+*rss*
+    Creates a RSS/XML view and call the view `rssitem` for each entity of
+    the result set.
+
+*rssitem*
+    Create a RSS/XML view for each entity based on the results of the dublin core
+    methods of the entity (`dc_*`)
+
+RSS Channel Example
+++++++++++++++++++++
+
+Assuming you have several blog entries, click on the title of the
+search box in the left column. A larger search box should appear. Enter::
+
+   Any X ORDERBY D WHERE X is BlogEntry, X creation_date D
+
+and you get a list of blog entries.
+
+Click on your login at the top right corner. Chose "user preferences",
+then "boxes", then "possible views box" and check "visible = yes"
+before validating your changes.
+
+Enter the same query in the search box and you will see the same list,
+plus a box titled "possible views" in the left column. Click on
+"entityview", then "RSS".
+
+You just applied the "RSS" view to the RQL selection you requested.
+
+That's it, you have a RSS channel for your blog.
+
+Try again with::
+
+    Any X ORDERBY D WHERE X is BlogEntry, X creation_date D,
+    X entry_of B, B title "MyLife"
+
+Another RSS channel, but a bit more focused.
+
+A last one for the road::
+
+    Any C ORDERBY D WHERE C is Comment, C creation_date D LIMIT 15
+
+displayed with the RSS view, that's a channel for the last fifteen
+comments posted.
+
+[WRITE ME]
+
+* show that the RSS view can be used to display an ordered selection
+  of blog entries, thus providing a RSS channel
+
+* show that a different selection (by category) means a different channel
Binary file doc/book/en/images/03-transitions-view.en.png has changed
Binary file doc/book/en/images/03-transitions-view_en.png has changed
Binary file doc/book/en/images/archi_globale.en.png has changed
Binary file doc/book/en/images/archi_globale_en.png has changed
Binary file doc/book/en/images/cbw-add-relation-entryof.en.png has changed
Binary file doc/book/en/images/cbw-add-relation-entryof_en.png has changed
Binary file doc/book/en/images/cbw-create-blog.en.png has changed
Binary file doc/book/en/images/cbw-create-blog_en.png has changed
Binary file doc/book/en/images/cbw-detail-one-blogentry.en.png has changed
Binary file doc/book/en/images/cbw-detail-one-blogentry_en.png has changed
Binary file doc/book/en/images/cbw-list-one-blog.en.png has changed
Binary file doc/book/en/images/cbw-list-one-blog_en.png has changed
Binary file doc/book/en/images/cbw-list-two-blog.en.png has changed
Binary file doc/book/en/images/cbw-list-two-blog_en.png has changed
Binary file doc/book/en/images/cbw-schema.en.png has changed
Binary file doc/book/en/images/cbw-schema_en.png has changed
Binary file doc/book/en/images/cbw-update-primary-view.en.png has changed
Binary file doc/book/en/images/cbw-update-primary-view_en.png has changed
Binary file doc/book/en/images/lax-book.00-login.en.png has changed
Binary file doc/book/en/images/lax-book.01-start.en.png has changed
Binary file doc/book/en/images/lax-book.02-cookie-values.en.png has changed
Binary file doc/book/en/images/lax-book.02-create-blog.en.png has changed
Binary file doc/book/en/images/lax-book.03-list-one-blog.en.png has changed
Binary file doc/book/en/images/lax-book.03-site-config-panel.en.png has changed
Binary file doc/book/en/images/lax-book.03-state-submitted.en.png has changed
Binary file doc/book/en/images/lax-book.03-transitions-view.en.png has changed
Binary file doc/book/en/images/lax-book.04-detail-one-blog.en.png has changed
Binary file doc/book/en/images/lax-book.05-list-two-blog.en.png has changed
Binary file doc/book/en/images/lax-book.06-add-relation-entryof.en.png has changed
Binary file doc/book/en/images/lax-book.06-header-no-login.en.png has changed
Binary file doc/book/en/images/lax-book.06-main-template-layout.en.png has changed
Binary file doc/book/en/images/lax-book.06-main-template-logo.en.png has changed
Binary file doc/book/en/images/lax-book.06-simple-main-template.en.png has changed
Binary file doc/book/en/images/lax-book.07-detail-one-blogentry.en.png has changed
Binary file doc/book/en/images/lax-book.08-schema.en.png has changed
Binary file doc/book/en/images/lax-book.09-new-view-blogentry.en.png has changed
Binary file doc/book/en/images/lax-book.10-blog-with-two-entries.en.png has changed
Binary file doc/book/en/images/lax-book_00-login_en.png has changed
Binary file doc/book/en/images/lax-book_01-start_en.png has changed
Binary file doc/book/en/images/lax-book_02-cookie-values_en.png has changed
Binary file doc/book/en/images/lax-book_02-create-blog_en.png has changed
Binary file doc/book/en/images/lax-book_03-list-one-blog_en.png has changed
Binary file doc/book/en/images/lax-book_03-site-config-panel_en.png has changed
Binary file doc/book/en/images/lax-book_03-state-submitted_en.png has changed
Binary file doc/book/en/images/lax-book_03-transitions-view_en.png has changed
Binary file doc/book/en/images/lax-book_04-detail-one-blog_en.png has changed
Binary file doc/book/en/images/lax-book_05-list-two-blog_en.png has changed
Binary file doc/book/en/images/lax-book_06-add-relation-entryof_en.png has changed
Binary file doc/book/en/images/lax-book_06-header-no-login_en.png has changed
Binary file doc/book/en/images/lax-book_06-main-template-layout_en.png has changed
Binary file doc/book/en/images/lax-book_06-main-template-logo_en.png has changed
Binary file doc/book/en/images/lax-book_06-simple-main-template_en.png has changed
Binary file doc/book/en/images/lax-book_07-detail-one-blogentry_en.png has changed
Binary file doc/book/en/images/lax-book_08-schema_en.png has changed
Binary file doc/book/en/images/lax-book_09-new-view-blogentry_en.png has changed
Binary file doc/book/en/images/lax-book_10-blog-with-two-entries_en.png has changed
--- a/doc/book/en/index.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/index.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -40,9 +40,6 @@
 .. _`mailing-list`: http://lists.cubicweb.org/mailman/listinfo/cubicweb
 .. _blog: http://www.cubicweb.org/blog/1238
 
-Table of Contents
-=================
-
 .. toctree::
    :maxdepth: 2
 
@@ -52,7 +49,8 @@
 .. toctree::
    :maxdepth: 3
 
-   development/index
+   devrepo/index
+   devweb/index
 
 .. toctree::
    :maxdepth: 2
--- a/doc/book/en/intro/concepts.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/intro/concepts.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -16,8 +16,8 @@
 -----
 
 A cube is a software component made of three parts: its data model
-(:file:`schema`), its logic (:file:`entities`) and its user interface
-(:file:`views`).
+(:mod:`schema`), its logic (:mod:`entities`) and its user interface
+(:mod:`views`).
 
 A cube can use other cubes as building blocks and assemble them to provide a
 whole with richer functionnalities than its parts. The cubes `cubicweb-blog`_ and
@@ -59,7 +59,7 @@
 repository. For applications that support high traffic, several web (front-end)
 and data (back-end) instances can be set-up to share the load.
 
-.. image:: ../images/archi_globale.en.png
+.. image:: ../images/archi_globale_en.png
 
 The command :command:`cubicweb-ctl list` also displays the list of instances
 installed on your system.
@@ -70,7 +70,7 @@
 environment variable.
 
 
-.. Note::
+.. note::
 
   The term application is used to refer to "something that should do something as
   a whole", eg more like a project and so can refer to an instance or to a cube,
@@ -101,14 +101,14 @@
 repository side, you can for instance by-pass security checks, which isn't
 possible from client code.
 
-Some logic can be attached to events that happen in the repository, like
-creation of entities, deletion of relations, etc. This is used for example to
-send email notifications when the state of an object changes. See :ref:`HookIntro` below.
+Some logic can be attached to events that happen in the repository,
+like creation of entities, deletion of relations, etc. This is used
+for example to send email notifications when the state of an object
+changes. See :ref:`HookIntro` below.
 
 .. [1] not to be confused with a Mercurial repository or a Debian repository.
 .. _`Python Remote Objects`: http://pyro.sourceforge.net/
 
-
 .. _WebEngineIntro:
 
 Web Engine
@@ -237,11 +237,11 @@
 The RQL query language
 ----------------------
 
-**No need for a complicated ORM when you have a powerful data
-  manipulation language**
+No need for a complicated ORM when you have a powerful data
+manipulation language.
 
-All the persistent data in a |cubicweb| instance is retrieved and modified by
-using the Relation Query Language.
+All the persistent data in a |cubicweb| instance is retrieved and
+modified using RQL (see :ref:`rql_intro`).
 
 This query language is inspired by SQL but is on a higher level in order to
 emphasize browsing relations.
@@ -252,6 +252,8 @@
 
 The repository exposes a `db-api`_ like api but using the RQL instead of SQL.
 
+.. _`db-api`: http://www.python.org/dev/peps/pep-0249/
+
 You basically get a connection using :func:`cubicweb.dbapi.connect` , then
 get a cursor to call its `execute` method which will return result set for the
 given rql query.
@@ -336,8 +338,6 @@
 Hooks and operation are an essential building block of any moderately complicated
 cubicweb application.
 
-.. Note:
+.. note::
    RQL queries executed in hooks and operations are *unsafe* by default, e.g. the
    read and write security is deactivated unless explicitly asked.
-
-.. |cubicweb| replace:: *CubicWeb*
--- a/doc/book/en/tutorials/base/create-cube.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/tutorials/base/create-cube.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -174,7 +174,7 @@
 ``everything about technology`` as the description, then validate the form by
 clicking on ``Validate``.
 
-.. image:: ../../images/cbw-create-blog.en.png
+.. image:: ../../images/cbw-create-blog_en.png
    :alt: from to create blog
 
 Click on the logo at top left to get back to the home page, then
@@ -182,7 +182,7 @@
 You should be seeing a list with a single item ``Tech-blog`` you
 just created.
 
-.. image:: ../../images/cbw-list-one-blog.en.png
+.. image:: ../../images/cbw-list-one-blog_en.png
    :alt: displaying a list of a single blog
 
 Clicking on this item will get you to its detailed description except
@@ -194,7 +194,7 @@
 again to follow the Blog link for the second time. The list now
 has two items.
 
-.. image:: ../../images/cbw-list-two-blog.en.png
+.. image:: ../../images/cbw-list-two-blog_en.png
    :alt: displaying a list of two blogs
 
 Add a BlogEntry
@@ -215,21 +215,21 @@
 combobox titled ``add relation`` would have showed up.
 
 
-.. image:: ../../images/cbw-add-relation-entryof.en.png
+.. image:: ../../images/cbw-add-relation-entryof_en.png
    :alt: editing a blog entry to add a relation to a blog
 
 Validate the changes by clicking ``Validate``. The entity BlogEntry
 that is displayed now includes a link to the entity Blog named
 ``MyLife``.
 
-.. image:: ../../images/cbw-detail-one-blogentry.en.png
+.. image:: ../../images/cbw-detail-one-blogentry_en.png
    :alt: displaying the detailed view of a blogentry
 
 Note that all of this was handled by the framework and that the only input
 that was provided so far is the schema. To get a graphical view of the schema,
 point your browser to the URL http://localhost:8080/schema
 
-.. image:: ../../images/cbw-schema.en.png
+.. image:: ../../images/cbw-schema_en.png
    :alt: graphical view of the schema (aka data-model)
 
 
@@ -325,7 +325,7 @@
 
 You can now see that the publication date has a prefix.
 
-.. image:: ../../images/cbw-update-primary-view.en.png
+.. image:: ../../images/cbw-update-primary-view_en.png
    :alt: modified primary view
 
 
--- a/doc/book/en/tutorials/base/maintemplate.rst	Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/tutorials/base/maintemplate.rst	Mon Apr 26 12:52:48 2010 +0200
@@ -8,7 +8,7 @@
 
 A page is composed as indicated on the schema below:
 
-.. image:: ../../images/lax-book.06-main-template-layout.en.png
+.. image:: ../../images/lax-book_06-main-template-layout_en.png
 
 In this section we will demonstrate a change in one of the main
 interesting template from the three you will look for,
@@ -83,7 +83,7 @@
 
 
 
-.. image:: ../../images/lax-book.06-header-no-login.en.png
+.. image:: ../../images/lax-book_06-header-no-login_en.png
 
 Customize footer
 ````````````````
@@ -121,7 +121,7 @@
 be used based on TheMainTemplate called SimpleMainTemplate which does not have
 a top section.
 
-.. image:: ../../images/lax-book.06-simple-main-template.en.png
+.. image:: ../../images/lax-book_06-simple-main-template_en.png
 
 XXX
 [WRITE ME]
--- a/server/migractions.py	Fri Apr 23 13:36:43 2010 +0200
+++ b/server/migractions.py	Mon Apr 26 12:52:48 2010 +0200
@@ -116,10 +116,10 @@
                 return super(ServerMigrationHelper, self).cmd_process_script(
                     migrscript, funcname, *args, **kwargs)
             else:
-                print
-                print ('-> ignoring %s, only .py .sql and .txt scripts are considered' %
+                print >> sys.stderr
+                print >> sys.stderr, ('-> ignoring %s, only .py .sql and .txt scripts are considered' %
                        migrscript)
-                print
+                print >> sys.stderr
             self.commit()
         except:
             self.rollback()
--- a/web/views/baseviews.py	Fri Apr 23 13:36:43 2010 +0200
+++ b/web/views/baseviews.py	Mon Apr 26 12:52:48 2010 +0200
@@ -311,7 +311,8 @@
 
     def call(self, **kwargs):
         """display a list of entities by calling their <item_vid> view"""
-        if not 'vtitle' in self._cw.form:
+        showtitle = kwargs.pop('showtitle', not 'vtitle' in self._cw.form)
+        if showtitle:
             self.w(u'<h1>%s</h1>' % self.title)
         super(SameETypeListView, self).call(**kwargs)