[doc/book] include sylvain great advanced tutorial, move tutorials in one proper section stable
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Wed, 14 Apr 2010 16:15:08 +0200
branchstable
changeset 5253 7ee07d18dc95
parent 5245 385c2351153e
child 5254 de4721274648
[doc/book] include sylvain great advanced tutorial, move tutorials in one proper section
doc/book/en/intro/book-map.rst
doc/book/en/intro/tutorial/blog-in-five-minutes.rst
doc/book/en/intro/tutorial/components.rst
doc/book/en/intro/tutorial/conclusion.rst
doc/book/en/intro/tutorial/create-cube.rst
doc/book/en/intro/tutorial/index.rst
doc/book/en/intro/tutorial/maintemplate.rst
doc/book/en/tutorials/advanced/index.rst
doc/book/en/tutorials/base/blog-in-five-minutes.rst
doc/book/en/tutorials/base/components.rst
doc/book/en/tutorials/base/conclusion.rst
doc/book/en/tutorials/base/create-cube.rst
doc/book/en/tutorials/base/index.rst
doc/book/en/tutorials/base/maintemplate.rst
doc/book/en/tutorials/index.rst
--- a/doc/book/en/intro/book-map.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Book map
-========
-
-[XXX WRITE ME]
-
-* explain how to use this book and what chapters to read in what order depending on the
-  objectives of the reader
-
--- a/doc/book/en/intro/tutorial/blog-in-five-minutes.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _BlogFiveMinutes:
-
-Get a blog running in five minutes!
------------------------------------
-
-For Debian or Ubuntu users, first install the following packages (:ref:`DebianInstallation`)::
-
-    cubicweb, cubicweb-dev, cubicweb-blog
-
-For Windows or Mac OS X users, you must install cubicweb from source (see :ref:`SourceInstallation` and  :ref:`WindowsInstallation`).
-
-Then create and initialize your instance::
-
-    cubicweb-ctl create blog myblog
-
-And start it::
-
-    cubicweb-ctl start -D myblog
-
-The -D option is the debugging mode of cubicweb, removing it will lauch the instance in the background.
-
-Permission
-~~~~~~~~~~
-
-This command assumes that you have root access to the /etc/ path. In order to initialize your instance as a `user` (from scratch), please check your current PYTHONPATH then create the ~/etc/cubicweb.d directory.
-
-Instance parameters
-~~~~~~~~~~~~~~~~~~~
-
-If the database installation failed, you'd like to change some instance parameters, for example, the database host or the user name. These informations can be edited in the `source` file located in the /etc/cubicweb.d/myblog directory.
-
-Then relaunch the database creation:
-
-     cubicweb-ctl db-create myblog
-
-Other paramaters, like web server or emails parameters, can be modified in the `all-in-one.conf` file.
-
-This is it. Your blog is running. Visit http://localhost:8080 and enjoy it! This blog is fully functionnal. The next section section will present the way to develop new cubes and customizing the look of your instance.
-
-
--- a/doc/book/en/intro/tutorial/components.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _cubes:
-
-Cubes
------
-
-Standard library
-~~~~~~~~~~~~~~~~
-
-A library of standard cubes are available from `CubicWeb Forge`_
-Cubes provide entities and views.
-
-The available application entities in standard cubes are:
-
-* addressbook: PhoneNumber and PostalAddress
-
-* basket: Basket (like a shopping cart)
-
-* blog: Blog (a *very* basic blog)
-
-* classfolder: Folder (to organize things but grouping them in folders)
-
-* classtags: Tag (to tag anything)
-
-* comment: Comment (to attach comment threads to entities)
-
-* 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)
-
-.. _`CubicWeb Forge`: http://www.cubicweb.org/project/
-
-Adding comments to BlogDemo
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To import a cube in your instance just change the line in the
-``__pkginfo__.py`` file and verify that the cube you are planning
-to use is listed by the command ``cubicweb-ctl list``.
-For example::
-
-    __use__ = ('comment',)
-
-will make the ``Comment`` entity available in your ``BlogDemo``
-cube.
-
-Change the schema to add a relationship between ``BlogEntry`` and
-``Comment`` and you are done. Since the comment cube defines the
-``comments`` relationship, adding the line::
-
-    comments = ObjectRelation('Comment', cardinality='1*', composite='object')
-
-to the definition of a ``BlogEntry`` will be enough.
-
-Synchronize the data model
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Once you modified your data model, you need to synchronize the
-database with your model. For this purpose, *CubicWeb* provides
-a very useful command ``cubicweb-ctl shell blogdemo`` which
-launches an interactive shell where you can enter migration
-commands (see :ref:`cubicweb-ctl` for more details)).
-As you added the cube named `comment`, you need to run:
-
-::
-
-  add_cube('comment')
-
-You can now start your instance and comment your blog entries.
--- a/doc/book/en/intro/tutorial/conclusion.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-What's next?
-------------
-
-We demonstrated how from a straight out of the box *CubicWeb* installation, you
-can build your web application based on a data model. It's all already there:
-views, templates, permissions, etc. The step forward is now for you to customize
-according to your needs.
-
-Many features are available to extend your application, for example: RSS channel
-integration (:ref:`XmlAndRss`), hooks (:ref:`hooks`), support of sources such as
-Google App Engine (:ref:`GoogleAppEngineSource`) and lots of others to discover
-through our book.
-
--- a/doc/book/en/intro/tutorial/create-cube.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,430 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-
-.. _Steps:
-
-Steps for creating your cube
-----------------------------
-
-The following steps will help you to create and customize a new cube.
-
-1. :ref:`CreateYourCube`
-
-Create the directory to hold the code of your cube. The most important files that will be useful to customize your newly created cube are:
-  * schema.py: contains the data model
-  * views.py: contains your custom views
-  * entities.py: contains XXX 
-
-The detailed structure of the code directory is described in :ref:`cubelayout`.
-
-2. :ref:`DefineDataModel`
-
-Define the data model of your application.
-
-3. :ref:`ExploreYourInstance`
-
-Create, run, and explore an instance of your cube.
-
-4. :ref:`DefineViews`
-
-Customize the views of your data: how and which part of your data are showed. 
-
-Note: views don't concern the look'n'feel or design of the site. For that, you should use CSS instead, and default CSS or your new cube are located in 'blog/data/'.
-
-
-5. :ref:`DefineEntities`
-
-Define your own entities to add useful functions when you manipulate your data, especially when you write view.
-
-
-.. _CreateYourCube:
-
-Create your cube
-----------------
-
-The packages ``cubicweb`` and ``cubicweb-dev`` install a command line
-tool for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide
-range of commands described in details in :ref:`cubicweb-ctl`.
-
-Once your *CubicWeb* development environment is set up, you can create
-a new cube::
-
-  cubicweb-ctl newcube blog
-
-This will create in the cubes directory (``/path/to/forest/cubes`` for Mercurial
-installation, ``/usr/share/cubicweb/cubes`` for debian packages installation)
-a directory named ``blog`` reflecting the structure described in :ref:`Concepts`.
-
-
-For packages installation, you can still create new cubes in your home directory using the following configuration. Let's say you want to develop your new cubes in `~src/cubes`, then set the following environment variables:
-::
-
-  CW_CUBES_PATH=~/src/cubes
-  CW_MODE=user
-
-and then create your new cube using:
-::
-
-  cubicweb-ctl newcube --directory=~/src/cubes blog
-
-
-
-
-
-
-.. _DefineDataModel:
-
-Define your data model
-----------------------
-
-The data model or schema is the core of your *CubicWeb* application.
-It defines the type of content your application will handle.
-
-The data model of your cube ``blog`` is defined in the file ``schema.py``:
-
-.. sourcecode:: python
-
-  from yams.buildobjs import EntityType, String, SubjectRelation, Date
-
-  class Blog(EntityType):
-    title = String(maxsize=50, required=True)
-    description = String()
-
-  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='?*')
-
-The first step is the import of the EntityType (generic class for entity and 
-attributes that will be used in both Blog and BlogEntry entities. 
-
-A Blog has a title and a description. The title is a string that is
-required and must be less than 50 characters.  The
-description is a string that is not constrained.
-
-A BlogEntry has a title, a publish_date and a content. The title is a
-string that is required and must be less than 100 characters. The
-publish_date is a Date with a default value of TODAY, meaning that
-when a BlogEntry is created, its publish_date will be the current day
-unless it is modified. The content is a string that will be indexed in
-the database full-text index and has no constraint.
-
-A BlogEntry also has a relationship ``entry_of`` that links it to a
-Blog. The cardinality ``?*`` means that a BlogEntry can be part of
-zero or one Blog (``?`` means `zero or one`) and that a Blog can
-have any number of BlogEntry (``*`` means `any number including
-zero`). For completeness, remember that ``+`` means `one or more`.
-
-
-.. _ExploreYourInstance:
-
-Create and explore your instance
---------------------------------
-.. _CreateYourInstance:
-
-Create your instance
-~~~~~~~~~~~~~~~~~~~~
-
-To use this cube as an instance and create a new instance named ``blogdemo``, do::
-
-  cubicweb-ctl create blog blogdemo
-
-This command will create the corresponding database and initialize it.
-
-
-.. _WelcomeToYourWebInstance:
-
-Welcome to your web instance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Start your instance in debug mode with the following command: ::
-
-  cubicweb-ctl start -D blogdemo
-
-
-You can now access your web instance to create blogs and post messages
-by visiting the URL http://localhost:8080/.
-
-A login form will appear. By default, the instance will not allow anonymous
-users to enter the instance. To login, you need then use the admin account
-you created at the time you initialized the database with ``cubicweb-ctl
-create``.
-
-.. image:: ../../images/login-form.png
-
-
-Once authenticated, you can start playing with your instance
-and create entities.
-
-.. image:: ../../images/blog-demo-first-page.png
-
-Please notice that so far, the *CubicWeb* framework managed all aspects of
-the web application based on the schema provided at the beginning.
-
-.. _AddEntities:
-
-Add entities
-~~~~~~~~~~~~
-
-We will now add entities in our web application.
-
-Add a Blog
-**********
-
-Let us create a few of these entities. Click on the `[+]` at the left of the
-link Blog on the home page. Call this new Blog ``Tech-blog`` and type in
-``everything about technology`` as the description, then validate the form by
-clicking on ``Validate``.
-
-.. 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
-follow the Blog link that will list for you all the existing Blog.
-You should be seeing a list with a single item ``Tech-blog`` you
-just created.
-
-.. 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
-that in this case, there is not much to display besides the name and
-the phrase ``everything about technology``.
-
-Now get back to the home page by clicking on the top-left logo, then
-create a new Blog called ``MyLife`` and get back to the home page
-again to follow the Blog link for the second time. The list now
-has two items.
-
-.. image:: ../../images/cbw-list-two-blog.en.png
-   :alt: displaying a list of two blogs
-
-Add a BlogEntry
-***************
-
-Get back to the home page and click on [+] at the left of the link
-BlogEntry. Call this new entry ``Hello World`` and type in some text
-before clicking on ``Validate``. You added a new blog entry without
-saying to what blog it belongs. There is a box on the left entitled
-``actions``, click on the menu item ``modify``. You are back to the form
-to edit the blog entry you just created, except that the form now has
-another section with a combobox titled ``add relation``. Chose
-``entry_of`` in this menu and a second combobox appears where you pick
-``MyLife``.
-
-You could also have, at the time you started to fill the form for a
-new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the
-combobox titled ``add relation`` would have showed up.
-
-
-.. 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
-   :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
-   :alt: graphical view of the schema (aka data-model)
-
-
-.. _DefineViews:
-
-Define your entity views
-------------------------
-
-Each entity defined in a model is associated with default views
-allowing different rendering of the data. You can redefine each of
-them according to your needs and preferences. So let's see how the
-views are defined.
-
-
-The view selection principle
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A view is defined by a Python class which includes:
-
-  - an identifier (all objects in *CubicWeb* are recorded in a
-    registry and this identifier will be used as a key)
-
-  - a filter to select the result sets it can be applied to
-
-A view has a set of methods complying with the `View` class interface
-(`cubicweb.common.view`).
-
-*CubicWeb* provides a lot of standard views for the type `EntityView`;
-for a complete list, read the code in directory ``cubicweb/web/views/``.
-
-A view is applied on a `result set` which contains a set of entities
-we are trying to display. *CubicWeb* uses a selector mechanism which
-computes for each available view a score: the view with the highest
-score is then used to display the given `result set`.  The standard
-library of selectors is in ``cubicweb.selector``.
-
-It is possible to define multiple views for the same identifier
-and to associate selectors and filters to allow the application
-to find the most appropriate way to render the data.
-
-For example, the view named ``primary`` is the one used to display a
-single entity. We will now show you how to create a primary view for
-BlogEntry.
-
-
-Primary view customization
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you wish to modify the way a `BlogEntry` is rendered, you will have
-to subclass the `primary` view, for instance in the module ``views``
-of the cube ``cubes/blog/views.py``.
-
-The standard primary view is the most sophisticated view of all. It
-has more than a call() method. It is a template. Actually the entry
-point calls the following sequence of (redefinable) methods:
-
- * render_entity_title
-
- * render_entity_metadata
-
- * render_entity_attributes
-
- * render_entity_relations
-
- * render_side_boxes
-
-Excepted side boxes, we can see all of them already in action in the
-blog entry view. This is all described in more details in
-:ref:`primary`.
-
-We can for example add in front of the publication date a prefix
-specifying that the date we see is the publication date.
-
-To do so, please apply the following changes:
-
-.. sourcecode:: python
-
-  from cubicweb.selectors import implements
-  from cubicweb.web.views import primary
-
-  class BlogEntryPrimaryView(primary.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)
-
-.. note::
-  When a view is modified, it is not required to restart the instance
-  server. Save the Python file and reload the page in your web browser
-  to view the changes.
-
-You can now see that the publication date has a prefix.
-
-.. image:: ../../images/cbw-update-primary-view.en.png
-   :alt: modified primary view
-
-
-The above source code defines a new primary view for ``BlogEntry``.
-
-Since views are applied to result sets and result sets can be tables of
-data, we have to recover the entity from its (row,col)-coordinates.
-The view has a ``self.w()`` method that is used to output data, in our
-example HTML output.
-
-.. note::
-   You can find more details about views and selectors in :ref:`Views`.
-
-
-.. _DefineEntities:
-
-Write entities to add logic in your data
-----------------------------------------
-
-By default, CubicWeb provides a default entity for each data type defined in the schema. 
-A default entity mainly contains the attributes defined in the data model. 
-
-You can redefine each entity to provide additional functions to help you write your views. 
-
-.. sourcecode:: python
-
-    from cubicweb.entities import AnyEntity
-
-    class BlogEntry(AnyEntity):
-        """customized class for BlogEntry entities"""
-    	__regid__ = 'BlogEntry'
-    	__implements__ = AnyEntity.__implements__ 
-
-        def display_cw_logo(self):
-            if 'CW' in self.title:
-                return True
-            else:	
-                return False
-
-Customizing an entity requires that your entity:
- - inherits from ``cubicweb.entities`` or any subclass
- - defines a ``__regid__`` linked to the corresponding data type of your schema
- - implements the base class by explicitly using ``__implements__``.
-
-We implemented here a function ``display_cw_logo`` which tests if the blog entry title contains 'CW'.
-This function can then be used when you customize your views. For instance, you can modify your previous ``views.py`` as follows:
-
-.. sourcecode:: python
-
- class BlogEntryPrimaryView(primary.PrimaryView):
-     __select__ = implements('BlogEntry')
-
-     ...
-
-     def render_entity_title(self, entity):
-	 if entity.display_cw_logo():
-	     self.w(u'<image src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
-	 super(BlogEntryPrimaryView, self).render_entity_title(entity)
-
-Then each blog entry whose title contains 'CW' is shown with the CubicWeb logo in front of it.
-
-.. _UpdatingSchemaAndSynchronisingInstance:
-
-Updating the schema and synchronising the instance
---------------------------------------------------
-
-While developping your cube, you may want to update your data model. Let's say you
-want to add a ``category`` attribute in the ``Blog`` data type. This is called a migration.
-
-The required steps are:
-1. modify the file ``schema.py``. The ``Blog`` class looks now like this:
-
-.. sourcecode:: python
-
- class Blog(EntityType):
-   title = String(maxsize=50, required=True)
-   description = String()
-   category = String(required=True, vocabulary=(_('Professional'), _('Personal')), default='Personal')
-
-2. stop your ``blogdemo`` instance
-
-3. start the cubicweb shell for your instance by running the following command:
-
-.. sourcecode:: bash
-
-  cubicweb-ctl shell blogdemo
-
-4. in the shell, execute:
-
-.. sourcecode:: python
-
- add_attribute('Blog', 'category')
-
-5. you can restart your instance, modify a blog entity and check that the new attribute 
-``category`` has been added.
-
-Of course, you may also want to add relations, entity types, ... See :ref:`migration`
-for a list of all available migration commands.
-
--- a/doc/book/en/intro/tutorial/index.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Tutorial:
-
-Tutorial
-========
-
-*CubicWeb* is a semantic web application framework that favors reuse and
-object-oriented design.
-
-A `cube` is a component that includes a model defining the data types and a set of
-views to display the data. A cube can be built by assembling other cubes.
-
-An `instance` is a specific installation of a cube and includes configuration
-files.
-
-
-This tutorial will show how to create a `cube` and how to use it as an
-application to run an `instance`.
-
-.. toctree::
-   :maxdepth: 2
-
-   blog-in-five-minutes
-   create-cube
-   components
-   maintemplate
-   conclusion
--- a/doc/book/en/intro/tutorial/maintemplate.rst	Wed Apr 14 10:31:09 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Templates
----------
-
-Look at ``cubicweb/web/views/basetemplates.py`` and you will
-find the base templates used to generate HTML for your application.
-
-A page is composed as indicated on the schema below:
-
-.. 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,
-that is to say, the HTMLPageHeader, the HTMLPageFooter
-and the TheMainTemplate.
-
-
-Customize a template
-~~~~~~~~~~~~~~~~~~~~
-
-Based on the diagram below, each template can be overriden
-by your customized template. To do so, we recommand you create
-a Python module ``blog.views.templates`` to keep it organized.
-In this module you will have to import the parent class you are
-interested as follows: ::
-
-  from cubicweb.web.views.basetemplates import HTMLPageHeader, \
-                                    HTMLPageFooter, TheMainTemplate
-
-and then create your sub-class::
-
-  class MyBlogHTMLPageHeader(HTMLPageHeader):
-      ...
-
-Customize header
-`````````````````
-
-Let's now move the search box in the header and remove the login form from the
-header. We'll show how to move it to the left column of the user interface.
-
-Let's say we do not want anymore the login menu to be in the header
-
-First, to remove the login menu, we just need to comment out the display of the
-login graphic component such as follows:
-
-.. sourcecode:: python
-
-  class MyBlogHTMLPageHeader(HTMLPageHeader):
-
-      def main_header(self, view):
-          """build the top menu with authentification info and the rql box"""
-          self.w(u'<table id="header"><tr>\n')
-          self.w(u'<td id="firstcolumn">')
-          self._cw.vreg.select_component('logo', self._cw, self.cw_rset).dispatch(w=self.w)
-          self.w(u'</td>\n')
-          # appliname and breadcrumbs
-          self.w(u'<td id="headtext">')
-          comp = self._cw.vreg.select_component('appliname', self._cw, self.cw_rset)
-          if comp and comp.propval('visible'):
-              comp.dispatch(w=self.w)
-          comp = self._cw.vreg.select_component('breadcrumbs', self._cw, self.cw_rset, view=view)
-          if comp and comp.propval('visible'):
-              comp.dispatch(w=self.w, view=view)
-          self.w(u'</td>')
-          # logged user and help
-          #self.w(u'<td>\n')
-          #comp = self._cw.vreg.select_component('loggeduserlink', self._cw, self.cw_rset)
-          #comp.dispatch(w=self.w)
-          #self.w(u'</td><td>')
-
-          self.w(u'<td>')
-          helpcomp = self._cw.vreg.select_component('help', self._cw, self.cw_rset)
-          if helpcomp: # may not be available if Card is not defined in the schema
-              helpcomp.dispatch(w=self.w)
-          self.w(u'</td>')
-          # lastcolumn
-          self.w(u'<td id="lastcolumn">')
-          self.w(u'</td>\n')
-          self.w(u'</tr></table>\n')
-          self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden',
-                        title=False, message=False)
-
-
-
-.. image:: ../../images/lax-book.06-header-no-login.en.png
-
-Customize footer
-````````````````
-
-If you want to change the footer for example, look
-for HTMLPageFooter and override it in your views file as in:
-
-.. sourcecode:: python
-
-  from cubicweb.web.views.basetemplates import HTMLPageFooter
-
-  class MyHTMLPageFooter(HTMLPageFooter):
-
-      def call(self, **kwargs):
-          self.w(u'<div class="footer">')
-          self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
-          self.w(u'</div>')
-
-Updating a view does not require any restart of the server. By reloading
-the page you can see your new page footer.
-
-
-TheMainTemplate
-```````````````
-
-.. _TheMainTemplate:
-
-The MainTemplate is a bit complex as it tries to accomodate many
-different cases. We are now about to go through it and cutomize entirely
-our application.
-
-TheMainTemplate is responsible for the general layout of the entire application.
-It defines the template of ``__regid__ = main`` that is used by the application. Is
-also defined in ``cubicweb/web/views/basetemplates.py`` another template that can
-be used based on TheMainTemplate called SimpleMainTemplate which does not have
-a top section.
-
-.. image:: ../../images/lax-book.06-simple-main-template.en.png
-
-XXX
-[WRITE ME]
-
-* customize MainTemplate and show that everything in the user
-  interface can be changed
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/advanced/index.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,586 @@
+.. _advanced_tutorial:
+
+Building a photo gallery with CubicWeb
+======================================
+
+Desired features
+----------------
+
+* basically a photo gallery
+
+* photo stored onto the fs and displayed dynamically through a web interface
+
+* navigation through folder (album), tags, geographical zone, people on the
+  picture... using facets
+
+* advanced security (eg not everyone can see everything). More on this later.
+
+
+Cube creation and schema definition
+-----------------------------------
+
+.. _adv_tuto_create_new_cube:
+
+Step 1: creating a new cube for my web site
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One note about my development environment: I wanted to use packaged
+version of CubicWeb and cubes while keeping my cube in my user
+directory, let's say `~src/cubes`.  I achieve this by setting the
+following environment variables::
+
+  CW_CUBES_PATH=~/src/cubes
+  CW_MODE=user
+
+I can now create the cube which will hold custom code for this web
+site using::
+
+  c-c newcube --directory=~/src/cubes sytweb
+
+
+.. _adv_tuto_assemble_cubes:
+
+Step 2: pick building blocks into existing cubes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Almost everything I want represent in my web-site is somewhat already modelized in
+some cube that I'll extend for my need. So I'll pick the following cubes:
+
+* `folder`, containing `Folder` entity type, which will be used as
+  both 'album' and a way to map file system folders. Entities are
+  added to a given folder using the `filed_under` relation.
+
+* `file`, containing `File` and `Image` entity types, gallery view,
+  and a file system import utility.
+
+* `zone`, containing the `Zone` entity type for hierarchical geographical
+  zones. Entities (including sub-zones) are added to a given zone using the
+  `situated_in` relation.
+
+* `person`, containing the `Person` entity type plus some basic views.
+
+* `comment`, providing a full commenting system allowing one to comment entity types
+  supporting the `comments` relation by adding a `Comment` entity.
+
+* `tag`, providing a full tagging system as a easy and powerful way to classify
+  entities supporting the `tags` relation by linking the to `Tag` entities. This
+  will allows navigation into a large number of picture.
+
+Ok, now I'll tell my cube requires all this by editing cubes/sytweb/__pkginfo__.py:
+
+  .. sourcecode:: python
+
+    __depends_cubes__ = {'file': '>= 1.2.0',
+			 'folder': '>= 1.1.0',
+			 'person': '>= 1.2.0',
+			 'comment': '>= 1.2.0',
+			 'tag': '>= 1.2.0',
+			 'zone': None,
+			 }
+    __depends__ = {'cubicweb': '>= 3.5.10',
+		   }
+    for key,value in __depends_cubes__.items():
+	__depends__['cubicweb-'+key] = value
+    __use__ = tuple(__depends_cubes__)
+
+Notice that you can express minimal version of the cube that should be used,
+`None` meaning whatever version available.
+
+Step 3: glue everything together in my cube's schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. sourcecode:: python
+
+    from yams.buildobjs import RelationDefinition
+
+    class comments(RelationDefinition):
+	subject = 'Comment'
+	object = ('File', 'Image')
+	cardinality = '1*'
+	composite = 'object'
+
+    class tags(RelationDefinition):
+	subject = 'Tag'
+	object = ('File', 'Image')
+
+    class filed_under(RelationDefinition):
+	subject = ('File', 'Image')
+	object = 'Folder'
+
+    class situated_in(RelationDefinition):
+	subject = 'Image'
+	object = 'Zone'
+
+    class displayed_on(RelationDefinition):
+	subject = 'Person'
+	object = 'Image'
+
+
+This schema:
+
+* allows to comment and tag on `File` and `Image` entity types by adding the
+  `comments` and `tags` relations. This should be all we've to do for this
+  feature since the related cubes provide 'pluggable section' which are
+  automatically displayed on the primary view of entity types supporting the
+  relation.
+
+* adds a `situated_in` relation definition so that image entities can be
+  geolocalized.
+
+* add a new relation `displayed_on` relation telling who can be seen on a
+  picture.
+
+This schema will probably have to evolve as time goes (for security handling at
+least), but since the possibility to make schema evolving is one of CubicWeb
+feature (and goal), we won't worry and see that later when needed.
+
+
+Step 4: creating the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now that I've a schema, I want to create an instance so I can start To
+create an instance using this new 'sytweb' cube, I run::
+
+  c-c create sytweb sytweb_instance
+
+hint : if you get an error while the database is initialized, you can
+avoid having to reanswer to questions by runing ::
+
+   c-c db-create sytweb_instance
+
+This will use your already configured instance and start directly from the create
+database step, thus skipping questions asked by the 'create' command.
+
+Once the instance and database are fully initialized, run ::
+
+  c-c start sytweb_instance
+
+to start the instance, check you can connect on it, etc...
+
+
+Security, testing and migration
+-------------------------------
+
+This post will cover various topics:
+
+* configuring security
+* migrating existing instance
+* writing some unit tests
+
+Here is the ``read`` security model I want:
+
+* folders, files, images and comments should have one of the following visibility:
+  - ``public``, everyone can see it
+  - ``authenticated``, only authenticated users can see it
+  - ``restricted``, only a subset of authenticated users can see it
+* managers (e.g. me) can see everything
+* only authenticated user can see people
+* everyone can  see classifier entities, eg tag and zone
+
+Also, unless explicity specified, visibility of an image should be the same as
+its parent folder, as well as visibility of a comment should be the same as the
+commented entity. If there is no parent entity, the default visibility is
+``authenticated``.
+
+Regarding write security, that's much easier:
+* anonymous can't write anything
+* authenticated users can only add comment
+* managers will add the remaining stuff
+
+Now, let's implement that!
+
+Proper security in CubicWeb is done at the schema level, so you don't have to
+bother with it in views: users will only see what they can see automatically.
+
+.. _adv_tuto_security:
+
+Step 1: configuring security into the schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In schema, you can grant access according to groups, or to some RQL expressions:
+users get access it the expression return some results. To implements the read
+security defined earlier, groups are not enough, we'll need RQL expression. Here
+is the idea:
+
+* add a `visibility` attribute on folder, image and comment, which may be one of
+  the value explained above
+
+* add a `may_be_read_by` relation from folder, image and comment to users,
+  which will define who can see the entity
+
+* security propagation will be done in hook.
+
+So the first thing to do is to modify my cube'schema.py to define those
+relations:
+
+.. sourcecode:: python
+
+    from yams.constraints import StaticVocabularyConstraint
+
+    class visibility(RelationDefinition):
+	subject = ('Folder', 'File', 'Image', 'Comment')
+	object = 'String'
+	constraints = [StaticVocabularyConstraint(('public', 'authenticated',
+						   'restricted', 'parent'))]
+	default = 'parent'
+	cardinality = '11' # required
+
+    class may_be_read_by(RelationDefinition):
+	subject = ('Folder', 'File', 'Image', 'Comment',)
+	object = 'CWUser'
+
+We can note the following points:
+
+* we've added a new `visibility` attribute to folder, file, image and comment
+  using a `RelationDefinition`
+
+* `cardinality = '11'` means this attribute is required. This is usually hidden
+  under the `required` argument given to the `String` constructor, but we can
+  rely on this here (same thing for StaticVocabularyConstraint, which is usually
+  hidden by the `vocabulary` argument)
+
+* the `parent` possible value will be used for visibility propagation
+
+Now, we should be able to define security rules in the schema, based on these new
+attribute and relation. Here is the code to add to *schema.py*:
+
+.. sourcecode:: python
+
+    from cubicweb.schema import ERQLExpression
+
+    VISIBILITY_PERMISSIONS = {
+	'read':   ('managers',
+		   ERQLExpression('X visibility "public"'),
+		   ERQLExpression('X may_be_read_by U')),
+	'add':    ('managers',),
+	'update': ('managers', 'owners',),
+	'delete': ('managers', 'owners'),
+	}
+    AUTH_ONLY_PERMISSIONS = {
+	    'read':   ('managers', 'users'),
+	    'add':    ('managers',),
+	    'update': ('managers', 'owners',),
+	    'delete': ('managers', 'owners'),
+	    }
+    CLASSIFIERS_PERMISSIONS = {
+	    'read':   ('managers', 'users', 'guests'),
+	    'add':    ('managers',),
+	    'update': ('managers', 'owners',),
+	    'delete': ('managers', 'owners'),
+	    }
+
+    from cubes.folder.schema import Folder
+    from cubes.file.schema import File, Image
+    from cubes.comment.schema import Comment
+    from cubes.person.schema import Person
+    from cubes.zone.schema import Zone
+    from cubes.tag.schema import Tag
+
+    Folder.__permissions__ = VISIBILITY_PERMISSIONS
+    File.__permissions__ = VISIBILITY_PERMISSIONS
+    Image.__permissions__ = VISIBILITY_PERMISSIONS
+    Comment.__permissions__ = VISIBILITY_PERMISSIONS.copy()
+    Comment.__permissions__['add'] = ('managers', 'users',)
+    Person.__permissions__ = AUTH_ONLY_PERMISSIONS
+    Zone.__permissions__ = CLASSIFIERS_PERMISSIONS
+    Tag.__permissions__ = CLASSIFIERS_PERMISSIONS
+
+What's important in there:
+
+* `VISIBILITY_PERMISSIONS` provides read access to managers group, if
+  `visibility` attribute's value is 'public', or if user (designed by the 'U'
+  variable in the expression) is linked to the entity (the 'X' variable) through
+  the `may_read` permission
+
+* we modify permissions of the entity types we use by importing them and
+  modifying their `__permissions__` attribute
+
+* notice the `.copy()`: we only want to modify 'add' permission for `Comment`,
+  not for all entity types using `VISIBILITY_PERMISSIONS`!
+
+* the remaining part of the security model is done using regular groups:
+
+  - `users` is the group to which all authenticated users will belong
+  - `guests` is the group of anonymous users
+
+
+.. _ adv_tuto_security_propagation:
+
+Step 2: security propagation in hooks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To fullfill the requirements, we have to implement::
+
+  Also, unless explicity specified, visibility of an image should be the same as
+  its parent folder, as well as visibility of a comment should be the same as the
+  commented entity.
+
+This kind of `active` rule will be done using CubicWeb's hook
+system. Hooks are triggered on database event such as addition of new
+entity or relation.
+
+The trick part of the requirement is in *unless explicitly specified*, notably
+because when the entity addition hook is added, we don't know yet its 'parent'
+entity (eg folder of an image, image commented by a comment). To handle such things,
+CubicWeb provides `Operation`, which allow to schedule things to do at commit time.
+
+In our case we will:
+
+* on entity creation, schedule an operation that will set default visibility
+
+* when a "parent" relation is added, propagate parent's visibility unless the
+  child already has a visibility set
+
+Here is the code in cube's *hooks.py*:
+
+.. sourcecode:: python
+
+    from cubicweb.selectors import implements
+    from cubicweb.server import hook
+
+    class SetVisibilityOp(hook.Operation):
+	def precommit_event(self):
+	    for eid in self.session.transaction_data.pop('pending_visibility'):
+		entity = self.session.entity_from_eid(eid)
+		if entity.visibility == 'parent':
+		    entity.set_attributes(visibility=u'authenticated')
+
+    class SetVisibilityHook(hook.Hook):
+	__regid__ = 'sytweb.setvisibility'
+	__select__ = hook.Hook.__select__ & implements('Folder', 'File', 'Image', 'Comment')
+	events = ('after_add_entity',)
+	def __call__(self):
+	    hook.set_operation(self._cw, 'pending_visibility', self.entity.eid,
+			       SetVisibilityOp)
+
+    class SetParentVisibilityHook(hook.Hook):
+	__regid__ = 'sytweb.setparentvisibility'
+	__select__ = hook.Hook.__select__ & hook.match_rtype('filed_under', 'comments')
+	events = ('after_add_relation',)
+
+	def __call__(self):
+	    parent = self._cw.entity_from_eid(self.eidto)
+	    child = self._cw.entity_from_eid(self.eidfrom)
+	    if child.visibility == 'parent':
+		child.set_attributes(visibility=parent.visibility)
+
+Notice:
+
+* hooks are application objects, hence have selectors that should match entity or
+  relation types to which the hook applies. To match a relation type, we use the
+  hook specific `match_rtype` selector.
+
+* usage of `set_operation`: instead of adding an operation for each added entity,
+  set_operation allows to create a single one and to store entity's eids to be
+  processed in session's transaction data. This is a good pratice to avoid heavy
+  operations manipulation cost when creating a lot of entities in the same
+  transaction.
+
+* the `precommit_event` method of the operation will be called at transaction's
+  commit time.
+
+* in a hook, `self._cw` is the repository session, not a web request as usually
+  in views
+
+* according to hook's event, you have access to different attributes on the hook
+  instance. Here:
+
+  - `self.entity` is the newly added entity on 'after_add_entity' events
+
+  - `self.eidfrom` / `self.eidto` are the eid of the subject / object entity on
+    'after_add_relatiohn' events (you may also get the relation type using
+    `self.rtype`)
+
+The `parent` visibility value is used to tell "propagate using parent security"
+because we want that attribute to be required, so we can't use None value else
+we'll get an error before we get any chance to propagate...
+
+Now, we also want to propagate the `may_be_read_by` relation. Fortunately,
+CubicWeb provides some base hook classes for such things, so we only have to add
+the following code to *hooks.py*:
+
+.. sourcecode:: python
+
+    # relations where the "parent" entity is the subject
+    S_RELS = set()
+    # relations where the "parent" entity is the object
+    O_RELS = set(('filed_under', 'comments',))
+
+    class AddEntitySecurityPropagationHook(hook.PropagateSubjectRelationHook):
+	"""propagate permissions when new entity are added"""
+	__regid__ = 'sytweb.addentity_security_propagation'
+	__select__ = (hook.PropagateSubjectRelationHook.__select__
+		      & hook.match_rtype_sets(S_RELS, O_RELS))
+	main_rtype = 'may_be_read_by'
+	subject_relations = S_RELS
+	object_relations = O_RELS
+
+    class AddPermissionSecurityPropagationHook(hook.PropagateSubjectRelationAddHook):
+	"""propagate permissions when new entity are added"""
+	__regid__ = 'sytweb.addperm_security_propagation'
+	__select__ = (hook.PropagateSubjectRelationAddHook.__select__
+		      & hook.match_rtype('may_be_read_by',))
+	subject_relations = S_RELS
+	object_relations = O_RELS
+
+    class DelPermissionSecurityPropagationHook(hook.PropagateSubjectRelationDelHook):
+	__regid__ = 'sytweb.delperm_security_propagation'
+	__select__ = (hook.PropagateSubjectRelationDelHook.__select__
+		      & hook.match_rtype('may_be_read_by',))
+	subject_relations = S_RELS
+	object_relations = O_RELS
+
+* the `AddEntitySecurityPropagationHook` will propagate the relation
+  when `filed_under` or `comments` relations are added
+
+  - the `S_RELS` and `O_RELS` set as well as the `match_rtype_sets` selector are
+    used here so that if my cube is used by another one, it'll be able to
+    configure security propagation by simply adding relation to one of the two
+    sets.
+
+* the two others will propagate permissions changes on parent entities to
+  children entities
+
+
+.. _adv_tuto_tesing_security:
+
+Step 3: testing our security
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Security is tricky. Writing some tests for it is a very good idea. You should
+even write them first, as Test Driven Development recommends!
+
+Here is a small test case that will check the basis of our security
+model, in *test/unittest_sytweb.py*:
+
+.. sourcecode:: python
+
+    from cubicweb.devtools.testlib import CubicWebTC
+    from cubicweb import Binary
+
+    class SecurityTC(CubicWebTC):
+
+	def test_visibility_propagation(self):
+	    # create a user for later security checks
+	    toto = self.create_user('toto')
+	    # init some data using the default manager connection
+	    req = self.request()
+	    folder = req.create_entity('Folder',
+				       name=u'restricted',
+				       visibility=u'restricted')
+	    photo1 = req.create_entity('Image',
+				       data_name=u'photo1.jpg',
+				       data=Binary('xxx'),
+				       filed_under=folder)
+	    self.commit()
+	    photo1.clear_all_caches() # good practice, avoid request cache effects
+	    # visibility propagation
+	    self.assertEquals(photo1.visibility, 'restricted')
+	    # unless explicitly specified
+	    photo2 = req.create_entity('Image',
+				       data_name=u'photo2.jpg',
+				       data=Binary('xxx'),
+				       visibility=u'public',
+				       filed_under=folder)
+	    self.commit()
+	    self.assertEquals(photo2.visibility, 'public')
+	    # test security
+	    self.login('toto')
+	    req = self.request()
+	    self.assertEquals(len(req.execute('Image X')), 1) # only the public one
+	    self.assertEquals(len(req.execute('Folder X')), 0) # restricted...
+	    # may_be_read_by propagation
+	    self.restore_connection()
+	    folder.set_relations(may_be_read_by=toto)
+	    self.commit()
+	    photo1.clear_all_caches()
+	    self.failUnless(photo1.may_be_read_by)
+	    # test security with permissions
+	    self.login('toto')
+	    req = self.request()
+	    self.assertEquals(len(req.execute('Image X')), 2) # now toto has access to photo2
+	    self.assertEquals(len(req.execute('Folder X')), 1) # and to restricted folder
+
+    if __name__ == '__main__':
+	from logilab.common.testlib import unittest_main
+	unittest_main()
+
+It's not complete, but show most things you'll want to do in tests: adding some
+content, creating users and connecting as them in the test, etc...
+
+To run it type: ::
+
+    [syt@scorpius test]$ pytest unittest_sytweb.py
+    ========================  unittest_sytweb.py  ========================
+    -> creating tables [....................]
+    -> inserting default user and default groups.
+    -> storing the schema in the database [....................]
+    -> database for instance data initialized.
+    .
+    ----------------------------------------------------------------------
+    Ran 1 test in 22.547s
+
+    OK
+
+
+The first execution is taking time, since it creates a sqlite database for the
+test instance. The second one will be much quicker: ::
+
+    [syt@scorpius test]$ pytest unittest_sytweb.py
+    ========================  unittest_sytweb.py  ========================
+    .
+    ----------------------------------------------------------------------
+    Ran 1 test in 2.662s
+
+    OK
+
+If you do some changes in your schema, you'll have to force regeneration of that
+database. You do that by removing the tmpdb files before running the test: ::
+
+    [syt@scorpius test]$ rm tmpdb*
+
+
+.. Note::
+  pytest is a very convenient utilities to control test execution, from the `logilab-common`_
+  package
+
+.. _`logilab-common`: http://www.logilab.org/project/logilab-common
+
+.. _adv_tuto_migration_script:
+
+Step 4: writing the migration script and migrating the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Prior to those changes, Iv'e created an instance, feeded it with some data, so I
+don't want to create a new one, but to migrate the existing one. Let's see how to
+do that.
+
+Migration commands should be put in the cube's *migration* directory, in a
+file named file:`<X.Y.Z>_Any.py` ('Any' being there mostly for historical reason).
+
+Here I'll create a *migration/0.2.0_Any.py* file containing the following
+instructions:
+
+.. sourcecode:: python
+
+  add_relation_type('may_be_read_by')
+  add_relation_type('visibility')
+  sync_schema_props_perms()
+
+Then I update the version number in cube's *__pkginfo__.py* to 0.2.0. And
+that's it! Those instructions will:
+
+* update the instance's schema by adding our two new relations and update the
+  underlying database tables accordingly (the two first instructions)
+
+* update schema's permissions definition (the later instruction)
+
+
+To migrate my instance I simply type::
+
+   [syt@scorpius ~]$ cubicweb-ctl upgrade sytweb
+
+I'll then be asked some questions to do the migration step by step. You should say
+YES when it asks if a backup of your database should be done, so you can get back
+to initial state if anything goes wrong...
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/blog-in-five-minutes.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,42 @@
+.. -*- coding: utf-8 -*-
+
+.. _BlogFiveMinutes:
+
+Get a blog running in five minutes!
+-----------------------------------
+
+For Debian or Ubuntu users, first install the following packages (:ref:`DebianInstallation`)::
+
+    cubicweb, cubicweb-dev, cubicweb-blog
+
+For Windows or Mac OS X users, you must install cubicweb from source (see :ref:`SourceInstallation` and  :ref:`WindowsInstallation`).
+
+Then create and initialize your instance::
+
+    cubicweb-ctl create blog myblog
+
+And start it::
+
+    cubicweb-ctl start -D myblog
+
+The -D option is the debugging mode of cubicweb, removing it will lauch the instance in the background.
+
+Permission
+~~~~~~~~~~
+
+This command assumes that you have root access to the /etc/ path. In order to initialize your instance as a `user` (from scratch), please check your current PYTHONPATH then create the ~/etc/cubicweb.d directory.
+
+Instance parameters
+~~~~~~~~~~~~~~~~~~~
+
+If the database installation failed, you'd like to change some instance parameters, for example, the database host or the user name. These informations can be edited in the `source` file located in the /etc/cubicweb.d/myblog directory.
+
+Then relaunch the database creation:
+
+     cubicweb-ctl db-create myblog
+
+Other paramaters, like web server or emails parameters, can be modified in the `all-in-one.conf` file.
+
+This is it. Your blog is running. Visit http://localhost:8080 and enjoy it! This blog is fully functionnal. The next section section will present the way to develop new cubes and customizing the look of your instance.
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/components.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,79 @@
+.. -*- coding: utf-8 -*-
+
+.. _cubes:
+
+Cubes
+-----
+
+Standard library
+~~~~~~~~~~~~~~~~
+
+A library of standard cubes are available from `CubicWeb Forge`_
+Cubes provide entities and views.
+
+The available application entities in standard cubes are:
+
+* addressbook: PhoneNumber and PostalAddress
+
+* basket: Basket (like a shopping cart)
+
+* blog: Blog (a *very* basic blog)
+
+* classfolder: Folder (to organize things but grouping them in folders)
+
+* classtags: Tag (to tag anything)
+
+* comment: Comment (to attach comment threads to entities)
+
+* 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)
+
+.. _`CubicWeb Forge`: http://www.cubicweb.org/project/
+
+Adding comments to BlogDemo
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To import a cube in your instance just change the line in the
+``__pkginfo__.py`` file and verify that the cube you are planning
+to use is listed by the command ``cubicweb-ctl list``.
+For example::
+
+    __use__ = ('comment',)
+
+will make the ``Comment`` entity available in your ``BlogDemo``
+cube.
+
+Change the schema to add a relationship between ``BlogEntry`` and
+``Comment`` and you are done. Since the comment cube defines the
+``comments`` relationship, adding the line::
+
+    comments = ObjectRelation('Comment', cardinality='1*', composite='object')
+
+to the definition of a ``BlogEntry`` will be enough.
+
+Synchronize the data model
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once you modified your data model, you need to synchronize the
+database with your model. For this purpose, *CubicWeb* provides
+a very useful command ``cubicweb-ctl shell blogdemo`` which
+launches an interactive shell where you can enter migration
+commands (see :ref:`cubicweb-ctl` for more details)).
+As you added the cube named `comment`, you need to run:
+
+::
+
+  add_cube('comment')
+
+You can now start your instance and comment your blog entries.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/conclusion.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,15 @@
+.. -*- coding: utf-8 -*-
+
+What's next?
+------------
+
+We demonstrated how from a straight out of the box *CubicWeb* installation, you
+can build your web application based on a data model. It's all already there:
+views, templates, permissions, etc. The step forward is now for you to customize
+according to your needs.
+
+Many features are available to extend your application, for example: RSS channel
+integration (:ref:`XmlAndRss`), hooks (:ref:`hooks`), support of sources such as
+Google App Engine (:ref:`GoogleAppEngineSource`) and lots of others to discover
+through our book.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/create-cube.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,431 @@
+.. -*- coding: utf-8 -*-
+
+.. _Steps:
+
+Steps for creating your cube
+----------------------------
+
+The following steps will help you to create and customize a new cube.
+
+1. :ref:`CreateYourCube`
+
+Create the directory to hold the code of your cube. The most important
+files that will be useful to customize your newly created cube are:
+
+  * schema.py: contains the data model
+  * views.py: contains your custom views
+  * entities.py: contains XXX
+
+The detailed structure of the code directory is described in :ref:`cubelayout`.
+
+2. :ref:`DefineDataModel`
+
+Define the data model of your application.
+
+3. :ref:`ExploreYourInstance`
+
+Create, run, and explore an instance of your cube.
+
+4. :ref:`DefineViews`
+
+Customize the views of your data: how and which part of your data are showed.
+
+Note: views don't concern the look'n'feel or design of the site. For that, you should use CSS instead, and default CSS or your new cube are located in 'blog/data/'.
+
+
+5. :ref:`DefineEntities`
+
+Define your own entities to add useful functions when you manipulate your data, especially when you write view.
+
+
+.. _CreateYourCube:
+
+Create your cube
+----------------
+
+The packages ``cubicweb`` and ``cubicweb-dev`` install a command line
+tool for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide
+range of commands described in details in :ref:`cubicweb-ctl`.
+
+Once your *CubicWeb* development environment is set up, you can create
+a new cube::
+
+  cubicweb-ctl newcube blog
+
+This will create in the cubes directory (``/path/to/forest/cubes`` for Mercurial
+installation, ``/usr/share/cubicweb/cubes`` for debian packages installation)
+a directory named ``blog`` reflecting the structure described in :ref:`Concepts`.
+
+
+For packages installation, you can still create new cubes in your home directory using the following configuration. Let's say you want to develop your new cubes in `~src/cubes`, then set the following environment variables:
+::
+
+  CW_CUBES_PATH=~/src/cubes
+  CW_MODE=user
+
+and then create your new cube using:
+::
+
+  cubicweb-ctl newcube --directory=~/src/cubes blog
+
+
+
+
+
+
+.. _DefineDataModel:
+
+Define your data model
+----------------------
+
+The data model or schema is the core of your *CubicWeb* application.
+It defines the type of content your application will handle.
+
+The data model of your cube ``blog`` is defined in the file ``schema.py``:
+
+.. sourcecode:: python
+
+  from yams.buildobjs import EntityType, String, SubjectRelation, Date
+
+  class Blog(EntityType):
+    title = String(maxsize=50, required=True)
+    description = String()
+
+  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='?*')
+
+The first step is the import of the EntityType (generic class for entity and
+attributes that will be used in both Blog and BlogEntry entities.
+
+A Blog has a title and a description. The title is a string that is
+required and must be less than 50 characters.  The
+description is a string that is not constrained.
+
+A BlogEntry has a title, a publish_date and a content. The title is a
+string that is required and must be less than 100 characters. The
+publish_date is a Date with a default value of TODAY, meaning that
+when a BlogEntry is created, its publish_date will be the current day
+unless it is modified. The content is a string that will be indexed in
+the database full-text index and has no constraint.
+
+A BlogEntry also has a relationship ``entry_of`` that links it to a
+Blog. The cardinality ``?*`` means that a BlogEntry can be part of
+zero or one Blog (``?`` means `zero or one`) and that a Blog can
+have any number of BlogEntry (``*`` means `any number including
+zero`). For completeness, remember that ``+`` means `one or more`.
+
+
+.. _ExploreYourInstance:
+
+Create and explore your instance
+--------------------------------
+.. _CreateYourInstance:
+
+Create your instance
+~~~~~~~~~~~~~~~~~~~~
+
+To use this cube as an instance and create a new instance named ``blogdemo``, do::
+
+  cubicweb-ctl create blog blogdemo
+
+This command will create the corresponding database and initialize it.
+
+
+.. _WelcomeToYourWebInstance:
+
+Welcome to your web instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Start your instance in debug mode with the following command: ::
+
+  cubicweb-ctl start -D blogdemo
+
+
+You can now access your web instance to create blogs and post messages
+by visiting the URL http://localhost:8080/.
+
+A login form will appear. By default, the instance will not allow anonymous
+users to enter the instance. To login, you need then use the admin account
+you created at the time you initialized the database with ``cubicweb-ctl
+create``.
+
+.. image:: ../../images/login-form.png
+
+
+Once authenticated, you can start playing with your instance
+and create entities.
+
+.. image:: ../../images/blog-demo-first-page.png
+
+Please notice that so far, the *CubicWeb* framework managed all aspects of
+the web application based on the schema provided at the beginning.
+
+.. _AddEntities:
+
+Add entities
+~~~~~~~~~~~~
+
+We will now add entities in our web application.
+
+Add a Blog
+**********
+
+Let us create a few of these entities. Click on the `[+]` at the left of the
+link Blog on the home page. Call this new Blog ``Tech-blog`` and type in
+``everything about technology`` as the description, then validate the form by
+clicking on ``Validate``.
+
+.. 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
+follow the Blog link that will list for you all the existing Blog.
+You should be seeing a list with a single item ``Tech-blog`` you
+just created.
+
+.. 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
+that in this case, there is not much to display besides the name and
+the phrase ``everything about technology``.
+
+Now get back to the home page by clicking on the top-left logo, then
+create a new Blog called ``MyLife`` and get back to the home page
+again to follow the Blog link for the second time. The list now
+has two items.
+
+.. image:: ../../images/cbw-list-two-blog.en.png
+   :alt: displaying a list of two blogs
+
+Add a BlogEntry
+***************
+
+Get back to the home page and click on [+] at the left of the link
+BlogEntry. Call this new entry ``Hello World`` and type in some text
+before clicking on ``Validate``. You added a new blog entry without
+saying to what blog it belongs. There is a box on the left entitled
+``actions``, click on the menu item ``modify``. You are back to the form
+to edit the blog entry you just created, except that the form now has
+another section with a combobox titled ``add relation``. Chose
+``entry_of`` in this menu and a second combobox appears where you pick
+``MyLife``.
+
+You could also have, at the time you started to fill the form for a
+new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the
+combobox titled ``add relation`` would have showed up.
+
+
+.. 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
+   :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
+   :alt: graphical view of the schema (aka data-model)
+
+
+.. _DefineViews:
+
+Define your entity views
+------------------------
+
+Each entity defined in a model is associated with default views
+allowing different renderings of the data. You can redefine each of
+them according to your needs and preferences. So let's see how the
+views are defined.
+
+
+The view selection principle
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A view is defined by a Python class which includes:
+
+  - an identifier (all objects in *CubicWeb* are recorded in a
+    registry and this identifier will be used as a key)
+
+  - a filter to select the result sets it can be applied to
+
+A view has a set of methods complying with the `View` class interface
+(`cubicweb.common.view`).
+
+*CubicWeb* provides a lot of standard views for the type `EntityView`;
+for a complete list, read the code in directory ``cubicweb/web/views/``.
+
+A view is applied on a `result set` which contains a set of entities
+we are trying to display. *CubicWeb* uses a selector mechanism which
+computes for each available view a score: the view with the highest
+score is then used to display the given `result set`.  The standard
+library of selectors is in ``cubicweb.selector``.
+
+It is possible to define multiple views for the same identifier
+and to associate selectors and filters to allow the application
+to find the most appropriate way to render the data.
+
+For example, the view named ``primary`` is the one used to display a
+single entity. We will now show you how to create a primary view for
+BlogEntry.
+
+
+Primary view customization
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you wish to modify the way a `BlogEntry` is rendered, you will have
+to subclass the `primary` view, for instance in the module ``views``
+of the cube ``cubes/blog/views.py``.
+
+The standard primary view is the most sophisticated view of all. It
+has more than a call() method. It is a template. Actually the entry
+point calls the following sequence of (redefinable) methods:
+
+ * render_entity_title
+
+ * render_entity_metadata
+
+ * render_entity_attributes
+
+ * render_entity_relations
+
+ * render_side_boxes
+
+Excepted side boxes, we can see all of them already in action in the
+blog entry view. This is all described in more details in
+:ref:`primary`.
+
+We can for example add in front of the publication date a prefix
+specifying that the date we see is the publication date.
+
+To do so, please apply the following changes:
+
+.. sourcecode:: python
+
+  from cubicweb.selectors import implements
+  from cubicweb.web.views import primary
+
+  class BlogEntryPrimaryView(primary.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)
+
+.. note::
+  When a view is modified, it is not required to restart the instance
+  server. Save the Python file and reload the page in your web browser
+  to view the changes.
+
+You can now see that the publication date has a prefix.
+
+.. image:: ../../images/cbw-update-primary-view.en.png
+   :alt: modified primary view
+
+
+The above source code defines a new primary view for ``BlogEntry``.
+
+Since views are applied to result sets and result sets can be tables of
+data, we have to recover the entity from its (row,col)-coordinates.
+The view has a ``self.w()`` method that is used to output data, in our
+example HTML output.
+
+.. note::
+   You can find more details about views and selectors in :ref:`Views`.
+
+
+.. _DefineEntities:
+
+Write entities to add logic in your data
+----------------------------------------
+
+By default, CubicWeb provides a default entity for each data type defined in the schema.
+A default entity mainly contains the attributes defined in the data model.
+
+You can redefine each entity to provide additional functions to help you write your views.
+
+.. sourcecode:: python
+
+    from cubicweb.entities import AnyEntity
+
+    class BlogEntry(AnyEntity):
+        """customized class for BlogEntry entities"""
+    	__regid__ = 'BlogEntry'
+    	__implements__ = AnyEntity.__implements__
+
+        def display_cw_logo(self):
+            if 'CW' in self.title:
+                return True
+            else:
+                return False
+
+Customizing an entity requires that your entity:
+ - inherits from ``cubicweb.entities`` or any subclass
+ - defines a ``__regid__`` linked to the corresponding data type of your schema
+ - implements the base class by explicitly using ``__implements__``.
+
+We implemented here a function ``display_cw_logo`` which tests if the blog entry title contains 'CW'.
+This function can then be used when you customize your views. For instance, you can modify your previous ``views.py`` as follows:
+
+.. sourcecode:: python
+
+ class BlogEntryPrimaryView(primary.PrimaryView):
+     __select__ = implements('BlogEntry')
+
+     ...
+
+     def render_entity_title(self, entity):
+	 if entity.display_cw_logo():
+	     self.w(u'<image src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+	 super(BlogEntryPrimaryView, self).render_entity_title(entity)
+
+Then each blog entry whose title contains 'CW' is shown with the CubicWeb logo in front of it.
+
+.. _UpdatingSchemaAndSynchronisingInstance:
+
+Updating the schema and synchronising the instance
+--------------------------------------------------
+
+While developping your cube, you may want to update your data model. Let's say you
+want to add a ``category`` attribute in the ``Blog`` data type. This is called a migration.
+
+The required steps are:
+1. modify the file ``schema.py``. The ``Blog`` class looks now like this:
+
+.. sourcecode:: python
+
+ class Blog(EntityType):
+   title = String(maxsize=50, required=True)
+   description = String()
+   category = String(required=True, vocabulary=(_('Professional'), _('Personal')), default='Personal')
+
+2. stop your ``blogdemo`` instance
+
+3. start the cubicweb shell for your instance by running the following command:
+
+.. sourcecode:: bash
+
+  cubicweb-ctl shell blogdemo
+
+4. in the shell, execute:
+
+.. sourcecode:: python
+
+ add_attribute('Blog', 'category')
+
+5. you can restart your instance, modify a blog entity and check that the new attribute
+``category`` has been added.
+
+Of course, you may also want to add relations, entity types, ... See :ref:`migration`
+for a list of all available migration commands.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/index.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,29 @@
+.. -*- coding: utf-8 -*-
+
+.. _Tutorial:
+
+
+Building a simple blog
+======================
+
+*CubicWeb* is a semantic web application framework that favors reuse and
+object-oriented design.
+
+A `cube` is a component that includes a model defining the data types and a set of
+views to display the data. A cube can be built by assembling other cubes.
+
+An `instance` is a specific installation of a cube and includes configuration
+files.
+
+
+This tutorial will show how to create a `cube` and how to use it as an
+application to run an `instance`.
+
+.. toctree::
+   :maxdepth: 2
+
+   blog-in-five-minutes
+   create-cube
+   components
+   maintemplate
+   conclusion
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/maintemplate.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,131 @@
+.. -*- coding: utf-8 -*-
+
+Templates
+---------
+
+Look at ``cubicweb/web/views/basetemplates.py`` and you will
+find the base templates used to generate HTML for your application.
+
+A page is composed as indicated on the schema below:
+
+.. 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,
+that is to say, the HTMLPageHeader, the HTMLPageFooter
+and the TheMainTemplate.
+
+
+Customize a template
+~~~~~~~~~~~~~~~~~~~~
+
+Based on the diagram below, each template can be overriden
+by your customized template. To do so, we recommand you create
+a Python module ``blog.views.templates`` to keep it organized.
+In this module you will have to import the parent class you are
+interested as follows: ::
+
+  from cubicweb.web.views.basetemplates import HTMLPageHeader, \
+                                    HTMLPageFooter, TheMainTemplate
+
+and then create your sub-class::
+
+  class MyBlogHTMLPageHeader(HTMLPageHeader):
+      ...
+
+Customize header
+`````````````````
+
+Let's now move the search box in the header and remove the login form from the
+header. We'll show how to move it to the left column of the user interface.
+
+Let's say we do not want anymore the login menu to be in the header
+
+First, to remove the login menu, we just need to comment out the display of the
+login graphic component such as follows:
+
+.. sourcecode:: python
+
+  class MyBlogHTMLPageHeader(HTMLPageHeader):
+
+      def main_header(self, view):
+          """build the top menu with authentification info and the rql box"""
+          self.w(u'<table id="header"><tr>\n')
+          self.w(u'<td id="firstcolumn">')
+          self._cw.vreg.select_component('logo', self._cw, self.cw_rset).dispatch(w=self.w)
+          self.w(u'</td>\n')
+          # appliname and breadcrumbs
+          self.w(u'<td id="headtext">')
+          comp = self._cw.vreg.select_component('appliname', self._cw, self.cw_rset)
+          if comp and comp.propval('visible'):
+              comp.dispatch(w=self.w)
+          comp = self._cw.vreg.select_component('breadcrumbs', self._cw, self.cw_rset, view=view)
+          if comp and comp.propval('visible'):
+              comp.dispatch(w=self.w, view=view)
+          self.w(u'</td>')
+          # logged user and help
+          #self.w(u'<td>\n')
+          #comp = self._cw.vreg.select_component('loggeduserlink', self._cw, self.cw_rset)
+          #comp.dispatch(w=self.w)
+          #self.w(u'</td><td>')
+
+          self.w(u'<td>')
+          helpcomp = self._cw.vreg.select_component('help', self._cw, self.cw_rset)
+          if helpcomp: # may not be available if Card is not defined in the schema
+              helpcomp.dispatch(w=self.w)
+          self.w(u'</td>')
+          # lastcolumn
+          self.w(u'<td id="lastcolumn">')
+          self.w(u'</td>\n')
+          self.w(u'</tr></table>\n')
+          self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden',
+                        title=False, message=False)
+
+
+
+.. image:: ../../images/lax-book.06-header-no-login.en.png
+
+Customize footer
+````````````````
+
+If you want to change the footer for example, look
+for HTMLPageFooter and override it in your views file as in:
+
+.. sourcecode:: python
+
+  from cubicweb.web.views.basetemplates import HTMLPageFooter
+
+  class MyHTMLPageFooter(HTMLPageFooter):
+
+      def call(self, **kwargs):
+          self.w(u'<div class="footer">')
+          self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
+          self.w(u'</div>')
+
+Updating a view does not require any restart of the server. By reloading
+the page you can see your new page footer.
+
+
+TheMainTemplate
+```````````````
+
+.. _TheMainTemplate:
+
+The MainTemplate is a bit complex as it tries to accomodate many
+different cases. We are now about to go through it and cutomize entirely
+our application.
+
+TheMainTemplate is responsible for the general layout of the entire application.
+It defines the template of ``__regid__ = main`` that is used by the application. Is
+also defined in ``cubicweb/web/views/basetemplates.py`` another template that can
+be used based on TheMainTemplate called SimpleMainTemplate which does not have
+a top section.
+
+.. image:: ../../images/lax-book.06-simple-main-template.en.png
+
+XXX
+[WRITE ME]
+
+* customize MainTemplate and show that everything in the user
+  interface can be changed
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/index.rst	Wed Apr 14 16:15:08 2010 +0200
@@ -0,0 +1,19 @@
+.. _Tutorials:
+
+---------
+Tutorials
+---------
+
+We present two tutorials of different levels. The blog building
+tutorial introduces one smoothly to the basic concepts.
+
+Then there is a photo gallery construction tutorial which highlights
+more advanced concepts such as unit tests, security settings,
+migration scripts.
+
+.. toctree::
+   :maxdepth: 1
+   :numbered:
+
+   base/index
+   advanced/index