backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Wed, 19 Jan 2011 09:31:15 +0100
changeset 6842 117b53c10d79
parent 6824 026581ea2b16 (current diff)
parent 6841 f04df13fc851 (diff)
child 6847 c1d33aff7715
backport stable
doc/book/en/images/blog-demo-first-page.png
doc/book/en/images/cbw-add-relation-entryof_en.png
doc/book/en/images/cbw-create-blog_en.png
doc/book/en/images/cbw-detail-one-blogentry_en.png
doc/book/en/images/cbw-list-one-blog_en.png
doc/book/en/images/cbw-list-two-blog_en.png
doc/book/en/images/cbw-schema_en.png
doc/book/en/images/cbw-update-primary-view_en.png
doc/book/en/images/lax-book_06-header-no-login_en.png
doc/book/en/images/lax-book_06-main-template-layout_en.png
doc/book/en/images/lax-book_06-simple-main-template_en.png
doc/book/en/images/login-form.png
doc/book/en/tutorials/base/components.rst
doc/book/en/tutorials/base/create-cube.rst
doc/book/en/tutorials/base/maintemplate.rst
i18n/en.po
i18n/fr.po
--- a/doc/book/en/devrepo/testing.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/devrepo/testing.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -196,13 +196,13 @@
             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.assertEqual(len(MAILBOX), 0)
             self.commit()
-            self.assertEquals(len(MAILBOX), 2)
+            self.assertEqual(len(MAILBOX), 2)
             mail = MAILBOX[0]
-            self.assertEquals(mail.subject, '[data] hop')
+            self.assertEqual(mail.subject, '[data] hop')
             mail = MAILBOX[1]
-            self.assertEquals(mail.subject, '[data] yes')
+            self.assertEqual(mail.subject, '[data] yes')
 
 Visible actions tests
 `````````````````````
@@ -229,7 +229,7 @@
         def test_admin(self):
             req = self.request()
             rset = req.execute('Any C WHERE C is Conference')
-            self.assertListEquals(self.pactions(req, rset),
+            self.assertListEqual(self.pactions(req, rset),
                                   [('workflow', workflow.WorkflowActions),
                                    ('edit', confactions.ModifyAction),
                                    ('managepermission', actions.ManagePermissionsAction),
@@ -238,7 +238,7 @@
                                    ('generate_badge_action', badges.GenerateBadgeAction),
                                    ('addtalkinconf', confactions.AddTalkInConferenceAction)
                                    ])
-            self.assertListEquals(self.action_submenu(req, rset, 'addrelated'),
+            self.assertListEqual(self.action_submenu(req, rset, 'addrelated'),
                                   [(u'add Track in_conf Conference object',
                                     u'http://testing.fr/cubicweb/add/Track'
                                     u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&'
--- a/doc/book/en/devweb/request.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/devweb/request.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -1,5 +1,5 @@
-The `Request` class (`cubicweb.web`)
-------------------------------------
+The `Request` class (`cubicweb.web.request`)
+--------------------------------------------
 
 Overview
 ````````
@@ -7,7 +7,8 @@
 A request instance is created when an HTTP request is sent to the web
 server.  It contains informations such as form parameters,
 authenticated user, etc. It is a very prevalent object and is used
-throughout all of the framework and applications.
+throughout all of the framework and applications, as you'll access to
+almost every resources through it.
 
 **A request represents a user query, either through HTTP or not (we
 also talk about RQL queries on the server side for example).**
@@ -24,8 +25,8 @@
 
 * `User and identification`:
 
-  * `user`, instance of `cubicweb.common.utils.User` corresponding to
-    the authenticated user
+  * `user`, instance of `cubicweb.entities.authobjs.CWUser` corresponding to the
+    authenticated user
 
 * `Session data handling`
 
--- a/doc/book/en/devweb/views/views.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/devweb/views/views.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -88,7 +88,7 @@
 
 Other basic view classes
 ````````````````````````
-Here are some of the subclasses of `View` defined in `cubicweb.common.view`
+Here are some of the subclasses of `View` defined in `cubicweb.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)
Binary file doc/book/en/images/blog-demo-first-page.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-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-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-update-primary-view_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-simple-main-template_en.png has changed
Binary file doc/book/en/images/login-form.png has changed
Binary file doc/book/en/images/tutos-base_blog-form_en.png has changed
Binary file doc/book/en/images/tutos-base_blog-primary-after-post-creation_en.png has changed
Binary file doc/book/en/images/tutos-base_blog-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_blogs-list_en.png has changed
Binary file doc/book/en/images/tutos-base_form-generic-relations_en.png has changed
Binary file doc/book/en/images/tutos-base_index_en.png has changed
Binary file doc/book/en/images/tutos-base_login-form_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-custom-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-default-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-taggable-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-custom-footer_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-schema_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-siteinfo_en.png has changed
Binary file doc/book/en/images/tutos-base_schema_en.png has changed
Binary file doc/book/en/images/tutos-base_siteconfig_en.png has changed
Binary file doc/book/en/images/tutos-base_user-menu_en.png has changed
--- a/doc/book/en/tutorials/advanced/index.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/advanced/index.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -66,25 +66,35 @@
   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:
+Ok, now I'll tell my cube requires all this by editing :file:`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__)
+    __depends__ = {'cubicweb': '>= 3.8.0',
+                   'cubicweb-file': '>= 1.2.0',
+		   'cubicweb-folder': '>= 1.1.0',
+		   'cubicweb-person': '>= 1.2.0',
+		   'cubicweb-comment': '>= 1.2.0',
+		   'cubicweb-tag': '>= 1.2.0',
+		   'cubicweb-zone': None}
 
 Notice that you can express minimal version of the cube that should be used,
-`None` meaning whatever version available.
+`None` meaning whatever version available. All packages starting with 'cubicweb-'
+will be recognized as being cube, not bare python packages. You can still specify
+this explicitly using instead the `__depends_cubes__` dictionary which should
+contains cube's name without the prefix. So the example below would be written
+as:
+
+  .. sourcecode:: python
+
+    __depends__ = {'cubicweb': '>= 3.8.0'}
+    __depends_cubes__ = {'file': '>= 1.2.0',
+		         'folder': '>= 1.1.0',
+		   	 'person': '>= 1.2.0',
+		   	 'comment': '>= 1.2.0',
+		   	 'tag': '>= 1.2.0',
+		   	 'zone': None}
+
 
 Step 3: glue everything together in my cube's schema
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -170,9 +180,11 @@
 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 users can see people
 * everyone can see classifier entities, such as tag and zone
@@ -226,6 +238,12 @@
 	cardinality = '11' # required
 
     class may_be_read_by(RelationDefinition):
+        __permissions__ = {
+	    'read':   ('managers', 'users'),
+	    'add':    ('managers',),
+	    'delete': ('managers',),
+	    }
+
 	subject = ('Folder', 'File', 'Image', 'Comment',)
 	object = 'CWUser'
 
@@ -241,6 +259,9 @@
 
 * the `parent` possible value will be used for visibility propagation
 
+* think to secure the `may_be_read_by` permissions, else any user can add/delte it
+  by default, which somewhat breaks our security model...
+
 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*:
 
@@ -541,7 +562,7 @@
 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: ::
 
-    $ rm tmpdb*
+    $ rm data/tmpdb*
 
 
 .. Note::
--- a/doc/book/en/tutorials/base/blog-in-five-minutes.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/base/blog-in-five-minutes.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -1,42 +1,70 @@
 .. -*- coding: utf-8 -*-
 
-.. _BlogFiveMinutes:
+.. _TutosBaseBlogFiveMinutes:
 
 Get a blog running in five minutes!
 -----------------------------------
 
-For Debian or Ubuntu users, first install the following packages (:ref:`DebianInstallation`)::
+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`).
+Windows or Mac OS X users 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::
+You'll be asked a few questions, and you can keep the default answer for most of
+them. The one question you'll have to think about is the database you'll want to
+use for that instance. For a quick test, if you don't have `postgresql` installed
+and configured (see :ref:`PostgresqlConfiguration`), it's highly recommended to
+choose `sqlite` when asked for which database driver to use, since it has a much
+simple setup (no database server needed).
+
+One the process is completed (including database initialisation), you can start
+your instance by using: ::
 
     cubicweb-ctl start -D myblog
 
-The -D option is the debugging mode of cubicweb, removing it will lauch the instance in the background.
+The `-D` option activates the debugging mode. Removing it will launch the instance
+as a daemon in the background, and ``cubicweb-ctl stop myblog`` will stop
+it in that case. 
+
+
+About file system permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Permission
-~~~~~~~~~~
+Unless you installed from sources, the above commands assume that you have root
+access to the :file:`/etc/` directory. In order to initialize your instance as a
+regular user, within your home directory, you can use the :envvar:`CW_MODE`
+environment variable: ::
 
-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.
+  export CW_MODE=user
+
+then create a :file:`~/etc/cubicweb.d` directory that will hold your instances.
+
+More information about how to configure your own environment is
+available in :ref:`ResourceMode`.
+
 
 Instance parameters
 ~~~~~~~~~~~~~~~~~~~
 
-If you would like to change some instance parameters, for example, the database host or the user name, edit the `source` file located in the /etc/cubicweb.d/myblog directory.
+If you would like to change database parameters such as the database host or the
+user name used to connect to the database, edit the `sources` file located in the
+:file:`/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.
+Other parameters, like web server or emails parameters, can be modified in the
+:file:`/etc/cubicweb.d/myblog/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.
+You'll have to restart the instance after modification in one of those files.
 
+This is it. Your blog is functional and running. Visit http://localhost:8080 and enjoy it!
 
--- a/doc/book/en/tutorials/base/components.rst	Fri Jan 14 08:10:41 2011 +0100
+++ /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/tutorials/base/conclusion.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/base/conclusion.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -3,11 +3,16 @@
 What's next?
 ------------
 
-In this chapter, we have seen have you can, right after the installation of *CubicWeb*, build a web application in five minutes by defining a data model. Everything is there already: views, templates, permissions, etc.
+In this tutorial, we have seen have you can, right after the installation of
+|cubicweb|, build a web application in a few minutes by defining a data model as
+assembling cubes. You get a working application that you can then customize there
+and there while keeping something that works. This is important in agile
+development practices, you can right from the start of the project show things
+to customer and so take the right decision early in the process.
 
-The next step is to change the design and learn about the many features available to customize and extend your application: RSS channels (:ref:`XmlAndRss`), events (:ref:`hooks`), support of sources such as
-Google App Engine (:ref:`GoogleAppEngineSource`), etc.
-
-You will find more `tutorials and howtos`_ in the blog published on the CubicWeb.org website.
+The next steps will be to discover hooks, security, data sources, digging deeper
+into view writing and interface customisation... Yet a lot of fun stuff to
+discover! You will find more `tutorials and howtos`_ in the blog published on the
+CubicWeb.org website.
 
 .. _`tutorials and howtos`: http://www.cubicweb.org/view?rql=Any+X+ORDERBY+D+DESC+WHERE+X+is+BlogEntry%2C+T+tags+X%2C+T+name+IN+%28%22tutorial%22%2C+%22howto%22%29%2C+X+creation_date+D
--- a/doc/book/en/tutorials/base/create-cube.rst	Fri Jan 14 08:10:41 2011 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,437 +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 do not define the look'n'feel and the design of your application. For that, you will use CSS and the files located '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_view`.
-
-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 is_instance
-  from cubicweb.web.views import primary
-
-  class BlogEntryPrimaryView(primary.PrimaryView):
-      __select__ = is_instance('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'
-
-        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__ = is_instance('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:
-
-.. sourcecode:: bash
-
-  cubicweb-ctl stop blogdemo
-
-3. start the cubicweb shell for your instance by running the following command:
-
-.. sourcecode:: bash
-
-  cubicweb-ctl shell blogdemo
-
-4. at the cubicweb shell prompt, execute:
-
-.. sourcecode:: python
-
- add_attribute('Blog', 'category')
-
-5. restart your instance:
-   
-.. sourcecode:: bash
-
-  cubicweb-ctl start blogdemo
-
-6. 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, etc. 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/customizing-the-application.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -0,0 +1,536 @@
+.. -*- coding: utf-8 -*-
+
+.. _TutosBaseCustomizingTheApplication:
+
+Customizing your application
+----------------------------
+
+So far so good. The point is that usually, you won't get enough by assembling
+cubes out-of-the-box. You will want to customize them, have a personal look and
+feel, add your own data model and so on. Or maybe start from scratch?
+
+So let's get a bit deeper and start coding our own cube. In our case, we want
+to customize the blog we created to add more features to it.
+
+
+Create your own cube
+~~~~~~~~~~~~~~~~~~~~
+
+First, notice that if you've installed |cubicweb| using Debian packages, you will
+need the additional ``cubicweb-dev`` package to get the commands necessary to
+|cubicweb| development. All `cubicweb-ctl` commands are described in details in
+:ref:`cubicweb-ctl`.
+
+Once your |cubicweb| development environment is set up, you can create a new
+cube::
+
+  cubicweb-ctl newcube myblog
+
+This will create in the cubes directory (:file:`/path/to/forest/cubes` for source
+installation, :file:`/usr/share/cubicweb/cubes` for Debian packages installation)
+a directory named :file:`blog` reflecting the structure described in
+:ref:`cubelayout`.
+
+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
+
+and then create your new cube using: ::
+
+  cubicweb-ctl newcube --directory=~/src/cubes myblog
+
+.. Note:
+
+   We previously used `myblog` as the name of our *instance*. We're now creating
+   a *cube* with the same name. Both are different things. We'll now try to
+   specify when we talk about one or another, but keep in mind this difference.
+
+
+Cube metadata
+~~~~~~~~~~~~~
+
+A simple set of metadata about your cube are stored in the :file:`__pkginfo__.py`
+file. In our case, we want to extend the blog cube, so we have to tell that our
+cube depends on this cube, by modifying the ``__depends__`` dictionary in that
+file:
+
+.. sourcecode:: python
+
+   __depends__ =  {'cubicweb': '>= 3.10.7',
+                   'cubicweb-blog': None}
+
+where the ``None`` means we do not depends on a particular version of the cube.
+
+
+Extending the data model
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The data model or schema is the core of your |cubicweb| application.  It defines
+the type of content your application will handle. It is defined in the file
+:file:`schema.py` of the cube.
+
+
+Defining our model
+******************
+
+For the sake of example, let's say we want a new entity type named `Community`
+with a name, a description. A `Community` will hold several blogs.
+
+.. sourcecode:: python
+
+  from yams.buildobjs import EntityType, RelationDefinition, String, RichString
+
+  class Community(EntityType):
+      name = String(maxsize=50, required=True)
+      description = RichString()
+
+  class community_blog(RelationDefinition):
+      subject = 'Community'
+      object = 'Blog'
+      cardinality = '*?'
+      composite = 'subject'
+
+The first step is the import from the :mod:`yams` package necessary classes to build
+the schema.
+
+This file defines the following:
+
+* a `Community` has a title and a description as attributes
+
+  - the name is a string that is required and can't be longer than 50 characters
+
+  - the description is a string that is not constrained and may contains rich
+    content such as HTML or Restructured text.
+
+* a `Community` may be linked to a `Blog` using the `community_blog` relation
+
+  - ``*`` means a community may be linked to 0 to N blog, ``?`` means a blog may
+    be linked to 0 to 1 community. For completeness, remember that you can also
+    use ``+`` for 1 to N, and ``1`` for single, mandatory relation (e.g. one to one);
+
+  - this is a composite relation where `Community` (e.g. the subject of the
+    relation) is the composite. That means that if you delete a community, its
+    blog will be deleted as well.
+
+Of course, there are a lot of other data types and things such as constraints,
+permissions, etc, that may be defined in the schema, but those won't be covered
+in this tutorial.
+
+Notice that our schema refers to the `Blog` entity type which is not defined
+here.  But we know this type is available since we depend on the `blog` cube
+which is defining it.
+
+
+Applying changes to the model into our instance
+***********************************************
+
+Now the problem is that we created an instance using the `blog` cube, not our
+`myblog` cube, so if we don't do anything there is no way that we'll see anything
+changing in the instance.
+
+One easy way, as we've no really valuable data in the instance would be to trash and recreated it::
+
+  cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
+  cubicweb-ctl delete myblog
+  cubicweb-ctl create myblog
+  cubicweb-ctl start -D myblog
+
+Another way is to add our cube to the instance using the cubicweb-ctl shell
+facility. It's a python shell connected to the instance with some special
+commands available to manipulate it (the same as you'll have in migration
+scripts, which are not covered in this tutorial). In that case, we're interested
+in the `add_cube` command: ::
+
+  $ cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
+  $ cubicweb-ctl shell myblog
+  entering the migration python shell
+  just type migration commands or arbitrary python code and type ENTER to execute it
+  type "exit" or Ctrl-D to quit the shell and resume operation
+  >>> add_cube('myblog')
+  >>>
+  $ cubicweb-ctl start -D myblog
+
+The `add_cube` command is enough since it automatically updates our
+application to the cube's schema. There are plenty of other migration
+commands of a more finer grain. They are described in :ref:`migration`
+
+As explained, leave the shell by typing Ctrl-D. If you restart the instance and
+take another look at the schema, you'll see that changes to the data model have
+actually been applied (meaning database schema updates and all necessary stuff
+has been done).
+
+.. image:: ../../images/tutos-base_myblog-schema_en.png
+   :alt: the instance schema after adding our cube
+
+If you follow the 'info' link in the user pop-up menu, you'll also see that the
+instance is using blog and myblog cubes.
+
+.. image:: ../../images/tutos-base_myblog-siteinfo_en.png
+   :alt: the instance schema after adding our cube
+
+You can now add some communities, link them to blog, etc... You'll see that the
+framework provides default views for this entity type (we have not yet defined any
+view for it!), and also that the blog primary view will show the community it's
+linked to if any. All this thanks to the model driven interface provided by the
+framework.
+
+You'll then be able to redefine each of them according to your needs
+and preferences. We'll now see how to do such thing.
+
+Defining your views
+~~~~~~~~~~~~~~~~~~~
+
+|cubicweb| provides a lot of standard views in directory
+:file:`cubicweb/web/views/`. We already talked about 'primary' and 'list' views,
+which are views which apply to one ore more entities.
+
+A view is defined by a python class which includes:
+
+  - an identifier: all objects used to build the user interface in |cubicweb| are
+    recorded in a registry and this identifier will be used as a key in that
+    registry. There may be multiple views for the same identifier.
+
+  - a *selector*, which is a kind of filter telling how well a view suit to a
+    particular context. When looking for a particular view (e.g. given an
+    identifier), |cubicweb| computes for each available view with that identifier
+    a score which is returned by the selector. Then the view with the highest
+    score is used. The standard library of selectors is in
+    :mod:`cubicweb.selector`.
+
+A view has a set of methods inherited from the :class:`cubicweb.view.View` class,
+though you usually don't derive directly from this class but from one of its more
+specific child class.
+
+Last but not least, |cubicweb| provides a set of default views accepting any kind
+of entities.
+
+Want a proof? Create a community as you've already done for other entity types
+through the index page, you'll then see something like that:
+
+.. image:: ../../images/tutos-base_myblog-community-default-primary_en.png
+   :alt: the default primary view for our community entity type
+
+
+If you notice the weird messages that appear in the page: those are messages
+generated for the new data model, which have no translation yet. To fix that,
+we'll have to use dedicated `cubicweb-ctl` commands:
+
+.. sourcecode: bash
+
+  cubicweb-ctl i18ncube myblog # build/update cube's message catalogs
+  # then add translation into .po file into the cube's i18n directory
+  cubicweb-ctl i18ninstance myblog # recompile instance's message catalogs
+  cubicweb-ctl restart -D myblog # instance has to be restarted to consider new catalogs
+
+You'll then be able to redefine each of them according to your needs and
+preferences. So let's see how to do such thing.
+
+Changing the layout of the application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The layout is the general organization of the pages in the site. Views that generate
+the layout are sometimes referred to as 'templates'. They are implemented in the
+framework in the module :mod:`cubicweb.web.views.basetemplates`. By overriding
+classes in this module, you can customize whatever part you wish of the default
+layout.
+
+But notice that |cubicweb| provides many other ways to customize the
+interface, thanks to actions and components (which you can individually
+(de)activate, control their location, customize their look...) as well as
+"simple" CSS customization. You should first try to achieve your goal using such
+fine grained parametrization rather then overriding a whole template, which usually
+embeds customisation access points that you may loose in the process.
+
+But for the sake of example, let's say we want to change the generic page
+footer...  We can simply add to the module ``views`` of our cube,
+e.g. :file:`cubes/myblog/views.py`, the code below:
+
+.. sourcecode:: python
+
+  from cubicweb.web.views import basetemplates
+
+  class MyHTMLPageFooter(basetemplates.HTMLPageFooter):
+
+      def footer_content(self):
+	  self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
+
+  def registration_callback(vreg):
+      vreg.register_all(globals().values(), __name__, (MyHTMLPageFooter,))
+      vreg.register_and_replace(MyHTMLPageFooter, basetemplates.HTMLPageFooter)
+
+
+* Our class inherits from the default page footer to ease getting things right,
+  but this is not mandatory.
+
+* When we want to write something to the output stream, we simply call `self.w`,
+  with *must be passed an unicode string*.
+
+* The latest function is the most exotic stuff. The point is that without it, you
+  would get an error at display time because the framework wouldn't be able to
+  choose which footer to use between :class:`HTMLPageFooter` and
+  :class:`MyHTMLPageFooter`, since both have the same selector, hence the same
+  score...  In this case, we want our footer to replace the default one, so we have
+  to define a :func:`registration_callback` function to control object
+  registration: the first instruction tells to register everything in the module
+  but the :class:`MyHTMLPageFooter` class, then the second to register it instead
+  of :class:`HTMLPageFooter`. Without this function, everything in the module is
+  registered blindly.
+
+.. Note::
+
+  When a view is modified while running in debug mode, 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.
+
+We will now have this simple footer on every page of the site.
+
+
+Primary view customization
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The 'primary' view (i.e. any view with the identifier set to 'primary') is the one used to
+display all the information about a single entity. The standard primary view is one
+of the most sophisticated views of all. It has several customisation points, but
+its power comes with `uicfg`, allowing you to control it without having to
+subclass it.
+
+However this is a bit off-topic for this first tutorial. Let's say we simply want a
+custom primary view for my `Community` entity type, using directly the view
+interface without trying to benefit from the default implementation (you should
+do that though if you're rewriting reusable cubes; everything is described in more
+details in :ref:`primary_view`).
+
+
+So... Some code! That we'll put again in the module ``views`` of our cube.
+
+.. sourcecode:: python
+
+  from cubicweb.selectors import is_instance
+  from cubicweb.web.views import primary
+
+  class CommunityPrimaryView(primary.PrimaryView):
+      __select__ = is_instance('Community')
+
+      def cell_call(self, row, col):
+          entity = self.cw_rset.get_entity(row, col)
+          self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+          if entity.description:
+              self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+What's going on here?
+
+* Our class inherits from the default primary view, here mainly to get the correct
+  view identifier, since we don't use any of its features.
+
+* We set on it a selector telling that it only applies when trying to display
+  some entity of the `Community` type. This is enough to get an higher score than
+  the default view for entities of this type.
+
+* View applying to entities usually have to define `cell_call` as entry point,
+  and are given `row` and `col` arguments tell to which entity in the result set
+  the view is applied. We can then get this entity from the result set
+  (`self.cw_rset`) by using the `get_entity` method.
+
+* To ease thing, we access our entity's attribute for display using its
+  printable_value method, which will handle formatting and escaping when
+  necessary. As you can see, you can also access attributes by their name on the
+  entity to get the raw value.
+
+
+You can now reload the page of the community we just created and see the changes.
+
+.. image:: ../../images/tutos-base_myblog-community-custom-primary_en.png
+   :alt: the custom primary view for our community entity type
+
+We've seen here a lot of thing you'll have to deal with to write views in
+|cubicweb|. The good news is that this is almost everything that is used to
+build higher level layers.
+
+.. Note::
+
+  As things get complicated and the volume of code in your cube increases, you can
+  of course still split your views module into a python package with subpackages.
+
+You can find more details about views and selectors in :ref:`Views`.
+
+
+Write entities to add logic in your data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+|cubicweb| provides an ORM to easily programmaticaly manipulate
+entities (just like the one we have fetched earlier by calling
+`get_entity` on a result set). By default, entity
+types are instances of the :class:`AnyEntity` class, which holds a set of
+predefined methods as well as property automatically generated for
+attributes/relations of the type it represents.
+
+You can redefine each entity to provide additional methods or whatever you want
+to help you write your application. Customizing an entity requires that your
+entity:
+
+- inherits from :class:`cubicweb.entities.AnyEntity` or any subclass
+
+- defines a :attr:`__regid__` linked to the corresponding data type of your schema
+
+You may then want to add your own methods, override default implementation of some
+method, etc...
+
+.. sourcecode:: python
+
+    from cubicweb.entities import AnyEntity, fetch_config
+
+
+    class Community(AnyEntity):
+        """customized class for Community entities"""
+        __regid__ = 'Community'
+
+        fetch_attrs, fetch_order = fetch_config(['name'])
+
+        def dc_title(self):
+            return self.name
+
+        def display_cw_logo(self):
+            return 'CubicWeb' in self.description
+
+In this example:
+
+* we used convenience :func:`fetch_config` function to tell which attributes
+  should be prefetched by the ORM when looking for some related entities of this
+  type, and how they should be ordered
+
+* we overrode the standard `dc_title` method, used in various place in the interface
+  to display the entity (though in this case the default implementation would
+  have had the same result)
+
+* we implemented here a method :meth:`display_cw_logo` which tests if the blog
+  entry title contains 'CW'.  It can then be used when you're writing code
+  involving 'Community' entities in your views, hooks, etc. For instance, you can
+  modify your previous views as follows:
+
+.. sourcecode:: python
+
+
+  class CommunityPrimaryView(primary.PrimaryView):
+      __select__ = is_instance('Community')
+
+      def cell_call(self, row, col):
+          entity = self.cw_rset.get_entity(row, col)
+          self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+          if entity.display_cw_logo():
+              self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+          if entity.description:
+              self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+Then each community whose description contains 'CW' is shown with the |cubicweb|
+logo in front of it.
+
+.. Note::
+
+  As for view, you don't have to restart your instance when modifying some entity
+  classes while your server is running in debug mode, the code will be
+  automatically reloaded.
+
+
+Extending the application by using more cubes!
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the goal of the |cubicweb| framework was to have truly reusable
+components. To do so, they must both behave nicely when plugged into the
+application and be easily customisable, from the data model to the user
+interface. And I think the result is pretty successful, thanks to system such as
+the selection mechanism and the choice to write views as python code which allows
+to build our page using true object oriented programming techniques, that no
+template language provides.
+
+
+A library of standard cubes is available from `CubicWeb Forge`_, to address a
+lot of common concerns such has manipulating people, files, things to do, etc. In
+our community blog case, we could be interested for instance in functionalities
+provided by the `comment` and `tag` cubes. The former provides threaded
+discussion functionalities, the latter a simple tag mechanism to classify content.
+Let's say we want to try those. We will first modify our cube's :file:`__pkginfo__.py`
+file:
+
+.. sourcecode:: python
+
+   __depends__ =  {'cubicweb': '>= 3.10.7',
+                   'cubicweb-blog': None,
+                   'cubicweb-comment': None,
+                   'cubicweb-tag': None}
+
+Now, we'll simply tell on which entity types we want to activate the 'comment'
+and 'tag' facilities by adding respectively the 'comments' and 'tags' relations on
+them in our schema (:file:`schema.py`).
+
+.. sourcecode:: python
+
+  class comments(RelationDefinition):
+      subject = 'Comment'
+      object = 'BlogEntry'
+      cardinality = '1*'
+      composite = 'object'
+
+  class tags(RelationDefinition):
+      subject = 'Tag'
+      object = ('Community', 'BlogEntry')
+
+
+So in the case above we activated comments on `BlogEntry` entities and tags on
+both `Community` and `BlogEntry`. Various views from both `comment` and `tag`
+cubes will then be automatically displayed when one of those relations is
+supported.
+
+Let's synchronize the data model as we've done earlier: ::
+
+
+  $ cubicweb-ctl stop myblog
+  $ cubicweb-ctl shell myblog
+  entering the migration python shell
+  just type migration commands or arbitrary python code and type ENTER to execute it
+  type "exit" or Ctrl-D to quit the shell and resume operation
+  >>> add_cubes('comment', 'tag')
+  >>>
+
+Then restart the instance. Let's look at a blog entry:
+
+.. image:: ../../images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png
+   :alt: the primary view for a blog entry with comments and tags activated
+
+As you can see, we now have a box displaying tags and a section proposing to add
+a comment and displaying existing one below the post. All this without changing
+anything in our views, thanks to the design of generic views provided by the
+framework. Though if we take a look at a community, we won't see the tags box!
+That's because by default this box try to locate itself in the left column within
+the white frame, and this column is handled by the primary view we
+hijacked. Let's change our view to make it more extensible, by keeping both our
+custom rendering but also extension points provided by the default
+implementation.
+
+
+.. sourcecode:: python
+
+  class CommunityPrimaryView(primary.PrimaryView):
+      __select__ = is_instance('Community')
+
+      def render_entity_title(self, entity):
+	  self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+
+      def render_entity_attributes(self, entity):
+	  if entity.display_cw_logo():
+	      self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+	  if entity.description:
+	      self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+It appears now properly:
+
+.. image:: ../../images/tutos-base_myblog-community-taggable-primary_en.png
+   :alt: the custom primary view for a community entry with tags activated
+
+You can control part of the interface independently from each others, piece by
+piece. Really.
+
+
+
+.. _`CubicWeb Forge`: http://www.cubicweb.org/project
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/tutorials/base/discovering-the-ui.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -0,0 +1,161 @@
+
+.. _TutosBaseDiscoveringTheUI:
+
+Discovering the web interface
+-----------------------------
+
+You can now access your web instance to create blogs and post messages
+by visiting the URL http://localhost:8080/.
+
+By default, anonymous access is disabled, so a login form will appear. If you
+asked to allow anonymous access when initializing the instance, click on the
+'login' link in the top right hand corner. To login, you need then use the admin
+account you specified at the time you initialized the database with
+``cubicweb-ctl create``.
+
+.. image:: ../../images/tutos-base_login-form_en.png
+   :alt: the login form
+
+
+Once authenticated, you can start playing with your instance. The default index
+page looks like the following:
+
+.. image:: ../../images/tutos-base_index_en.png
+   :alt: the index page
+
+
+Minimal configuration
+~~~~~~~~~~~~~~~~~~~~~
+
+Before creating entities, let's change that 'unset title' thing that appears
+here and there. This comes from a |cubicweb| system properties. To set it,
+click on the 'site configuration link' in the pop-up menu behind your login name
+in the upper left-hand corner
+
+.. image:: ../../images/tutos-base_user-menu_en.png
+   :alt: the user pop-up menu
+
+The site title is in the 'Ui' section. Simply set it to the desired value and
+click the 'validate' button.
+
+.. image:: ../../images/tutos-base_siteconfig_en.png
+   :alt: the site configuration form
+
+You should see a 'changes applied' message. You can now go back to the
+index page by clicking on the |cubicweb| logo in the upper left-hand corner.
+
+You will much likely still see 'unset title' at this point. This is because by
+default the index page is cached. Force a refresh of the page (by typing Ctrl-R
+in Firefox for instance) and you should now see the title you entered.
+
+
+Adding entities
+~~~~~~~~~~~~~~~
+
+The ``blog`` cube defines several entity types, among them ``Blog`` which is a
+container for ``BlogEntry`` (i.e. posts) on a particular topic. We can get a
+graphical view of the schema by clicking on the 'site schema' link in the user
+pop-up menu we've already seen:
+
+.. image:: ../../images/tutos-base_schema_en.png
+   :alt: graphical view of the schema (aka data-model)
+
+Nice isn't it? Notice that this, as most other stuff we'll see in this tutorial,
+is generated by the framework according to the model of the application. In our
+case, the model defined by the ``blog`` cube.
+
+Now let us create a few of these entities.
+
+
+Add a blog
+**********
+
+Clicking on the `[+]` at the left of the 'Blog' link on the index page will lead
+you to an HTML form to create a blog.
+
+.. image:: ../../images/tutos-base_blog-form_en.png
+   :alt: the blog creation form
+
+For instance, call this new blog 'Tech-blog' and type in 'everything about
+technology' as the description , then validate the form by clicking on
+'Validate'. You will be redirected to the `primary` view of the newly created blog.
+
+.. image:: ../../images/tutos-base_blog-primary_en.png
+   :alt: the blog primary view
+
+
+Add a blog post
+***************
+
+There are several ways to add a blog entry. The simplest is to click on the 'add
+blog entry' link in the actions box on viewing the blog you have just created.
+You will then see a form to create a post, with a 'blog entry of' field preset
+to the blog we're coming from. Enter a title, some content, click the 'validate'
+button and you're done. You will be redirected to the blog primary view, though you
+now see that it contains the blog post you've just created.
+
+.. image:: ../../images/tutos-base_blog-primary-after-post-creation_en.png
+   :alt: the blog primary view after creation of a post
+
+Notice there are some new boxes that appears in the left column.
+
+You can achieve the same thing by following the same path as we did for the blog
+creation, e.g. by clicking on the `[+]` at the left of the 'Blog entry' link on
+the index page. The diffidence being that since there is no context information,
+the 'blog entry of' selector won't be preset to the blog.
+
+
+If you click on the 'modify' link of the action box, you are back to
+the form to edit the entity you just created, except that the form now
+has another section with a combo-box entitled 'add relation'. It
+provisos a generic way to edit relations which don't appears in the
+above form. Choose the relation you want to add and a second combo box
+appears where you can pick existing entities.  If there are too many
+of them, you will be offered to navigate to the target entity, that is
+go away from the form and go back to it later, once you've selected
+the entity you want to link with.
+
+.. image:: ../../images/tutos-base_form-generic-relations_en.png
+   :alt: the generic relations combo box
+
+This combo box can't appear until the entity is actually created. That's why you
+haven't seen it at creation time. You could also have hit 'Apply' instead of
+'validate' and it would have showed up.
+
+
+About ui auto-adaptation
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the things that make |cubicweb| different of other frameworks is
+its automatic user interface that adapts itself according to the data being
+displayed. Let's see an example.
+
+If you go back to the home page an click on the 'Blog' link, you will be redirected
+to the primary view of the blog, the same we've seen earlier. Now, add another
+blog, go back to the index page, and click again on this link. You will see
+a very different view (namely the 'list' view).
+
+.. image:: ../../images/tutos-base_blogs-list_en.png
+   :alt: the list view when there are more than one blog to display
+
+This is because in the first case, the framework chose to use the 'primary'
+view since there was only one entity in the data to be displayed. Now that there
+are two entities, the 'list' view is more appropriate and hence is being used.
+
+There are various other places where |cubicweb| adapts to display data in the best
+way, the main being provided by the view *selection* mechanism that will be detailed
+later.
+
+
+Digging deeper
+~~~~~~~~~~~~~~
+
+By following principles explained below, you should now be able to
+create new users for your application, to configure with a finer
+grain, etc... You will notice that the index page lists a lot of types
+you don't know about. Most are built-in types provided by the framework
+to make the whole system work. You may ignore them in a first time and
+discover them as time goes.
+
+One thing that is worth playing with is the search box. It may be used in various
+way, from simple full text search to advanced queries using the :ref:`RQL` .
--- a/doc/book/en/tutorials/base/index.rst	Fri Jan 14 08:10:41 2011 +0100
+++ b/doc/book/en/tutorials/base/index.rst	Wed Jan 19 09:31:15 2011 +0100
@@ -1,30 +1,48 @@
 .. -*- coding: utf-8 -*-
 
-.. _Tutorial:
-
-.. _tuto_blog:
+.. _TutosBase:
 
-Building a simple blog
-======================
+Building a simple blog with |cubicweb|
+======================================
 
-*CubicWeb* is a semantic web application framework that favors reuse and
+|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.
+
+This tutorial is designed to help in your very first steps to start with
+|cubicweb|. We will tour through basic concepts such as:
 
-An `instance` is a specific installation of a cube and includes configuration
-files.
+* getting an application running by using existing components
+* discovering the default user interface
+* basic extending and customizing the look and feel of that application
+
+More advanced concepts are covered in :ref:`advanced_tutorial`.
 
 
-This tutorial will show how to create a `cube` and how to use it as an
-application to run an `instance`.
+.. _TutosBaseVocab:
+
+Some vocabulary
+---------------
+
+|cubicweb| comes with a few words of vocabulary that you should know to
+understand what we're talking about. To follow this tutorial, you should at least
+know that:
+
+* a `cube` is a component that usually includes a model defining some data types
+  and a set of views to display them. A cube can be built by assembling other
+  cubes;
+
+* an `instance` is a specific installation of one or more cubes and includes
+  configuration files, a web server and a database.
+
+Reading :ref:`Concepts` for more vocabulary will be required at some point.
+
+Now, let's start the hot stuff!
 
 .. toctree::
    :maxdepth: 2
 
    blog-in-five-minutes
-   create-cube
-   components
-   maintemplate
+   discovering-the-ui
+   customizing-the-application
    conclusion
--- a/doc/book/en/tutorials/base/maintemplate.rst	Fri Jan 14 08:10:41 2011 +0100
+++ /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
-
--- a/etwist/twconfig.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/etwist/twconfig.py	Wed Jan 19 09:31:15 2011 +0100
@@ -49,7 +49,7 @@
          {'type' : 'string',
           'default': "",
           'help': 'http server address on which to listen (default to everywhere)',
-          'group': 'web', 'level': 0,
+          'group': 'web', 'level': 1,
           }),
         ('max-post-length',
          {'type' : 'bytes',
--- a/hooks/integrity.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/hooks/integrity.py	Wed Jan 19 09:31:15 2011 +0100
@@ -79,8 +79,6 @@
         session = self.session
         pendingeids = session.transaction_data.get('pendingeids', ())
         pendingrtypes = session.transaction_data.get('pendingrtypes', ())
-        # poping key is not optional: if further operation trigger new deletion
-        # of relation, we'll need a new operation
         for eid, rtype in self.get_data():
             # recheck pending eids / relation types
             if eid in pendingeids:
@@ -301,8 +299,6 @@
         session = self.session
         pendingeids = session.transaction_data.get('pendingeids', ())
         neweids = session.transaction_data.get('neweids', ())
-        # poping key is not optional: if further operation trigger new deletion
-        # of composite relation, we'll need a new operation
         for eid, rtype in self.get_data():
             # don't do anything if the entity is being created or deleted
             if not (eid in pendingeids or eid in neweids):
--- a/i18n/en.po	Fri Jan 14 08:10:41 2011 +0100
+++ b/i18n/en.po	Wed Jan 19 09:31:15 2011 +0100
@@ -328,22 +328,22 @@
 msgstr "Relations"
 
 msgid "CWSource"
-msgstr ""
+msgstr "Data source"
 
 msgid "CWSourceHostConfig"
-msgstr ""
+msgstr "Host configuration"
 
 msgid "CWSourceHostConfig_plural"
-msgstr ""
+msgstr "Host configurations"
 
 msgid "CWSource_plural"
-msgstr ""
+msgstr "Data sources"
 
 msgid "CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "Unicity constraint"
 
 msgid "CWUniqueTogetherConstraint_plural"
-msgstr ""
+msgstr "Unicity constraints"
 
 msgid "CWUser"
 msgstr "User"
@@ -525,13 +525,13 @@
 msgstr "New relation"
 
 msgid "New CWSource"
-msgstr ""
+msgstr "New source"
 
 msgid "New CWSourceHostConfig"
-msgstr ""
+msgstr "New host configuration"
 
 msgid "New CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "New unicity constraint"
 
 msgid "New CWUser"
 msgstr "New user"
@@ -733,13 +733,13 @@
 msgstr "This relation"
 
 msgid "This CWSource"
-msgstr ""
+msgstr "This data source"
 
 msgid "This CWSourceHostConfig"
-msgstr ""
+msgstr "This host configuration"
 
 msgid "This CWUniqueTogetherConstraint"
-msgstr ""
+msgstr "This unicity constraint"
 
 msgid "This CWUser"
 msgstr "This user"
@@ -933,10 +933,10 @@
 msgstr "relation definition"
 
 msgid "add CWSourceHostConfig cw_host_config_of CWSource object"
-msgstr ""
+msgstr "host configuration"
 
 msgid "add CWUniqueTogetherConstraint constraint_of CWEType object"
-msgstr ""
+msgstr "unicity constraint"
 
 msgid "add CWUser in_group CWGroup object"
 msgstr "user"
@@ -1433,18 +1433,18 @@
 msgstr ""
 
 msgid "constraint_of"
-msgstr ""
+msgstr "constraint of"
 
 msgctxt "CWUniqueTogetherConstraint"
 msgid "constraint_of"
-msgstr ""
+msgstr "constraint of"
 
 msgctxt "CWEType"
 msgid "constraint_of_object"
-msgstr ""
+msgstr "constrained by"
 
 msgid "constraint_of_object"
-msgstr ""
+msgstr "constrained by"
 
 msgid "constraints"
 msgstr ""
@@ -1540,7 +1540,7 @@
 msgid ""
 "creating CWUniqueTogetherConstraint (CWUniqueTogetherConstraint "
 "constraint_of CWEType %(linkto)s)"
-msgstr "creating unique together constrain for entity type %(linkto)s"
+msgstr "creating unique together constraint for entity type %(linkto)s"
 
 msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
 msgstr "creating a new user in group %(linkto)s"
@@ -3315,14 +3315,14 @@
 
 msgctxt "CWAttribute"
 msgid "relations_object"
-msgstr ""
-
-msgctxt "CWRelation"
+msgstr "constrained by"
+
+msgctxt "CWRType"
 msgid "relations_object"
-msgstr ""
+msgstr "constrained by"
 
 msgid "relations_object"
-msgstr ""
+msgstr "constrained by"
 
 msgid "relative url of the bookmarked page"
 msgstr ""
--- a/i18n/fr.po	Fri Jan 14 08:10:41 2011 +0100
+++ b/i18n/fr.po	Wed Jan 19 09:31:15 2011 +0100
@@ -347,10 +347,10 @@
 msgstr "Source de données"
 
 msgid "CWUniqueTogetherConstraint"
-msgstr "Contrainte unique_together"
+msgstr "Contrainte d'unicité"
 
 msgid "CWUniqueTogetherConstraint_plural"
-msgstr "Contraintes unique_together"
+msgstr "Contraintes d'unicité"
 
 msgid "CWUser"
 msgstr "Utilisateur"
--- a/schema.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/schema.py	Wed Jan 19 09:31:15 2011 +0100
@@ -83,7 +83,7 @@
                       'SubWorkflowExitPoint'))
 
 INTERNAL_TYPES = set(('CWProperty', 'CWPermission', 'CWCache', 'ExternalUri',
-                      'CWSource', 'CWSourceAlias',
+                      'CWSource', 'CWSourceHostConfig',
 ))
 
 
--- a/server/hook.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/server/hook.py	Wed Jan 19 09:31:15 2011 +0100
@@ -225,8 +225,9 @@
 
 
 Nothing precludes one to invent new categories and use the
-:class:`~cubicweb.server.session.hooks_control` context manager to filter them
-in or out.
+:class:`~cubicweb.server.session.hooks_control` context manager to
+filter them in or out. Note that ending the transaction with commit()
+or rollback() will restore the hooks.
 
 
 Hooks specific selector
@@ -299,6 +300,7 @@
                                key=lambda x: x.order)
                 with security_enabled(session, write=False):
                     for hook in hooks:
+                        #print hook.category, hook.__regid__
                         hook()
 
 class HooksManager(object):
@@ -371,8 +373,23 @@
 
 
 class match_rtype_sets(ExpectedValueSelector):
-    """accept if parameters specified as initializer arguments are specified
-    in named arguments given to the selector
+    """accept if the relation type is in one of the sets given as initializer
+    argument. The goal of this selector is that it keeps reference to original sets,
+    so modification to thoses sets are considered by the selector. For instance
+
+    MYSET = set()
+
+    class Hook1(Hook):
+        __regid__ = 'hook1'
+        __select__ = Hook.__select__ & match_rtype_sets(MYSET)
+        ...
+
+    class Hook2(Hook):
+        __regid__ = 'hook2'
+        __select__ = Hook.__select__ & match_rtype_sets(MYSET)
+
+    Client code can now change `MYSET`, this will changes the selection criteria
+    of :class:`Hook1` and :class:`Hook1`.
     """
 
     def __init__(self, *expected):
--- a/setup.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/setup.py	Wed Jan 19 09:31:15 2011 +0100
@@ -194,9 +194,10 @@
         old_ok = DS._ok
         def _ok(self, path):
             """Return True if ``path`` can be written during installation."""
-            out = old_ok(self, path)
+            out = old_ok(self, path) # here for side effect from setuptools
             realpath = os.path.normcase(os.path.realpath(path))
-            if realpath.startswith(sys.prefix):
+            allowed_path = os.path.normcase(sys.prefix)
+            if realpath.startswith(allowed_path):
                 out = True
             return out
         DS._ok = _ok
--- a/skeleton/__pkginfo__.py.tmpl	Fri Jan 14 08:10:41 2011 +0100
+++ b/skeleton/__pkginfo__.py.tmpl	Wed Jan 19 09:31:15 2011 +0100
@@ -8,13 +8,13 @@
 version = '.'.join(str(num) for num in numversion)
 
 license = '%(license)s'
-
 author = '%(author)s'
 author_email = '%(author-email)s'
+description = '%(shortdesc)s'
+web = 'http://www.cubicweb.org/project/%%s' %% distname
 
-description = '%(shortdesc)s'
-
-web = 'http://www.cubicweb.org/project/%%s' %% distname
+__depends__ =  %(dependencies)s
+__recommends__ = {}
 
 
 from os import listdir as _listdir
@@ -40,6 +40,3 @@
 # Note: here, you'll need to add subdirectories if you want
 # them to be included in the debian package
 
-__depends__ =  %(dependencies)s
-__recommends__ = {}
-
--- a/skeleton/setup.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/skeleton/setup.py	Wed Jan 19 09:31:15 2011 +0100
@@ -1,8 +1,25 @@
 #!/usr/bin/env python
-# pylint: disable=W0404,W0622,W0704,W0613
+# pylint: disable=W0142,W0403,W0404,W0613,W0622,W0622,W0704,R0904,C0103,E0611
+#
 # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-
+#
+# This file is part of CubicWeb tag cube.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
+"""Generic Setup script, takes package info from __pkginfo__.py file
+"""
 __docformat__ = "restructuredtext en"
 
 import os
@@ -12,49 +29,50 @@
 
 try:
     if os.environ.get('NO_SETUPTOOLS'):
-        raise ImportError()
+        raise ImportError() # do as there is no setuptools
     from setuptools import setup
     from setuptools.command import install_lib
-    USE_SETUPTOOLS = 1
+    USE_SETUPTOOLS = True
 except ImportError:
     from distutils.core import setup
     from distutils.command import install_lib
-    USE_SETUPTOOLS = 0
+    USE_SETUPTOOLS = False
+from distutils.command import install_data
 
-
-sys.modules.pop('__pkginfo__', None)
 # import required features
-from __pkginfo__ import modname, version, license, description, \
-     web, author, author_email
-# import optional features
-import __pkginfo__
-distname = getattr(__pkginfo__, 'distname', modname)
-scripts = getattr(__pkginfo__, 'scripts', [])
-data_files = getattr(__pkginfo__, 'data_files', None)
-include_dirs = getattr(__pkginfo__, 'include_dirs', [])
-ext_modules = getattr(__pkginfo__, 'ext_modules', None)
-dependency_links = getattr(__pkginfo__, 'dependency_links', [])
-
-STD_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build')
-
-IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~')
+from __pkginfo__ import modname, version, license, description, web, \
+     author, author_email
 
 if exists('README'):
     long_description = file('README').read()
 else:
     long_description = ''
+
+# import optional features
+import __pkginfo__
 if USE_SETUPTOOLS:
-   requires = {}
-   for entry in ("__depends__", "__recommends__"):
-      requires.update(getattr(__pkginfo__, entry, {}))
-   install_requires = [("%s %s" % (d, v and v or "")).strip()
+    requires = {}
+    for entry in ("__depends__",): # "__recommends__"):
+        requires.update(getattr(__pkginfo__, entry, {}))
+    install_requires = [("%s %s" % (d, v and v or "")).strip()
                        for d, v in requires.iteritems()]
 else:
-   install_requires = []
+    install_requires = []
+
+distname = getattr(__pkginfo__, 'distname', modname)
+scripts = getattr(__pkginfo__, 'scripts', ())
+include_dirs = getattr(__pkginfo__, 'include_dirs', ())
+data_files = getattr(__pkginfo__, 'data_files', None)
+ext_modules = getattr(__pkginfo__, 'ext_modules', None)
+dependency_links = getattr(__pkginfo__, 'dependency_links', ())
+
+BASE_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build')
+IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~')
 
 
 def ensure_scripts(linux_scripts):
-    """Creates the proper script names required for each platform
+    """
+    Creates the proper script names required for each platform
     (taken from 4Suite)
     """
     from distutils import util
@@ -64,23 +82,8 @@
         scripts_ = linux_scripts
     return scripts_
 
-def get_packages(directory, prefix):
-    """return a list of subpackages for the given directory"""
-    result = []
-    for package in os.listdir(directory):
-        absfile = join(directory, package)
-        if isdir(absfile):
-            if exists(join(absfile, '__init__.py')) or \
-                   package in ('test', 'tests'):
-                if prefix:
-                    result.append('%s.%s' % (prefix, package))
-                else:
-                    result.append(package)
-                result += get_packages(absfile, result[-1])
-    return result
-
 def export(from_dir, to_dir,
-           blacklist=STD_BLACKLIST,
+           blacklist=BASE_BLACKLIST,
            ignore_ext=IGNORED_EXTENSIONS,
            verbose=True):
     """make a mirror of from_dir in to_dir, omitting directories and files
@@ -134,6 +137,35 @@
                 dest = join(self.install_dir, base, directory)
                 export(directory, dest, verbose=False)
 
+# re-enable copying data files in sys.prefix
+old_install_data = install_data.install_data
+if USE_SETUPTOOLS:
+    # overwrite InstallData to use sys.prefix instead of the egg directory
+    class MyInstallData(old_install_data):
+        """A class that manages data files installation"""
+        def run(self):
+            _old_install_dir = self.install_dir
+            if self.install_dir.endswith('egg'):
+                self.install_dir = sys.prefix
+            old_install_data.run(self)
+            self.install_dir = _old_install_dir
+    try:
+        import setuptools.command.easy_install # only if easy_install avaible
+        # monkey patch: Crack SandboxViolation verification
+        from setuptools.sandbox import DirectorySandbox as DS
+        old_ok = DS._ok
+        def _ok(self, path):
+            """Return True if ``path`` can be written during installation."""
+            out = old_ok(self, path) # here for side effect from setuptools
+            realpath = os.path.normcase(os.path.realpath(path))
+            allowed_path = os.path.normcase(sys.prefix)
+            if realpath.startswith(allowed_path):
+                out = True
+            return out
+        DS._ok = _ok
+    except ImportError:
+        pass
+
 def install(**kwargs):
     """setup entry point"""
     if USE_SETUPTOOLS:
@@ -142,9 +174,13 @@
     # install-layout option was introduced in 2.5.3-1~exp1
     elif sys.version_info < (2, 5, 4) and '--install-layout=deb' in sys.argv:
         sys.argv.remove('--install-layout=deb')
-    if USE_SETUPTOOLS and install_requires:
+    cmdclass = {'install_lib': MyInstallLib}
+    if USE_SETUPTOOLS:
         kwargs['install_requires'] = install_requires
         kwargs['dependency_links'] = dependency_links
+        kwargs['zip_safe'] = False
+        cmdclass['install_data'] = MyInstallData
+
     return setup(name = distname,
                  version = version,
                  license = license,
@@ -156,7 +192,7 @@
                  scripts = ensure_scripts(scripts),
                  data_files = data_files,
                  ext_modules = ext_modules,
-                 cmdclass = {'install_lib': MyInstallLib},
+                 cmdclass = cmdclass,
                  **kwargs
                  )
 
--- a/web/uicfg.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/web/uicfg.py	Wed Jan 19 09:31:15 2011 +0100
@@ -128,6 +128,7 @@
 indexview_etype_section = InitializableDict(
     EmailAddress='subobject',
     # entity types in the 'system' table by default (managers only)
+    CWSource='system',
     CWUser='system', CWGroup='system',
     CWPermission='system',
     CWCache='system',
--- a/web/views/schema.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/web/views/schema.py	Wed Jan 19 09:31:15 2011 +0100
@@ -45,7 +45,7 @@
 ALWAYS_SKIP_TYPES = BASE_TYPES | SCHEMA_TYPES
 SKIP_TYPES  = (ALWAYS_SKIP_TYPES | META_RTYPES | SYSTEM_RTYPES | WORKFLOW_TYPES
                | INTERNAL_TYPES)
-SKIP_TYPES.update(set(('CWUser', 'CWGroup')))
+SKIP_TYPES.update(set(('CWUser', 'CWGroup', 'EmailAddress', 'Bookmark')))
 
 def skip_types(req):
     if int(req.form.get('skipmeta', True)):
--- a/web/views/sparql.py	Fri Jan 14 08:10:41 2011 +0100
+++ b/web/views/sparql.py	Wed Jan 19 09:31:15 2011 +0100
@@ -52,7 +52,7 @@
     __regid__ = 'sparql'
     def call(self):
         form = self._cw.vreg['forms'].select('sparql', self._cw)
-        self.w(form.render())
+        form.render(w=self.w)
         sparql = self._cw.form.get('sparql')
         vid = self._cw.form.get('resultvid', 'table')
         if sparql:
@@ -67,7 +67,7 @@
             else:
                 rql, args = qinfo.finalize()
                 if vid == 'sparqlxml':
-                    url = self._cw.build_url('view', rql=(rql,args), vid=vid)
+                    url = self._cw.build_url('view', rql=rql % args, vid=vid)
                     raise Redirect(url)
                 rset = self._cw.execute(rql, args)
                 self.wview(vid, rset, 'null')