--- a/cwconfig.py Fri Apr 23 13:36:43 2010 +0200
+++ b/cwconfig.py Mon Apr 26 12:52:48 2010 +0200
@@ -226,7 +226,7 @@
}),
('short-line-size',
{'type' : 'int',
- 'default': 40,
+ 'default': 80,
'help': _('maximum number of characters in short description'),
'group': 'navigation',
}),
--- a/devtools/testlib.py Fri Apr 23 13:36:43 2010 +0200
+++ b/devtools/testlib.py Mon Apr 26 12:52:48 2010 +0200
@@ -255,10 +255,10 @@
self.__class__._repo_init_failed = ex
raise
resume_tracing()
+ self._cnxs = []
self.setup_database()
self.commit()
MAILBOX[:] = [] # reset mailbox
- self._cnxs = []
def tearDown(self):
for cnx in self._cnxs:
--- a/doc/book/en/admin/additional-tips.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/additional-tips.rst Mon Apr 26 12:52:48 2010 +0200
@@ -1,40 +1,37 @@
.. _Additional Tips:
-Additional Tips
----------------
-
-Here are some additional tips as far as administration of a CubicWeb is concerned.
+Backups (mostly with postgresql)
+--------------------------------
-Backup, backup, backup
-``````````````````````
+It is always a good idea to backup. If your system does not do that,
+you should set it up. Note that whenever you do an upgrade,
+`cubicweb-ctl` offers you to backup your database. There are a number
+of ways for doing backups.
-It is always a good idea to backup. If your system does not do that, you should
-set it up. Note that whenever you do an upgrade, `cubicweb-ctl` offers you to
-backup your database. There are a number of ways for doing backups. Before you
+Using postgresql (and only that)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before you
go ahead, make sure the following permissions are correct ::
# chgrp postgres /var/lib/cubicweb/backup
-
# chmod g+ws /var/lib/cubicweb/backup
-
# chgrp postgres /etc/cubicweb.d/*<instance>*/sources
-
# chmod g+r /etc/cubicweb.d/*<instance>*/sources
-**Classic way on PostgreSQL server**
-
Simply use the pg_dump in a cron installed for `postgres` user on the database server::
# m h dom mon dow command
0 2 * * * pg_dump -Fc --username=cubicweb --no-owner <instance> > /var/backups/<instance>-$(date '+%Y-%m-%d_%H:%M:%S').dump
-**CubicWeb way**
+Using :command:`cubicweb-ctl db-dump`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The CubicWeb way is to use the `db-dump` command. For that, you have to put
-your passwords in a user-only-readable file at the home directory of root user.
-The file is `.pgpass` (`chmod 0600`), in this case for a socket run connection
-to PostgreSQL ::
+The CubicWeb way is to use the :command:`db-dump` command. For that,
+you have to put your passwords in a user-only-readable file at the
+home directory of root user. The file is `.pgpass` (`chmod 0600`), in
+this case for a socket run connection to PostgreSQL ::
/var/run/postgresql:5432:<instance>:<database user>:<database password>
@@ -45,7 +42,9 @@
# m h dom mon dow command
0 2 * * * cubicweb-ctl db-dump <instance>
-**The automated sysadmin way**
+
+Backup ninja
+~~~~~~~~~~~~
You can use a combination `backup-ninja`_ (which has a postgres script in the
example directory), `backuppc`)_ (for versionning).
@@ -56,3 +55,10 @@
.. _`here` : http://www.postgresql.org/docs/current/static/libpq-pgpass.html
.. _`backup-ninja` : https://labs.riseup.net/code/projects/show/backupninja/
.. _`backuppc` : http://backuppc.sourceforge.net/
+
+.. warning::
+
+ Remember that these indications will fail you whenever you use
+ another database backend than postgres. Also it does properly handle
+ externally managed data such as files (using the Bytes File System
+ Storage).
--- a/doc/book/en/admin/gae.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/gae.rst Mon Apr 26 12:52:48 2010 +0200
@@ -210,7 +210,7 @@
This cookie values needs to be provided to ``laxctl`` commands
in order to handle datastore administration requests.
-.. image:: ../images/lax-book.02-cookie-values.en.png
+.. image:: ../images/lax-book_02-cookie-values_en.png
:alt: displaying the detailed view of the cookie values returned
--- a/doc/book/en/admin/multisources.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/multisources.rst Mon Apr 26 12:52:48 2010 +0200
@@ -3,4 +3,4 @@
Data sources include SQL, LDAP, RQL, mercurial and subversion.
-XXX feed me
+.. XXX feed me
--- a/doc/book/en/admin/site-config.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/admin/site-config.rst Mon Apr 26 12:52:48 2010 +0200
@@ -3,7 +3,7 @@
User interface for web site configuration
=========================================
-.. image:: ../images/lax-book.03-site-config-panel.en.png
+.. image:: ../images/lax-book_03-site-config-panel_en.png
This panel allows you to configure the appearance of your instance site.
Six menus are available and we will go through each of them to explain how
--- a/doc/book/en/annexes/cookbook.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Cook book
-=========
-
-We gathered together some of our tricks and scripts that could make
-life easier.
-
-
-* How to import LDAP users in *CubicWeb*?
-
- [XXX distribute this script with cubicweb instead]
-
- Here is a very useful script which enables you to import LDAP users
- into your *CubicWeb* instance by running the following:
-
-.. sourcecode:: python
-
- import os
- import pwd
- import sys
-
- from logilab.common.db import get_connection
-
- def getlogin():
- """avoid usinng os.getlogin() because of strange tty / stdin problems
- (man 3 getlogin)
- Another solution would be to use $LOGNAME, $USER or $USERNAME
- """
- return pwd.getpwuid(os.getuid())[0]
-
-
- try:
- database = sys.argv[1]
- except IndexError:
- print 'USAGE: python ldap2system.py <database>'
- sys.exit(1)
-
- if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'):
- cnx = get_connection(user=getlogin(), database=database)
- cursor = cnx.cursor()
-
- insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, firstname, surname, last_login_time, upassword) '
- "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, %(surname)s, %(mtime)s, './fqEz5LeZnT6');")
- update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;"
- cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'")
- for eid, type, source, extid, mtime in cursor.fetchall():
- if type != 'CWUser':
- print "don't know what to do with entity type", type
- continue
- if source != 'ldapuser':
- print "don't know what to do with source type", source
- continue
- ldapinfos = dict(x.strip().split('=') for x in extid.split(','))
- login = ldapinfos['uid']
- firstname = ldapinfos['uid'][0].upper()
- surname = ldapinfos['uid'][1:].capitalize()
- if login != 'jcuissinat':
- args = dict(eid=eid, type=type, source=source, login=login,
- firstname=firstname, surname=surname, mtime=mtime)
- print args
- cursor.execute(insert, args)
- cursor.execute(update, args)
-
- cnx.commit()
- cnx.close()
-
-
-* How to load data from a script?
-
- The following script aims at loading data within a script assuming pyro-nsd is
- running and your instance is configured with ``pyro-server=yes``, otherwise
- you would not be able to use dbapi.
-
-.. sourcecode:: python
-
- from cubicweb import dbapi
-
- cnx = dbapi.connection(database='instance-id', user='admin', password='admin')
- cur = cnx.cursor()
- for name in ('Personal', 'Professional', 'Computers'):
- cur.execute('INSERT Blog B: B name %s', name)
- cnx.commit()
-
-
--- a/doc/book/en/annexes/faq.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/faq.rst Mon Apr 26 12:52:48 2010 +0200
@@ -249,7 +249,7 @@
By default all instance will look for a ``logo.png`` to be
rendered in the logo section.
- .. image:: ../images/lax-book.06-main-template-logo.en.png
+ .. image:: ../images/lax-book_06-main-template-logo_en.png
2. In your cube directory, you can specify which file to use for the logo.
This is configurable in ``mycube/data/external_resources``: ::
@@ -290,6 +290,66 @@
You can find additional information in the section :ref:`LDAP`.
+How to import LDAP users in |cubicweb| ?
+----------------------------------------
+
+ Here is a useful script which enables you to import LDAP users
+ into your *CubicWeb* instance by running the following:
+
+.. sourcecode:: python
+
+ import os
+ import pwd
+ import sys
+
+ from logilab.common.db import get_connection
+
+ def getlogin():
+ """avoid usinng os.getlogin() because of strange tty / stdin problems
+ (man 3 getlogin)
+ Another solution would be to use $LOGNAME, $USER or $USERNAME
+ """
+ return pwd.getpwuid(os.getuid())[0]
+
+
+ try:
+ database = sys.argv[1]
+ except IndexError:
+ print 'USAGE: python ldap2system.py <database>'
+ sys.exit(1)
+
+ if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'):
+ cnx = get_connection(user=getlogin(), database=database)
+ cursor = cnx.cursor()
+
+ insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, '
+ ' firstname, surname, last_login_time, upassword) '
+ "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, "
+ "%(surname)s, %(mtime)s, './fqEz5LeZnT6');")
+ update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;"
+ cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'")
+ for eid, type, source, extid, mtime in cursor.fetchall():
+ if type != 'CWUser':
+ print "don't know what to do with entity type", type
+ continue
+ if source != 'ldapuser':
+ print "don't know what to do with source type", source
+ continue
+ ldapinfos = dict(x.strip().split('=') for x in extid.split(','))
+ login = ldapinfos['uid']
+ firstname = ldapinfos['uid'][0].upper()
+ surname = ldapinfos['uid'][1:].capitalize()
+ if login != 'jcuissinat':
+ args = dict(eid=eid, type=type, source=source, login=login,
+ firstname=firstname, surname=surname, mtime=mtime)
+ print args
+ cursor.execute(insert, args)
+ cursor.execute(update, args)
+
+ cnx.commit()
+ cnx.close()
+
+
I get NoSelectableObject exceptions, how do I debug selectors ?
---------------------------------------------------------------
--- a/doc/book/en/annexes/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -13,7 +13,6 @@
:numbered:
faq
- cookbook
cubicweb-ctl
rql/index
mercurial
--- a/doc/book/en/annexes/rql/implementation.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/rql/implementation.rst Mon Apr 26 12:52:48 2010 +0200
@@ -128,7 +128,7 @@
- The current implementation does not support linking two relations of type 'is'
with an OR. I do not think that the negation is supported on this type of
- relation (XXX FIXME to be confirmed).
+ relation (XXX to be confirmed).
- Relations defining the variables must be left to those using them. For
example::
--- a/doc/book/en/annexes/rql/intro.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/rql/intro.rst Mon Apr 26 12:52:48 2010 +0200
@@ -1,3 +1,5 @@
+
+.. _rql_intro:
Introduction
------------
--- a/doc/book/en/annexes/rql/language.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/annexes/rql/language.rst Mon Apr 26 12:52:48 2010 +0200
@@ -92,8 +92,7 @@
Any X WHERE X name IN ( 'chauvat', 'fayolle', 'di mascio', 'thenault')
-XXX nico: "A trick <> 'bar'" wouldn't it be more convenient than
-"NOT A trick 'bar'" ?
+.. XXX nico: "A trick <> 'bar'" wouldn't it be more convenient than "NOT A trick 'bar'" ?
.. _PriorityOperators:
--- a/doc/book/en/development/cubes/available-cubes.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-
-Available cubes
----------------
-
-An instance is based on several basic cubes. In the set of available
-basic cubes we can find for example :
-
-Base entity types
-~~~~~~~~~~~~~~~~~
-* addressbook_: PhoneNumber and PostalAddress
-* card_: Card, generic documenting card
-* event_: Event (define events, display them in calendars)
-* file_: File (to allow users to upload and store binary or text files)
-* link_: Link (to collect links to web resources)
-* mailinglist_: MailingList (to reference a mailing-list and the URLs
- for its archives and its admin interface)
-* person_: Person (easily mixed with addressbook)
-* task_: Task (something to be done between start and stop date)
-* zone_: Zone (to define places within larger places, for example a
- city in a state in a country)
-
-
-Classification
-~~~~~~~~~~~~~~
-* folder_: Folder (to organize things but grouping them in folders)
-* keyword_: Keyword (to define classification schemes)
-* tag_: Tag (to tag anything)
-
-Other features
-~~~~~~~~~~~~~~
-* basket_: Basket (like a shopping cart)
-* blog_: a blogging system uxing Blog and BlogEntry entity types
-* comment_: system to attach comment threads to entities)
-* email_: archiving management for emails (`Email`, `Emailpart`,
- `Emailthread`), trigger action in cubicweb through email
-
-
-
-
-
-.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
-.. _basket: http://www.cubicweb.org/project/cubicweb-basket
-.. _card: http://www.cubicweb.org/project/cubicweb-card
-.. _blog: http://www.cubicweb.org/project/cubicweb-blog
-.. _comment: http://www.cubicweb.org/project/cubicweb-comment
-.. _email: http://www.cubicweb.org/project/cubicweb-email
-.. _event: http://www.cubicweb.org/project/cubicweb-event
-.. _file: http://www.cubicweb.org/project/cubicweb-file
-.. _folder: http://www.cubicweb.org/project/cubicweb-folder
-.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
-.. _link: http://www.cubicweb.org/project/cubicweb-link
-.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
-.. _person: http://www.cubicweb.org/project/cubicweb-person
-.. _tag: http://www.cubicweb.org/project/cubicweb-tag
-.. _task: http://www.cubicweb.org/project/cubicweb-task
-.. _zone: http://www.cubicweb.org/project/cubicweb-zone
-
-To declare the use of a component, once installed, add the name of the component
-to the variable `__use__` in the file `__pkginfo__.py` of your own component.
-
-.. note::
- The listed cubes above are available as debian-packages on `CubicWeb's forge`_.
-
-.. _`CubicWeb's forge`: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
--- a/doc/book/en/development/cubes/cc-newcube.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-Creating a new cube from scratch using :command:`cubicweb-ctl newcube`
-----------------------------------------------------------------------
-
-Let's start by creating the cube environment in which we will develop ::
-
- cd ~/hg
- # use cubicweb-ctl to generate a template for the cube
- cubicweb-ctl newcube mycube # will ask some questions, most with nice default
- # makes the cube source code managed by mercurial
- cd mycube
- hg init
- hg add .
- hg ci
-
-If all went well, you should see the cube you just created in the list
-returned by ``cubicweb-ctl list`` in the section *Available cubes*,
-and if it is not the case please refer to :ref:`ConfigurationEnv`.
-
-To reuse an existing cube, add it to the list named ``__use__`` and defined in
-:file:`__pkginfo__.py`. This variable is used for the instance packaging
-(dependencies handled by system utility tools such as APT) and the usable cubes
-at the time the base is created (import_erschema('MyCube') will not properly
-work otherwise).
-
-.. note::
-
- Please note that if you do not wish to use default directory for your cubes
- library, you should set the :envvar:`CW_CUBES_PATH` environment variable to
- add extra directories where cubes will be search, and you'll then have to use
- the option `--directory` to specify where you would like to place the source
- code of your cube:
-
- ``cubicweb-ctl newcube --directory=/path/to/cubes/library mycube``
-
-
-.. XXX resurrect once live-server is back
-.. Usage of :command:`cubicweb-ctl liveserver`
-.. -------------------------------------------
-
-.. To quickly test a new cube, you can also use the `liveserver` command for cubicweb-ctl
-.. which allows to create an instance in memory (using an SQLite database by
-.. default) and make it accessible through a web server ::
-
-.. cubicweb-ctl live-server mycube
-
-.. or by using an existing database (SQLite or Postgres)::
-
-.. cubicweb-ctl live-server -s myfile_sources mycube
--- a/doc/book/en/development/cubes/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-Cubes
-=====
-
-This chapter describes how to define your own cubes and reuse already available cubes.
-
-.. toctree::
- :maxdepth: 1
-
- layout.rst
- cc-newcube.rst
- available-cubes.rst
--- a/doc/book/en/development/cubes/layout.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-
-.. _foundationsCube:
-
-.. _cubelayout:
-
-Standard structure for a cube
------------------------------
-
-A cube is structured as follows:
-
-::
-
- mycube/
- |
- |-- data/
- | |-- cubes.mycube.css
- | |-- cubes.mycube.js
- | `-- external_resources
- |
- |-- debian/
- | |-- changelog
- | |-- compat
- | |-- control
- | |-- copyright
- | |-- cubicweb-mycube.prerm
- | `-- rules
- |
- |-- entities.py
- |
- |-- i18n/
- | |-- en.po
- | |-- es.po
- | `-- fr.po
- |
- |-- __init__.py
- |
- |-- MANIFEST.in
- |
- |-- migration/
- | |-- postcreate.py
- | `-- precreate.py
- |
- |-- __pkginfo__.py
- |
- |-- schema.py
- |
- |-- setup.py
- |
- |-- site_cubicweb.py
- |
- |-- hooks.py
- |
- |-- test/
- | |-- data/
- | | `-- bootstrap_cubes
- | |-- pytestconf.py
- | |-- realdb_test_mycube.py
- | `-- test_mycube.py
- |
- `-- views.py
-
-
-We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
-``schema.py`` or ``hooks.py``. For example, we could have:
-
-::
-
- mycube/
- |
- |-- entities.py
- |-- hooks.py
- `-- views/
- |-- forms.py
- |-- primary.py
- `-- widgets.py
-
-
-where :
-
-* ``schema`` contains the schema definition (server side only)
-* ``entities`` contains the entities definition (server side and web interface)
-* ``hooks`` contains hooks and/or views notifications (server side only)
-* ``views`` contains the web interface components (web interface only)
-* ``test`` contains tests related to the cube (not installed)
-* ``i18n`` contains message catalogs for supported languages (server side and
- web interface)
-* ``data`` contains data files for static content (images, css, javascripts)
- ...(web interface only)
-* ``migration`` contains initialization files for new instances (``postcreate.py``)
- and a file containing dependencies of the component depending on the version
- (``depends.map``)
-* ``debian`` contains all the files managing debian packaging (you will find
- the usual files ``control``, ``rules``, ``changelog``... not installed)
-* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
- and the current version (server side and web interface) or sub-cubes used by
- the cube.
-
-
-At least you should have:
-
-* the file ``__pkginfo__.py``
-* the schema definition
- XXX false, we may want to have cubes which are only adding a service,
- no persistent data (eg embedding for instance)
-
-
-
-The :file:`__init__.py` and :file:`site_cubicweb.py` files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :file:`__pkginfo__.py` file
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX contains metadata describing your cubes
- distname / modname
- version / numversion
- __use__
- __recommend__
-
-
-:file:`migration/precreate.py` and :file:`migration/postcreate.py`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX detail steps of instance creation
-
-
-External resources such as image, javascript and css files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX naming convention external_resources file
-
-
-Out-of the box testing
-~~~~~~~~~~~~~~~~~~~~~~
-XXX MANIFEST.in, __pkginfo__.include_dirs, debian
-
-
-
-Packaging and distribution
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX MANIFEST.in, __pkginfo__.include_dirs, debian
-
--- a/doc/book/en/development/datamodel/baseschema.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-.. _pre_defined_entity_types:
-
-Pre-defined entities in the library
------------------------------------
-
-The library defines a set of entity schemas that are required by the system
-or commonly used in *CubicWeb* instances.
-
-
-Entity types used to store the schema
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`CWEType`, entity type
-* _`CWRType`, relation type
-* _`CWRelation`, relation definition
-* _`CWAttribute`, attribute relation definition
-* _`CWConstraint`, `CWConstraintType`, `RQLExpression`
-
-Entity types used to manage users and permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`CWUser`, system users
-* _`CWGroup`, users groups
-* _`CWPermission`, used to configure the security of the instance
-
-Entity types used to manage workflows
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`Workflow`, workflow entity, linked to some entity types which may use this workflow
-* _`State`, workflow state
-* _`Transition`, workflow transition
-* _`TrInfo`, record of a transition trafic for an entity
-
-Other entity types
-~~~~~~~~~~~~~~~~~~
-* _`CWCache`, cache entities used to improve performances
-* _`CWProperty`, used to configure the instance
-
-* _`EmailAddress`, email address, used by the system to send notifications
- to the users and also used by others optionnals schemas
-
-* _`Bookmark`, an entity type used to allow a user to customize his links within
- the instance
-
-* _`ExternalUri`, used for semantic web site to indicate that an entity is the
- same as another from an external site
--- a/doc/book/en/development/datamodel/define-workflows.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Workflow:
-
-Define a Workflow
-=================
-
-General
--------
-
-A workflow describes how certain entities have to evolve between
-different states. Hence we have a set of states, and a "transition graph",
-i.e. a set of possible transitions from one state to another state.
-
-We will define a simple workflow for a blog, with only the following
-two states: `submitted` and `published`. So first, we create a simple
-*CubicWeb* instance in ten minutes (see :ref:`BlogFiveMinutes`).
-
-Set-up a workflow
------------------
-
-We want to create a workflow to control the quality of the BlogEntry
-submitted on the instance. When a BlogEntry is created by a user
-its state should be `submitted`. To be visible to all, it has to
-be in the state `published`. To move it from `submitted` to `published`,
-we need a transition that we can call `approve_blogentry`.
-
-A BlogEntry state should not be modifiable by every user.
-So we have to define a group of users, `moderators`, and
-this group will have appropriate permissions to publish a BlogEntry.
-
-There are two ways to create a workflow: from the user interface, or
-by defining it in ``migration/postcreate.py``. This script is executed
-each time a new ``cubicweb-ctl db-init`` is done. We strongly
-recommend to create the workflow in ``migration/postcreate.py`` and we
-will now show you how. Read `Two bits of warning`_ to understand why.
-
-The state of an entity is managed by the `in_state` attribute which
-can be added to your entity schema by inheriting from
-`cubicweb.schema.WorkflowableEntityType`.
-
-
-About our example of BlogEntry, we must have:
-
-.. sourcecode:: python
-
- from cubicweb.schema import WorkflowableEntityType
-
- class BlogEntry(WorkflowableEntityType):
- ...
-
-
-Create states, transitions and group permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The ``postcreate.py`` script is executed in a special environment, adding
-several *CubicWeb* primitives that can be used.
-
-They are all defined in the ``class ServerMigrationHelper``.
-We will only discuss the methods we use to create a workflow in this example.
-
-A workflow is a collection of entities of type ``State`` and of type
-``Transition`` which are standard *CubicWeb* entity types.
-
-To define a workflow for BlogDemo, please add the following lines
-to ``migration/postcreate.py``:
-
-.. sourcecode:: python
-
- _ = unicode
-
- moderators = add_entity('CWGroup', name=u"moderators")
-
-This adds the `moderators` user group.
-
-.. sourcecode:: python
-
- wf = add_workflow(u'blog publication workflow', 'BlogEntry')
-
-At first, instanciate a new workflow object with a gentle description
-and the concerned entity types (this one can be a tuple for multiple
-value).
-
-.. sourcecode:: python
-
- submitted = wf.add_state(_('submitted'), initial=True)
- published = wf.add_state(_('published'))
-
-This will create two entities of type ``State``, one with name
-'submitted', and the other with name 'published'.
-
-``add_state`` expects as first argument the name of the state you want
-to create and an optional argument to say if it is supposed to be the
-initial state of the entity type.
-
-.. sourcecode:: python
-
- wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
-
-This will create an entity of type ``Transition`` with name
-`approve_blogentry` which will be linked to the ``State`` entities
-created before.
-
-``add_transition`` expects
-
- * as the first argument: the name of the transition
- * then the list of states on which the transition can be triggered,
- * the target state of the transition,
- * and the permissions
- (e.g. a list of user groups who can apply the transition; the user
- has to belong to at least one of the listed group to perform the action).
-
-.. sourcecode:: python
-
- checkpoint()
-
-.. note::
- Do not forget to add the `_()` in front of all states and transitions names while creating
- a workflow so that they will be identified by the i18n catalog scripts.
-
-In addition to the user groups (one of which the user needs to belong
-to), we could have added a RQL condition. In this case, the user can
-only perform the action if the two conditions are satisfied.
-
-If we use an RQL condition on a transition, we can use the following variables:
-
-* `X`, the entity on which we may pass the transition
-* `U`, the user executing that may pass the transition
-
-
-.. image:: ../../images/03-transitions-view.en.png
-
-You can notice that in the action box of a BlogEntry, the state is now
-listed as well as the possible transitions for the current state
-defined by the workflow.
-
-The transitions will only be displayed for users having the right permissions.
-In our example, the transition `approve_blogentry` will only be displayed
-for the users belonging to the group `moderators` or `managers`.
-
-
-Two bits of warning
-~~~~~~~~~~~~~~~~~~~
-
-We could perfectly use the administration interface to do these
-operations. It is a convenient thing to do at times (when doing
-development, to quick-check things). But it is not recommended beyond
-that because it is a bit complicated to do it right and it will be
-only local to your instance (or, said a bit differently, such a
-workflow only exists in an instance database). Furthermore, you cannot
-write unit tests against deployed instances, and experience shows it
-is mandatory to have tests for any mildly complicated workflow
-setup.
-
-Indeed, if you create the states and transitions through the user
-interface, next time you initialize the database you will have to
-re-create all the workflow entities. The user interface should only be
-a reference for you to view the states and transitions, but is not the
-appropriate interface to define your application workflow.
--- a/doc/book/en/development/datamodel/definition.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,630 +0,0 @@
- .. -*- coding: utf-8 -*-
-
-Yams *schema*
--------------
-
-The **schema** is the core piece of a *CubicWeb* instance as it
-defines and handles the data model. It is based on entity types that
-are either already defined in `Yams`_ and the *CubicWeb* standard
-library; or more specific types defined in cubes. The schema for a
-cube is defined in a `schema` python module or package.
-
-.. _`Yams`: http://www.logilab.org/project/yams
-
-Overview
-~~~~~~~~
-
-The core idea of the yams schema is not far from the classical
-`Entity-relationship`_ model. But while an E/R model (or `logical
-model`) traditionally has to be manually translated to a lower-level
-data description language (such as the SQL `create table`
-sublanguage), also often described as the `physical model`, no such
-step is required with |yams| and |cubicweb|.
-
-.. _`Entity-relationship`: http://en.wikipedia.org/wiki/Entity-relationship_model
-
-This is because in addition to high-level, logical |yams| models, one
-uses the |rql| data manipulation language to query, insert, update and
-delete data. |rql| abstracts as much of the underlying SQL database as
-a |yams| schema abstracts from the physical layout. The vagaries of
-SQL are avoided.
-
-As a bonus point, such abstraction make it quite comfortable to build
-or use different backends to which |rql| queries apply.
-
-So, as in the E/R formalism, the building blocks are ``entities``
-(:ref:`EntityType`), ``relationships`` (:ref:`RelationType`,
-:ref:`RelationDefinition`) and ``attributes`` (handled like relation
-with |yams|).
-
-Let us detail a little the divergences between E/R and |yams|:
-
-* all relationship are binary which means that to represent a
- non-binary relationship, one has to use an entity,
-* relationships do not support attributes (yet, see:
- http://www.cubicweb.org/ticket/341318), hence the need to reify it
- as an entity if need arises,
-* all entities have an `eid` attribute (an integer) that is its
- primary key (but it is possible to declare uniqueness on other
- attributes)
-
-Also |yams| supports the notions of:
-
-* entity inheritance,
-* relation type: that is, relationships can be established over a set
- of couple of entity types (henre the distinction made between
- `RelationType` and `RelationDefinition` below)
-
-Finally |yams| has a few concepts of its own:
-
-* relationships being oriented and binary, we call the left hand
- entity type the `subject` and the right hand entity type the
- `object`
-
-.. note::
-
- The |yams| schema is available at run time through the .schema
- attribute of the `vregistry`. It's an instance of
- :class:`cubicweb.schema.Schema`, which extends
- :class:`yams.schema.Schema`.
-
-.. _EntityType:
-
-Entity type
-~~~~~~~~~~~
-
-An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
-a set of attributes and relations, and some permissions which define who can add, read,
-update or delete entities of this type.
-
-The following built-in types are available: ``String``, ``Int``,
-``Float``, ``Decimal``, ``Boolean``, ``Date``, ``Datetime``, ``Time``,
-``Interval``, ``Byte`` and ``Password``. They can only be used as
-attributes of an other entity type.
-
-You can find more base entity types in
-:ref:`pre_defined_entity_types`.
-
-.. XXX yams inheritance
-
-.. _RelationType:
-
-Relation type
-~~~~~~~~~~~~~
-
-A relation type is an instance of
-:class:`yams.schema.RelationSchema`. A relation type is simply a
-semantic definition of a kind of relationship that may occur in an
-application.
-
-It may be referenced by zero, one or more relation definitions.
-
-It is important to choose a good name, at least to avoid conflicts
-with some semantically different relation defined in other cubes
-(since there's only a shared name space for these names).
-
-A relation type holds the following properties (which are hence shared
-between all relation definitions of that type):
-
-* `inlined`: boolean handling the physical optimization for archiving
- the relation in the subject entity table, instead of creating a specific
- table for the relation. This applies to relations where cardinality
- of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
- definitions.
-
-* `symmetric`: boolean indicating that the relation is symmetrical, which
- means that `X relation Y` implies `Y relation X`.
-
-.. _RelationDefinition:
-
-Relation definition
-~~~~~~~~~~~~~~~~~~~
-
-A relation definition is an instance of
-:class:`yams.schema.RelationDefinition`. It is a complete triplet
-"<subject entity type> <relation type> <object entity type>".
-
-When creating a new instance of that class, the corresponding
-:class:`RelationType` instance is created on the fly if necessary.
-
-Properties
-``````````
-
-The available properties for relation definitions are enumerated
-here. There are several kind of properties, as some relation
-definitions are actually attribute definitions, and other are not.
-
-Some properties may be completely optional, other may have a default
-value.
-
-Common properties for attributes and relations:
-
-* `description`: an unicode string describing an attribute or a
- relation. By default this string will be used in the editing form of
- the entity, which means that it is supposed to help the end-user and
- should be flagged by the function `_` to be properly
- internationalized.
-
-* `constraints`: a list of conditions/constraints that the relation has to
- satisfy (c.f. `Constraints`_)
-
-* `cardinality`: a two character string specifying the cardinality of
- the relation. The first character defines the cardinality of the
- relation on the subject, and the second on the object. When a
- relation can have multiple subjects or objects, the cardinality
- applies to all, not on a one-to-one basis (so it must be
- consistent...). Default value is '**'. The possible values are
- inspired from regular expression syntax:
-
- * `1`: 1..1
- * `?`: 0..1
- * `+`: 1..n
- * `*`: 0..n
-
-Attributes properties:
-
-* `unique`: boolean indicating if the value of the attribute has to be
- unique or not within all entities of the same type (false by
- default)
-
-* `indexed`: boolean indicating if an index needs to be created for
- this attribute in the database (false by default). This is useful
- only if you know that you will have to run numerous searches on the
- value of this attribute.
-
-* `default`: default value of the attribute. In case of date types, the values
- which could be used correspond to the RQL keywords `TODAY` and `NOW`.
-
-Properties for `String` attributes:
-
-* `fulltextindexed`: boolean indicating if the attribute is part of
- the full text index (false by default) (*applicable on the type
- `Byte` as well*)
-
-* `internationalizable`: boolean indicating if the value of the
- attribute is internationalizable (false by default)
-
-Relation properties:
-
-* `composite`: string indicating that the subject (composite ==
- 'subject') is composed of the objects of the relations. For the
- opposite case (when the object is composed of the subjects of the
- relation), we just set 'object' as value. The composition implies
- that when the relation is deleted (so when the composite is deleted,
- at least), the composed are also deleted.
-
-* `fulltext_container`: string indicating if the value if the full
- text indexation of the entity on one end of the relation should be
- used to find the entity on the other end. The possible values are
- 'subject' or 'object'. For instance the use_email relation has that
- property set to 'subject', since when performing a full text search
- people want to find the entity using an email address, and not the
- entity representing the email address.
-
-Constraints
-```````````
-
-By default, the available constraint types are:
-
-General Constraints
-......................
-
-* `SizeConstraint`: allows to specify a minimum and/or maximum size on
- string (generic case of `maxsize`)
-
-* `BoundConstraint`: allows to specify a minimum and/or maximum value
- on numeric types and date
-
-.. sourcecode:: python
-
- from yams.constraints import BoundConstraint, TODAY
- BoundConstraint('<=', TODAY())
-
-* `IntervalBoundConstraint`: allows to specify an interval with
- included values
-
-.. sourcecode:: python
-
- class Node(EntityType):
- latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
-
-* `UniqueConstraint`: identical to "unique=True"
-
-* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
-
-.. XXX Attribute, NOW
-
-RQL Based Constraints
-......................
-
-RQL based constraints may take three arguments. The first one is the ``WHERE``
-clause of a RQL query used by the constraint. The second argument ``mainvars``
-is the ``Any`` clause of the query. By default this include `S` reserved for the
-subject of the relation and `O` for the object. Additional variables could be
-specified using ``mainvars``. The argument expects a single string with all
-variable's name separated by spaces. The last one, ``msg``, is the error message
-displayed when the constraint fails. As RQLVocabularyConstraint never fails the
-third argument is not available.
-
-* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
- by the subject and/or the object of relation. In this query the variables
- `S` and `O` are reserved for the relation subject and object entities.
-
-* `RQLVocabularyConstraint`: similar to the previous type of constraint except
- that it does not express a "strong" constraint, which means it is only used to
- restrict the values listed in the drop-down menu of editing form, but it does
- not prevent another entity to be selected.
-
-* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
- attribute is unique in a specific context. The Query must **never** return more
- than a single result to be satisfied. In this query the variables `S` is
- reserved for the relation subject entity. The other variables should be
- specified with the second constructor argument (mainvars). This constraints
- should be used when UniqueConstraint doesn't fit. Here is a simple example.
-
-.. sourcecode:: python
-
- # Check that in the same Workflow each state's name is unique. Using
- # UniqueConstraint (or unique=True) here would prevent states in different
- # workflows to have the same name.
-
- # With: State S, Workflow W, String N ; S state_of W, S name N
-
- RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
- mainvars='Y',
- msg=_('workflow already has a state of that name'))
-
-.. XXX note about how to add new constraint
-
-.. _securitymodel:
-
-The security model
-~~~~~~~~~~~~~~~~~~
-
-The security model of `CubicWeb` is based on `Access Control List`.
-The main principles are:
-
-* users and groups of users
-* a user belongs to at least one group of user
-* permissions (read, update, create, delete)
-* permissions are assigned to groups (and not to users)
-
-For *CubicWeb* in particular:
-
-* we associate rights at the entities/relations schema level
-* for each entity, we distinguish four kinds of permissions: `read`,
- `add`, `update` and `delete`
-* for each relation, we distinguish three kinds of permissions: `read`,
- `add` and `delete` (it is not possible to `modify` a relation)
-* the default groups are: `administrators`, `users` and `guests`
-* by default, users belong to the `users` group
-* there is a virtual group called `owners` to which we
- can associate only `delete` and `update` permissions
-
- * we can not add users to the `Owners` group, they are
- implicitly added to it according to the context of the objects
- they own
- * the permissions of this group are only checked on `update`/`delete`
- actions if all the other groups the user belongs to do not provide
- those permissions
-
-Setting permissions is done with the attribute `__permissions__` of entities and
-relation types. The value of this attribute is a dictionary where the keys are the access types
-(action), and the values are the authorized groups or expressions.
-
-For an entity type, the possible actions are `read`, `add`, `update` and
-`delete`.
-
-For a relation type, the possible actions are `read`, `add`, and `delete`.
-
-For each access type, a tuple indicates the name of the authorized groups and/or
-one or multiple RQL expressions to satisfy to grant access. The access is
-provided if the user is in one of the listed groups or if one of the RQL condition
-is satisfied.
-
-The standard user groups
-````````````````````````
-
-* `guests`
-
-* `users`
-
-* `managers`
-
-* `owners`: virtual group corresponding to the entity's owner.
- This can only be used for the actions `update` and `delete` of an entity
- type.
-
-It is also possible to use specific groups if they are defined in the
-precreate script of the cube (``migration/precreate.py``). Defining groups in
-postcreate script or later makes them unavailable for security
-purposes (in this case, an `sync_schema_props_perms` command has to
-be issued in a CubicWeb shell).
-
-
-Use of RQL expression for write permissions
-```````````````````````````````````````````
-It is possible to define RQL expression to provide update permission
-(`add`, `delete` and `update`) on relation and entity types.
-
-RQL expression for entity type permission:
-
-* you have to use the class `ERQLExpression`
-
-* the used expression corresponds to the WHERE statement of an RQL query
-
-* in this expression, the variables `X` and `U` are pre-defined references
- respectively on the current entity (on which the action is verified) and
- on the user who send the request
-
-* it is possible to use, in this expression, a special relation
- "has_<ACTION>_permission" where the subject is the user and the
- object is any variable, meaning that the user needs to have
- permission to execute the action <ACTION> on the entities related
- to this variable
-
-For RQL expressions on a relation type, the principles are the same except
-for the following:
-
-* you have to use the class `RRQLExpression` in the case of a non-final relation
-
-* in the expression, the variables `S`, `O` and `U` are pre-defined references
- to respectively the subject and the object of the current relation (on
- which the action is being verified) and the user who executed the query
-
-* we can also define rights over attributes of an entity (non-final relation),
- knowing that:
-
- - to define RQL expression, we have to use the class `ERQLExpression`
- in which `X` represents the entity the attribute belongs to
-
- - the permissions `add` and `delete` are equivalent. Only `add`/`read`
- are actually taken in consideration.
-
-.. note::
-
- Potentially, the `use of an RQL expression to add an entity or a
- relation` can cause problems for the user interface, because if the
- expression uses the entity or the relation to create, then we are
- not able to verify the permissions before we actually add the entity
- (please note that this is not a problem for the RQL server at all,
- because the permissions checks are done after the creation). In such
- case, the permission check methods (CubicWebEntitySchema.check_perm
- and has_perm) can indicate that the user is not allowed to create
- this entity but can obtain the permission. To compensate this
- problem, it is usually necessary, for such case, to use an action
- that reflects the schema permissions but which enables to check
- properly the permissions so that it would show up if necessary.
-
-
-Use of RQL expression for reading rights
-````````````````````````````````````````
-
-The principles are the same but with the following restrictions:
-
-* we can not use `RRQLExpression` on relation types for reading
-
-* special relations "has_<ACTION>_permission" can not be used
-
-
-
-
-Defining your schema using yams
--------------------------------
-
-Entity type definition
-~~~~~~~~~~~~~~~~~~~~~~
-
-An entity type is defined by a Python class which inherits from
-:class:`yams.buildobjs.EntityType`. The class definition contains the
-description of attributes and relations for the defined entity type.
-The class name corresponds to the entity type name. It is expected to
-be defined in the module ``mycube.schema``.
-
-:Note on schema definition:
-
- The code in ``mycube.schema`` is not meant to be executed. The class
- EntityType mentioned above is different from the EntitySchema class
- described in the previous chapter. EntityType is a helper class to
- make Entity definition easier. Yams will process EntityType classes
- and create EntitySchema instances from these class definitions. Similar
- manipulation happen for relations.
-
-When defining a schema using python files, you may use the following shortcuts:
-
-- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
-
-- `vocabulary`: specify static possible values of an attribute
-
-- `maxsize`: integer providing the maximum size of a string (no limit by default)
-
-For example:
-
-.. sourcecode:: python
-
- class Person(EntityType):
- """A person with the properties and the relations necessary for my
- application"""
-
- last_name = String(required=True, fulltextindexed=True)
- first_name = String(required=True, fulltextindexed=True)
- title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
- date_of_birth = Date()
- works_for = SubjectRelation('Company', cardinality='?*')
-
-
-The entity described above defines three attributes of type String,
-last_name, first_name and title, an attribute of type Date for the date of
-birth and a relation that connects a `Person` to another entity of type
-`Company` through the semantic `works_for`.
-
-:Naming convention:
-
- Entity class names must start with an uppercase letter. The common
- usage is to use ``CamelCase`` names.
-
- Attribute and relation names must start with a lowercase letter. The
- common usage is to use ``underscore_separated_words``. Attribute and
- relation names starting with a single underscore are permitted, to
- denote a somewhat "protected" or "private" attribute.
-
- In any case, identifiers starting with "CW" or "cw" are reserved for
- internal use by the framework.
-
-
-The name of the Python attribute corresponds to the name of the attribute
-or the relation in *CubicWeb* application.
-
-An attribute is defined in the schema as follows::
-
- attr_name = attr_type(properties)
-
-where `attr_type` is one of the type listed above and `properties` is
-a list of the attribute needs to satisfy (see `Properties`_
-for more details).
-
-* it is possible to use the attribute `meta` to flag an entity type as a `meta`
- (e.g. used to describe/categorize other entities)
-
-.. XXX the paragraph below needs clarification and / or moving out in
-.. another place
-
-*Note*: if you end up with an `if` in the definition of your entity, this probably
-means that you need two separate entities that implement the `ITree` interface and
-get the result from `.children()` which ever entity is concerned.
-
-Inheritance
-```````````
-XXX feed me
-
-
-Definition of relations
-~~~~~~~~~~~~~~~~~~~~~~~
-
-XXX add note about defining relation type / definition
-
-A relation is defined by a Python class heriting `RelationType`. The name
-of the class corresponds to the name of the type. The class then contains
-a description of the properties of this type of relation, and could as well
-contain a string for the subject and a string for the object. This allows to create
-new definition of associated relations, (so that the class can have the
-definition properties from the relation) for example ::
-
- class locked_by(RelationType):
- """relation on all entities indicating that they are locked"""
- inlined = True
- cardinality = '?*'
- subject = '*'
- object = 'CWUser'
-
-If provided, the `subject` and `object` attributes denote the subject
-and object of the various relation definitions related to the relation
-type. Allowed values for these attributes are:
-
-* a string corresponding to an entity type
-* a tuple of string corresponding to multiple entity types
-* special string such as follows:
-
- - "**": all types of entities
- - "*": all types of non-meta entities
- - "@": all types of meta entities but not system entities (e.g. used for
- the basic schema description)
-
-When a relation is not inlined and not symmetrical, and it does not require
-specific permissions, it can be defined using a `SubjectRelation`
-attribute in the EntityType class. The first argument of `SubjectRelation` gives
-the entity type for the object of the relation.
-
-:Naming convention:
-
- Although this way of defining relations uses a Python class, the
- naming convention defined earlier prevails over the PEP8 conventions
- used in the framework: relation type class names use
- ``underscore_separated_words``.
-
-:Historical note:
-
- It has been historically possible to use `ObjectRelation` which
- defines a relation in the opposite direction. This feature is soon to be
- deprecated and therefore should not be used in newly written code.
-
-:Future deprecation note:
-
- In an even more remote future, it is quite possible that the
- SubjectRelation shortcut will become deprecated, in favor of the
- RelationType declaration which offers some advantages in the context
- of reusable cubes.
-
-Definition of permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-The entity type `CWPermission` from the standard library
-allows to build very complex and dynamic security architectures. The schema of
-this entity type is as follow:
-
-.. sourcecode:: python
-
- class CWPermission(EntityType):
- """entity type that may be used to construct some advanced security configuration
- """
- name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
- require_group = SubjectRelation('CWGroup', cardinality='+*',
- description=_('groups to which the permission is granted'))
- require_state = SubjectRelation('State',
- description=_("entity's state in which the permission is applicable"))
- # can be used on any entity
- require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
- description=_("link a permission to the entity. This "
- "permission should be used in the security "
- "definition of the entity's type to be useful."))
-
-
-Example of configuration:
-
-.. sourcecode:: python
-
- class Version(EntityType):
- """a version is defining the content of a particular project's release"""
-
- __permissions__ = {'read': ('managers', 'users', 'guests',),
- 'update': ('managers', 'logilab', 'owners',),
- 'delete': ('managers', ),
- 'add': ('managers', 'logilab',
- ERQLExpression('X version_of PROJ, U in_group G,'
- 'PROJ require_permission P, P name "add_version",'
- 'P require_group G'),)}
-
-
- class version_of(RelationType):
- """link a version to its project. A version is necessarily linked to one and only one project.
- """
- __permissions__ = {'read': ('managers', 'users', 'guests',),
- 'delete': ('managers', ),
- 'add': ('managers', 'logilab',
- RRQLExpression('O require_permission P, P name "add_version",'
- 'U in_group G, P require_group G'),)
- }
- inlined = True
-
-
-This configuration indicates that an entity `CWPermission` named
-"add_version" can be associated to a project and provides rights to create
-new versions on this project to specific groups. It is important to notice that:
-
-* in such case, we have to protect both the entity type "Version" and the relation
- associating a version to a project ("version_of")
-
-* because of the genericity of the entity type `CWPermission`, we have to execute
- a unification with the groups and/or the states if necessary in the expression
- ("U in_group G, P require_group G" in the above example)
-
-
-
-Handling schema changes
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Also, it should be clear that to properly handle data migration, an
-instance's schema is stored in the database, so the python schema file
-used to defined it is only read when the instance is created or
-upgraded.
-
-.. XXX complete me
--- a/doc/book/en/development/datamodel/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-Data model
-==========
-
-This chapter describes how you define a schema and how to make it evolves as the time goes.
-
-.. toctree::
- :maxdepth: 1
-
- definition
- metadata
- baseschema
- define-workflows
--- a/doc/book/en/development/datamodel/metadata.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-
-Metadata
---------
-
-.. index::
- schema: meta-data;
- schema: eid; creation_date; modification_data; cwuri
- schema: created_by; owned_by; is; is_instance;
-
-Each entity type in |cubicweb| has at least the following meta-data attributes and relations:
-
-`eid`
- entity's identifier which is unique in an instance. We usually call this identifier `eid` for historical reason.
-
-`creation_date`
- Date and time of the creation of the entity.
-
-`modification_date`
- Date and time of the latest modification of an entity.
-
-`cwuri`
- Reference URL of the entity, which is not expected to change.
-
-`created_by`
- Relation to the :ref:`users <CWUser>` who has created the entity
-
-`owned_by`
- Relation to :ref:`users <CWUser>` whom the entity belongs; usually the creator but not
- necessary, and it could have multiple owners notably for permission control
-
-`is`
- Relation to the :ref:`entity type <CWEType>` of which type the entity is.
-
-`is_instance`
- Relation to the :ref:`entity types <CWEType>` of which type the
- entity is an instance of.
-
--- a/doc/book/en/development/devcore/cwconfig.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-Configuration
--------------
-
-.. automodule:: cubicweb.cwconfig
- :members:
--- a/doc/book/en/development/devcore/dbapi.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-.. _dbapi:
-
-Python/RQL API
-~~~~~~~~~~~~~~
-
-The Python API developped to interface with RQL is inspired from the standard db-api,
-with a Connection object having the methods cursor, rollback and commit essentially.
-The most important method is the `execute` method of a cursor.
-
-.. sourcecode:: python
-
- execute(rqlstring, args=None, build_descr=True)
-
-:rqlstring: the RQL query to execute (unicode)
-:args: if the query contains substitutions, a dictionary containing the values to use
-
-The `Connection` object owns the methods `commit` and `rollback`. You
-*should never need to use them* during the development of the web
-interface based on the *CubicWeb* framework as it determines the end
-of the transaction depending on the query execution success. They are
-however useful in other contexts such as tests or custom controllers.
-
-.. note::
-
- While executing update queries (SET, INSERT, DELETE), if a query generates
- an error related to security, a rollback is automatically done on the current
- transaction.
-
-Executing RQL queries from a view or a hook
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When you're within code of the web interface, the db-api like connexion is
-handled by the request object. You should not have to access it directly, but
-use the `execute` method directly available on the request, eg:
-
- rset = self._cw.execute(rqlstring, kwargs)
-
-Similarly, on the server side (eg in hooks), there is no db-api connexion (since
-you're directly inside the data-server), so you'll have to use the execute method
-of the session object.
-
-
-Important note about proper usage of .execute
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's say you want to get T which is in configuration C, this translates to:
-
-.. sourcecode:: python
-
- self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
-
-But it must be written in a syntax that will benefit from the use
-of a cache on the RQL server side:
-
-.. sourcecode:: python
-
- self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
-
-The syntax tree is built once for the "generic" RQL and can be re-used
-with a number of different eids. There rql IN operator is an exception
-to this rule.
-
-.. sourcecode:: python
-
- self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
- % ','.join(['foo', 'bar']))
-
-Alternativelly, some of the common data related to an entity can be
-obtained from the `entity.related()` method (which is used under the
-hood by the orm when you use attribute access notation on an entity to
-get a relation. The initial request would then be translated to:
-
-.. sourcecode:: python
-
- entity.related('in_conf', 'object')
-
-Additionnaly this benefits from the fetch_attrs policy (see
-:ref:`FetchAttrs`) eventually defined on the class element, which says
-which attributes must be also loaded when the entity is loaded through
-the orm.
-
-
-.. _resultset:
-
-The `ResultSet` API
-~~~~~~~~~~~~~~~~~~~
-
-ResultSet instances are a very commonly manipulated object. They have
-a rich API as seen below, but we would like to highlight a bunch of
-methods that are quite useful in day-to-day practice:
-
-* `__str__()` (applied by `print`) gives a very useful overview of both
- the underlying RQL expression and the data inside; unavoidable for
- debugging purposes
-
-* `printable_rql()` produces back a well formed RQL expression as a
- string; it is very useful to build views
-
-* `entities()` returns a generator on all entities of the result set
-
-* `get_entity(row, col)` gets the entity at row, col coordinates; one
- of the most used result set method
-
-.. autoclass:: cubicweb.rset.ResultSet
- :members:
-
-
-The `Cursor` API
-~~~~~~~~~~~~~~~~
-
-The whole cursor API is developped below.
-
-.. note:
-
- In practice we use the `.execute` method on the _cw object of
- appobjects. Usage of other methods is quite rare.
-
-.. autoclass:: cubicweb.dbapi.Cursor
- :members:
--- a/doc/book/en/development/devcore/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-Core APIs
-=========
-
-.. toctree::
- :maxdepth: 1
-
- dbapi.rst
- reqbase.rst
- cwconfig.rst
-
--- a/doc/book/en/development/devcore/reqbase.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-Request and ResultSet methods
------------------------------
-
-Those are methods you'll find on both request objects and on repository session:
-
-:URL handling:
- * `build_url(*args, **kwargs)`, returns an absolute URL based on the
- given arguments. The *controller* supposed to handle the response,
- can be specified through the first positional parameter (the
- connection is theoretically done automatically :).
-:Data formatting:
- * `format_date(date, date_format=None, time=False)` returns a string for a
- date time according to instance's configuration
-
- * `format_time(time)` returns a string for a date time according to
- instance's configuration
-
-:And more...:
-
- * `tal_render(template, variables)`, renders a precompiled page template with
- variables in the given dictionary as context
-
-
-Result set methods:
-
- * `get_entity(row, col)`, returns the entity corresponding to the data position
- in the *result set*
-
- * `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but
- also call the method `complete()` on the entity before returning it
-
-
--- a/doc/book/en/development/devrepo/hooks.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,436 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _hooks:
-
-Hooks and Operations
-====================
-
-Generalities
-------------
-
-Paraphrasing the `emacs`_ documentation, let us say that hooks are an
-important mechanism for customizing an application. A hook is
-basically a list of functions to be called on some well-defined
-occasion (this is called `running the hook`).
-
-.. _`emacs`: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
-
-In CubicWeb, hooks are subclasses of the Hook class in
-`server/hook.py`, implementing their own `call` method, and selected
-over a set of pre-defined `events` (and possibly more conditions,
-hooks being selectable AppObjects like views and components).
-
-There are two families of events: data events and server events. In a
-typical application, most of the Hooks are defined over data
-events.
-
-The purpose of data hooks is to complement the data model as defined
-in the schema.py, which is static by nature, with dynamic or value
-driven behaviours. It is functionally equivalent to a `database
-trigger`_, except that database triggers definition languages are not
-standardized, hence not portable (for instance, PL/SQL works with
-Oracle and PostgreSQL but not SqlServer nor Sqlite).
-
-.. _`database trigger`: http://en.wikipedia.org/wiki/Database_trigger
-
-Data hooks can serve the following purposes:
-
-* enforcing constraints that the static schema cannot express
- (spanning several entities/relations, exotic value ranges and
- cardinalities, etc.)
-
-* implement computed attributes
-
-Operations are Hook-like objects that may be created by Hooks and
-scheduled to happen just before (or after) the `commit` event. Hooks
-being fired immediately on data operations, it is sometime necessary
-to delay the actual work down to a time where all other Hooks have
-run, for instance a validation check which needs that all relations be
-already set on an entity. Also while the order of execution of Hooks
-is data dependant (and thus hard to predict), it is possible to force
-an order on Operations.
-
-Operations also may be used to process various side effects associated
-with a transaction such as filesystem udpates, mail notifications,
-etc.
-
-Operations are subclasses of the Operation class in `server/hook.py`,
-implementing `precommit_event` and other standard methods (wholly
-described in :ref:`operations_api`).
-
-Events
-------
-
-Hooks are mostly defined and used to handle `dataflow`_ operations. It
-means as data gets in (entities added, updated, relations set or
-unset), specific events are issued and the Hooks matching these events
-are called.
-
-.. _`dataflow`: http://en.wikipedia.org/wiki/Dataflow
-
-Below comes a list of the dataflow events related to entities operations:
-
-* before_add_entity
-
-* before_update_entity
-
-* before_delete_entity
-
-* after_add_entity
-
-* after_update_entity
-
-* after_delete_entity
-
-These define ENTTIES HOOKS. RELATIONS HOOKS are defined
-over the following events:
-
-* after_add_relation
-
-* after_delete_relation
-
-* before_add_relation
-
-* before_delete_relation
-
-This is an occasion to remind us that relations support the add/delete
-operation, but no update.
-
-Non data events also exist. These are called SYSTEM HOOKS.
-
-* server_startup
-
-* server_shutdown
-
-* server_maintenance
-
-* server_backup
-
-* server_restore
-
-* session_open
-
-* session_close
-
-
-Using dataflow Hooks
---------------------
-
-Dataflow hooks either automate data operations or maintain the
-consistency of the data model. In the later case, we must use a
-specific exception named ValidationError
-
-Validation Errors
-~~~~~~~~~~~~~~~~~
-
-When a condition is not met in a Hook/Operation, it must raise a
-`ValidationError`. Raising anything but a (subclass of)
-ValidationError is a programming error. Raising a ValidationError
-entails aborting the current transaction.
-
-The ValidationError exception is used to convey enough information up
-to the user interface. Hence its constructor is different from the
-default Exception constructor. It accepts, positionally:
-
-* an entity eid,
-
-* a dict whose keys represent attribute (or relation) names and values
- an end-user facing message (hence properly translated) relating the
- problem.
-
-An entity hook
-~~~~~~~~~~~~~~
-
-We will use a very simple example to show hooks usage. Let us start
-with the following schema.
-
-.. sourcecode:: python
-
- class Person(EntityType):
- age = Int(required=True)
-
-We would like to add a range constraint over a person's age. Let's
-write an hook. It shall be placed into mycube/hooks.py. If this file
-were to grow too much, we can easily have a mycube/hooks/... package
-containing hooks in various modules.
-
-.. sourcecode:: python
-
- from cubicweb import ValidationError
- from cubicweb.selectors import implements
- from cubicweb.server.hook import Hook
-
- class PersonAgeRange(Hook):
- __regid__ = 'person_age_range'
- events = ('before_add_entity', 'before_update_entity')
- __select__ = Hook.__select__ & implements('Person')
-
- def __call__(self):
- if 0 >= self.entity.age <= 120:
- return
- msg = self._cw._('age must be between 0 and 120')
- raise ValidationError(self.entity.eid, {'age': msg})
-
-Hooks being AppObjects like views, they have a __regid__ and a
-__select__ class attribute. The base __select__ is augmented with an
-`implements` selector matching the desired entity type. The `events`
-tuple is used by the Hook.__select__ base selector to dispatch the
-hook on the right events. In an entity hook, it is possible to
-dispatch on any entity event (e.g. 'before_add_entity',
-'before_update_entity') at once if needed.
-
-Like all appobjects, hooks have the `self._cw` attribute which
-represents the current session. In entity hooks, a `self.entity`
-attribute is also present.
-
-
-A relation hook
-~~~~~~~~~~~~~~~
-
-Let us add another entity type with a relation to person (in
-mycube/schema.py).
-
-.. sourcecode:: python
-
- class Company(EntityType):
- name = String(required=True)
- boss = SubjectRelation('Person', cardinality='1*')
-
-We would like to constrain the company's bosses to have a minimum
-(legal) age. Let's write an hook for this, which will be fired when
-the `boss` relation is established.
-
-.. sourcecode:: python
-
- class CompanyBossLegalAge(Hook):
- __regid__ = 'company_boss_legal_age'
- events = ('before_add_relation',)
- __select__ = Hook.__select__ & match_rtype('boss')
-
- def __call__(self):
- boss = self._cw.entity_from_eid(self.eidto)
- if boss.age < 18:
- msg = self._cw._('the minimum age for a boss is 18')
- raise ValidationError(self.eidfrom, {'boss': msg})
-
-We use the `match_rtype` selector to select the proper relation type.
-
-The essential difference with respect to an entity hook is that there
-is no self.entity, but `self.eidfrom` and `self.eidto` hook attributes
-which represent the subject and object eid of the relation.
-
-
-Using Operations
-----------------
-
-Let's augment our example with a new `subsidiary_of` relation on Company.
-
-.. sourcecode:: python
-
- class Company(EntityType):
- name = String(required=True)
- boss = SubjectRelation('Person', cardinality='1*')
- subsidiary_of = SubjectRelation('Company', cardinality='*?')
-
-Base example
-~~~~~~~~~~~~
-
-We would like to check that there is no cycle by the `subsidiary_of`
-relation. This is best achieved in an Operation since all relations
-are likely to be set at commit time.
-
-.. sourcecode:: python
-
- def check_cycle(self, session, eid, rtype, role='subject'):
- parents = set([eid])
- parent = session.entity_from_eid(eid)
- while parent.related(rtype, role):
- parent = parent.related(rtype, role)[0]
- if parent.eid in parents:
- msg = session._('detected %s cycle' % rtype)
- raise ValidationError(eid, {rtype: msg})
- parents.add(parent.eid)
-
- class CheckSubsidiaryCycleOp(Operation):
-
- def precommit_event(self):
- check_cycle(self.session, self.eidto, 'subsidiary_of')
-
-
- class CheckSubsidiaryCycleHook(Hook):
- __regid__ = 'check_no_subsidiary_cycle'
- events = ('after_add_relation',)
- __select__ = Hook.__select__ & match_rtype('subsidiary_of')
-
- def __call__(self):
- CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
-
-The operation is instantiated in the Hook.__call__ method.
-
-An operation always takes a session object as first argument
-(accessible as `.session` from the operation instance), and optionally
-all keyword arguments needed by the operation. These keyword arguments
-will be accessible as attributes from the operation instance.
-
-Like in Hooks, ValidationError can be raised in Operations. Other
-exceptions are programming errors.
-
-Notice how our hook will instantiate an operation each time the Hook
-is called, i.e. each time the `subsidiary_of` relation is set.
-
-Using set_operation
-~~~~~~~~~~~~~~~~~~~
-
-There is an alternative method to schedule an Operation from a Hook,
-using the `set_operation` function.
-
-.. sourcecode:: python
-
- from cubicweb.server.hook import set_operation
-
- class CheckSubsidiaryCycleHook(Hook):
- __regid__ = 'check_no_subsidiary_cycle'
- events = ('after_add_relation',)
- __select__ = Hook.__select__ & match_rtype('subsidiary_of')
-
- def __call__(self):
- set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto,
- CheckSubsidiaryCycleOp, rtype=self.rtype)
-
- class CheckSubsidiaryCycleOp(Operation):
-
- def precommit_event(self):
- for eid in self._cw.transaction_data['subsidiary_cycle_detection']:
- check_cycle(self.session, eid, self.rtype)
-
-Here, we call set_operation with a session object, a specially forged
-key, a value that is the actual payload of an individual operation (in
-our case, the object of the subsidiary_of relation) , the class of the
-Operation, and more optional parameters to give to the operation (here
-the rtype which do not vary accross operations).
-
-The body of the operation must then iterate over the values that have
-been mapped in the transaction_data dictionary to the forged key.
-
-This mechanism is especially useful on two occasions (not shown in our
-example):
-
-* massive data import (reduced memory consumption within a large
- transaction)
-
-* when several hooks need to instantiate the same operation (e.g. an
- entity and a relation hook).
-
-.. note::
-
- A more realistic example can be found in the advanced tutorial
- chapter :ref:`adv_tuto_security_propagation`.
-
-.. _operations_api:
-
-Operation: a small API overview
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: cubicweb.server.hook.Operation
-.. autoclass:: cubicweb.server.hook.LateOperation
-.. autofunction:: cubicweb.server.hook.set_operation
-
-Hooks writing rules
--------------------
-
-Remainder
-~~~~~~~~~
-
-Never, ever use the `entity.foo = 42` notation to update an entity. It
-will not work.
-
-How to choose between a before and an after event ?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Before hooks give you access to the old attribute (or relation)
-values. By definition the database is not yet updated in a before
-hook.
-
-To access old and new values in an before_update_entity hook, one can
-use the `server.hook.entity_oldnewvalue` function which returns a
-tuple of the old and new values. This function takes an entity and an
-attribute name as parameters.
-
-In a 'before_add|update_entity' hook the self.entity contains the new
-values. One is allowed to further modify them before database
-operations, using the dictionary notation.
-
-.. sourcecode:: python
-
- self.entity['age'] = 42
-
-This is because using self.entity.set_attributes(age=42) will
-immediately update the database (which does not make sense in a
-pre-database hook), and will trigger any existing
-before_add|update_entity hook, thus leading to infinite hook loops or
-such awkward situations.
-
-Beyond these specific cases, updating an entity attribute or relation
-must *always* be done using `set_attributes` and `set_relations`
-methods.
-
-(Of course, ValidationError will always abort the current transaction,
-whetever the event).
-
-Peculiarities of inlined relations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some relations are defined in the schema as `inlined` (see
-:ref:`RelationType` for details). In this case, they are inserted in
-the database at the same time as entity attributes.
-
-Hence in the case of before_add_relation, such relations already exist
-in the database.
-
-Edited attributes
-~~~~~~~~~~~~~~~~~
-
-On udpates, it is possible to ask the `entity.edited_attributes`
-variable whether one attribute has been updated.
-
-.. sourcecode:: python
-
- if 'age' not in entity.edited_attribute:
- return
-
-Deleted in transaction
-~~~~~~~~~~~~~~~~~~~~~~
-
-The session object has a deleted_in_transaction method, which can help
-writing deletion Hooks.
-
-.. sourcecode:: python
-
- if self._cw.deleted_in_transaction(self.eidto):
- return
-
-Given this predicate, we can avoid scheduling an operation.
-
-Disabling hooks
-~~~~~~~~~~~~~~~
-
-It is sometimes convenient to disable some hooks. For instance to
-avoid infinite Hook loops. One uses the `hooks_control` context
-manager.
-
-This can be controlled more finely through the `category` Hook class
-attribute, which is a string.
-
-.. sourcecode:: python
-
- with hooks_control(self.session, self.session.HOOKS_ALLOW_ALL, <category>):
- # ... do stuff
-
-.. autoclass:: cubicweb.server.session.hooks_control
-
-The existing categories are: ``email``, ``syncsession``,
-``syncschema``, ``bookmark``, ``security``, ``worfklow``,
-``metadata``, ``notification``, ``integrity``, ``activeintegrity``.
-
-Nothing precludes one to invent new categories and use the
-hooks_control context manager to filter them (in or out).
--- a/doc/book/en/development/devrepo/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Repository customization
-++++++++++++++++++++++++
-.. toctree::
- :maxdepth: 1
-
- sessions
- hooks
- notifications
- tasks
-
-
--- a/doc/book/en/development/devrepo/notifications.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Notifications management
-========================
-
-XXX FILLME
--- a/doc/book/en/development/devrepo/sessions.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Sessions
-========
-
-There are three kinds of sessions.
-
-* `user sessions` are the most common: they are related to users and
- carry security checks coming with user credentials
-
-* `super sessions` are children of ordinary user sessions and allow to
- bypass security checks (they are created by calling unsafe_execute
- on a user session); this is often convenient in hooks which may
- touch data that is not directly updatable by users
-
-* `internal sessions` have all the powers; they are also used in only a
- few situations where you don't already have an adequate session at
- hand, like: user authentication, data synchronisation in
- multi-source contexts
-
-.. note::
- Do not confuse the session type with their connection mode, for
- instance : 'in memory' or 'pyro'.
-
-[WRITE ME]
-
-* authentication and management of sessions
--- a/doc/book/en/development/devrepo/tasks.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tasks
-=========
-
-[WRITE ME]
-
-* repository tasks
-
--- a/doc/book/en/development/devweb/controllers.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-.. _controllers:
-
-Controllers
------------
-
-Overview
-++++++++
-
-Controllers are responsible for taking action upon user requests
-(loosely following the terminology of the MVC meta pattern).
-
-The following controllers are provided out-of-the box in CubicWeb. We
-list them by category.
-
-`Browsing`:
-
-* the View controller (web/views/basecontrollers.py) is associated
- with most browsing actions within a CubicWeb application: it always
- instantiates a `main template` and lets the ResultSet/Views dispatch
- system build up the whole content; it handles ObjectNotFound and
- NoSelectableObject errors that may bubble up to its entry point, in
- an end-user-friendly way (but other programming errors will slip
- through)
-
-* the JSon controller (web/views/basecontrollers.py) provides services
- for Ajax calls, typically using JSON as a serialization format for
- input, and sometimes using either JSON or XML for output;
-
-* the Login/Logout controllers (web/views/basecontrollers.py) make
- effective user login or logout requests
-
-`Edition`:
-
-* the Edit controller (see :ref:`edit_controller`) handles CRUD
- operations in response to a form being submitted; it works in close
- association with the Forms, to which it delegates some of the work
-
-* the Form validator controller (web/views/basecontrollers.py)
- provides form validation from Ajax context, using the Edit
- controller, to implement the classic form handling loop (user edits,
- hits 'submit/apply', validation occurs server-side by way of the
- Form validator controller, and the UI is decorated with failure
- information, either global or per-field , until it is valid)
-
-`Other`:
-
-* the SendMail controller (web/views/basecontrollers.py) is reponsible
- for outgoing email notifications
-
-* the MailBugReport controller (web/views/basecontrollers.py) allows
- to quickly have a `repotbug` feature in one's application
-
-Registration
-++++++++++++
-
-All controllers (should) live in the 'controllers' namespace within
-the global registry.
-
-API
-+++
-
-Most API details should be resolved by source code inspection, as the
-various controllers have differing goals.
-
-`web/controller.py` contains the top-level abstract Controller class and
-its (NotImplemented) entry point `publish(rset=None)` method.
-
-A handful of helpers are also provided there:
-
-* process_rql builds a result set from an rql query typically issued
- from the browser (and available through _cw.form['rql'])
-
-* validate_cache will force cache validation handling with respect to
- the HTTP Cache directives (that were typically originally issued
- from a previous server -> client response); concrete Controller
- implementations dealing with HTTP (thus, for instance, not the
- SendMail controller) may very well call this in their publication
- process.
-
-
-.. _edit_controller:
-
-The `edit controller`
-+++++++++++++++++++++
-
-It can be found in (:mod:`cubicweb.web.views.editcontroller`).
-
-Editing control
-~~~~~~~~~~~~~~~~
-
-Re-requisites: the parameters related to entities to edit are
-specified as follows ::
-
- <field name>:<entity eid>
-
-where entity eid could be a letter in case of an entity to create. We
-name those parameters as *qualified*.
-
-1. Retrieval of entities to edit by looking for the forms parameters
- starting by `eid:` and also having a parameter `__type` associated
- (also *qualified* by eid)
-
-2. For all the attributes and the relations of an entity to edit:
-
- 1. search for a parameter `edits-<relation name>` or `edito-<relation name>`
- qualified in the case of a relation where the entity is object
- 2. if found, the value returned is considered as the initial value
- for this relaiton and we then look for the new value(s) in the parameter
- <relation name> (qualified)
- 3. if the value returned is different from the initial value, an database update
- request is done
-
-3. For each entity to edit:
-
- 1. if a qualified parameter `__linkto` is specified, its value has to be
- a string (or a list of string) such as: ::
-
- <relation type>:<eids>:<target>
-
- where <target> is either `subject` or `object` and each eid could be
- separated from the others by a `_`. Target specifies if the *edited entity*
- is subject or object of the relation and each relation specified will
- be inserted.
-
- 2. if a qualified parameter `__clone_eid` is specified for an entity, the
- relations of the specified entity passed as value of this parameter are
- copied on the edited entity.
-
- 3. if a qualified parameter `__delete` is specified, its value must be
- a string or a list of string such as follows: ::
-
- <ssubjects eids>:<relation type>:<objects eids>
-
- where each eid subject or object can be seperated from the other
- by `_`. Each relation specified will be deleted.
-
- 4. if a qualified parameter `__insert` is specified, its value should
- follow the same pattern as `__delete`, but each relation specified is
- inserted.
-
-4. If the parameters `__insert` and/or `__delete` are found not qualified,
- they are interpreted as explained above (independantly from the number
- of entities edited).
-
-5. If no entity is edited but the form contains the parameters `__linkto`
- and `eid`, this one is interpreted by using the value specified for `eid`
- to designate the entity on which to add the relations.
-
-
-.. note::
-
- * If the parameter `__action_delete` is found, all the entities specified
- as to be edited will be deleted.
-
- * If the parameter `__action_cancel` is found, no action is completed.
-
- * If the parameter `__action_apply` is found, the editing is
- applied normally but the redirection is done on the form (see
- :ref:`RedirectionControl`).
-
- * The parameter `__method` is also supported as for the main template
-
- * If no entity is found to be edited and if there is no parameter
- `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or
- `__insert`, an error is raised.
-
- * Using the parameter `__message` in the form will allow to use its value
- as a message to provide the user once the editing is completed.
-
-
-.. _RedirectionControl:
-
-Redirection control
-~~~~~~~~~~~~~~~~~~~
-Once editing is completed, there is still an issue left: where should we go
-now? If nothing is specified, the controller will do his job but it does not
-mean we will be happy with the result. We can control that by using the
-following parameters:
-
-* `__redirectpath`: path of the URL (relative to the root URL of the site,
- no form parameters
-
-* `__redirectparams`: forms parameters to add to the path
-
-* `__redirectrql`: redirection RQL request
-
-* `__redirectvid`: redirection view identifier
-
-* `__errorurl`: initial form URL, used for redirecting in case a validation
- error is raised during editing. If this one is not specified, an error page
- is displayed instead of going back to the form (which is, if necessary,
- responsible for displaying the errors)
-
-* `__form_id`: initial view form identifier, used if `__action_apply` is
- found
-
-In general we use either `__redirectpath` and `__redirectparams` or
-`__redirectrql` and `__redirectvid`.
-
--- a/doc/book/en/development/devweb/css.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-CSS Stylesheet
----------------
-Conventions
-~~~~~~~~~~~
-
-XXX external_resources variable
- naming convention
- request.add_css
-
-
-Extending / overriding existing styles
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We cannot modify the order in which the application is reading the CSS. In
-the case we want to create new CSS style, the best is to define it a in a new
-CSS located under ``myapp/data/`` and use those new styles while writing
-customized views and templates.
-
-If you want to modify an existing CSS styling property, you will have to use
-``!important`` declaration to override the existing property. The application
-apply a higher priority on the default CSS and you can not change that.
-Customized CSS will not be read first.
-
-
-CubicWeb stylesheets
-~~~~~~~~~~~~~~~~~~~~
-XXX explain diffenrent files and main classes
--- a/doc/book/en/development/devweb/facets.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
-The facets system
------------------
-
-Facets allow to restrict searches according to some criteria. CubicWeb has a builtin `facet`_ system to define restrictions
-`filters`_ really as easily as possible. A few base classes for facets
-are provided in ``cubicweb.web.facet.py``. All classes inherits from
-the base class ``AbstractFacet``.
-
-Here is an overview of the facets rendering pick from the `tracker` cube:
-
-.. image:: ../../images/facet_overview.png
-
-Facets will appear on each page presenting more than one entity.
-
-
-
-VocabularyFacet
-~~~~~~~~~~~~~~~~
-The ``VocabularyFacet`` inherits from the ``AbstractFacet``.
-A class which inherits from VocabularyFacets must redefine these methods:
-
-.. automethod:: cubicweb.web.facet.VocabularyFacet.vocabulary
-.. automethod:: cubicweb.web.facet.VocabularyFacet.possible_values
-
-RelationFacet
-~~~~~~~~~~~~~~
-
-The ``RelationFacet`` inherits from the ``VocabularyFacet``. It allows to filter entities according to certain relation's values. Generally, you just have to define some class attributes like:
-
-- rtype: the name of the relation
-- role: the default value is set to `subject`
-- target_attr: needed if it is not the default attribute of the entity
-
-
-To illustrate this facet, let's take for example an *excerpt* of the schema of an office location search application:
-
-.. sourcecode:: python
-
- class Office(WorkflowableEntityType):
- price = Int(description='euros / m2 / HC / HT')
- surface = Int(description='m2')
- description = RichString(fulltextindexed=True)
- has_address = SubjectRelation('PostalAddress',
- cardinality='1?',
- composite='subject')
- proposed_by = SubjectRelation('Agency')
- comments = ObjectRelation('Comment',
- cardinality='1*',
- composite='object')
- screenshots = SubjectRelation(('File', 'Image'),
- cardinality='*1',
- composite='subject')
-
-
-We define a facet to filter offices according to the attribute
-`postalcode` of their associated `PostalAdress`.
-
-.. sourcecode:: python
-
- class PostalCodeFacet(RelationFacet):
- __regid__ = 'postalcode-facet' # every registered class must have an id
- __select__ = implements('Office') # this facet should only be selected when
- # visualizing offices
- rtype = 'has_address' # this facet is a filter on the entity linked to
- # the office thrhough the relation
- # has_address
- target_attr = 'postalcode' # the filter's key is the attribute "postal_code"
- # of the target PostalAddress entity
-
-
-AttributeFacet
-~~~~~~~~~~~~~~
-
-The ``AttributeFacet`` inherits from the ``RelationFacet``. It allows to filter entities according to certain attribute's values.
-
-The example below resumes the former schema. We define now a filter based on the `surface` attribute of the
-`Office`.
-
-.. sourcecode:: python
-
- class SurfaceFacet(AttributeFacet):
- __regid__ = 'surface-facet' # every registered class must have an id
- __select__ = implements('Office') # this facet should only be selected when
- # visualizing offices
- rtype = 'surface' # the filter's key is the attribute "surface"
- comparator = '>=' # override the default value of operator since
- # we want to filter according to a
- # minimal
- # value, not an exact one
-
- def rset_vocabulary(self, ___):
- """override the default vocabulary method since we want to hard-code
- our threshold values.
- Not overriding would generate a filter box with all existing surfaces
- defined in the database.
- """
- return [('> 200', '200'), ('> 250', '250'),
- ('> 275', '275'), ('> 300', '300')]
-
-RangeFacet
-~~~~~~~~~~
-The ``RangeFacet`` inherits from the ``AttributeFacet``. It allows to filter entities according to certain attributes of numerical type.
-
-The ``RangeFacet`` displays a slider using `jquery`_ to choose a lower bound and an upper bound.
-
-The example below defines a facet to filter a selection of books according to their number of pages.
-
-.. sourcecode:: python
-
- class BookPagesFacet(RangeFacet):
- __regid__ = 'priority-facet'
- __select__ = RangeFacet.__select__ & implements('Book')
- rtype = 'pages'
-
-The image below display the rendering of the ``RangeFacet``:
-
-.. image:: ../../images/facet_range.png
-
-DateRangeFacet
-~~~~~~~~~~~~~~
-The ``DateRangeFacet`` inherits from the ``RangeFacet``. It allows to filter entities according to certain attributes of date type.
-
-Here is an example of code that defines a facet to filter
-musical works according to their composition date:
-
-.. sourcecode:: python
-
- class CompositionDateFacet(DateRangeFacet):
- # 1. make sure this facet is displayed only on Track selection
- __select__ = DateRangeFacet.__select__ & implements('Track')
- # 2. give the facet an id required by CubicWeb)
- __regid__ = 'compdate-facet'
- # 3. specify the attribute name that actually stores the date in the DB
- rtype = 'composition_date'
-
-With this facet, on each page displaying tracks, you'll be able to filter them
-according to their composition date with a jquery slider.
-
-The image below display the rendering of the ``DateRangeFacet``:
-
-.. image:: ../../images/facet_date_range.png
-
-
-HasRelationFacet
-~~~~~~~~~~~~~~~~
-
-The ``DateRangeFacet`` inherits from the ``AbstractFacet``. It will
-display a simple checkbox and lets you refine your selection in order
-to get only entities that actually use this relation.
-
-Here is an example of the rendering of the ``HasRelationFacet`` to
-filter entities with image and the corresponding code:
-
-.. image:: ../../images/facet_has_image.png
-
-.. sourcecode:: python
-
- class HasImageFacet(HasRelationFacet):
- __regid__ = 'hasimage-facet'
- __select__ = HasRelationFacet.__select__ & implements('Book')
- rtype = 'has_image'
-
-
-
-To use ``HasRelationFacet`` on a reverse relation add ``role = 'object'`` in
-it's definitions.
-
-.. _facet: http://en.wikipedia.org/wiki/Faceted_browser
-.. _filters: http://www.cubicweb.org/blogentry/154152
-.. _jquery: http://www.jqueryui.com/
-
--- a/doc/book/en/development/devweb/form.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-HTML form construction
-----------------------
-
-CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
-to provide generic building blocks which will greatly help you in building forms
-properly integrated with CubicWeb (coherent display, error handling, etc...),
-while keeping things as flexible as possible.
-
-A **form** basically only holds a set of **fields**, and has te be bound to a
-**renderer** which is responsible to layout them. Each field is bound to a
-**widget** that will be used to fill in value(s) for that field (at form
-generation time) and 'decode' (fetch and give a proper Python type to) values
-sent back by the browser.
-
-The **field** should be used according to the type of what you want to edit.
-E.g. if you want to edit some date, you'll have to use the
-:class:`~cubicweb.web.formfields.DateField`. Then you can choose among multiple
-widgets to edit it, for instance :class:`~cubicweb.web.formwidgets.TextInput` (a
-bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
-calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
-calendar). You can of course also write your own widget.
-
-
-.. automodule:: cubicweb.web.formfields
-.. automodule:: cubicweb.web.formwidgets
-.. automodule:: cubicweb.web.views.forms
-.. automodule:: cubicweb.web.views.autoform
-.. automodule:: cubicweb.web.views.formrenderers
-
-
-Now what ? Example of bare fields form
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We want to define a form doing something else than editing an entity. The idea is
-to propose a form to send an email to entities in a resultset which implements
-:class:`IEmailable`. Let's take a simplified version of what you'll find in
-:mod:`cubicweb.web.views.massmailing`.
-
-Here is the source code:
-
-.. sourcecode:: python
-
- def sender_value(form):
- return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
-
- def recipient_choices(form, field):
- return [(e.get_email(), e.eid) for e in form.cw_rset.entities()
- if e.get_email()]
-
- def recipient_value(form):
- return [e.eid for e in form.cw_rset.entities() if e.get_email()]
-
- class MassMailingForm(forms.FieldsForm):
- __regid__ = 'massmailing'
-
- needs_js = ('cubicweb.widgets.js',)
- domid = 'sendmail'
- action = 'sendmail'
-
- sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
- label=_('From:'),
- value=sender_value)
-
- recipient = ff.StringField(widget=CheckBox(),
- label=_('Recipients:'),
- choices=recipient_choices,
- value=recipients_value)
-
- subject = ff.StringField(label=_('Subject:'), max_length=256)
-
- mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
- inputid='mailbody'))
-
- form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
- _('send email'), 'SEND_EMAIL_ICON'),
- ImgButton('cancelbutton', "javascript: history.back()",
- stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
-
-Let's detail what's going on up there. Our form will hold four fields:
-
-* a sender field, which is disabled and will simply contains the user's name and
- email
-
-* a recipients field, which will be displayed as a list of users in the context
- result set with checkboxes so user can still choose who will receive his mailing
- by checking or not the checkboxes. By default all of them will be checked since
- field's value return a list containing same eids as those returned by the
- vocabulary function.
-
-* a subject field, limited to 256 characters (hence we know a
- :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
- :class:`~cubicweb.web.formfields.StringField`)
-
-* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
- and whose definition won't be shown here. Notice though that we tell this form
- need this javascript file by using `needs_js`
-
-Last but not least, we add two buttons control: one to post the form using
-javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
-set to 'sendmail', which is our form DOM id as specified by its `domid`
-attribute), another to cancel the form which will go back to the previous page
-using another javascript call. Also we specify image to used as button icon a
-resource identifier (see :ref:`external_resources`) given as last argument to
-:class:`cubicweb.web.formwidgets.ImgButton`.
-
-To see this form, we still have to wrap it in a view. This is pretty simple:
-
-.. sourcecode:: python
-
- class MassMailingFormView(form.FormViewMixIn, EntityView):
- __regid__ = 'massmailing'
- __select__ = implements(IEmailable) & authenticated_user()
-
- def call(self):
- form = self._cw.vreg['forms'].select('massmailing', self._cw,
- rset=self.cw_rset)
- self.w(form.render())
-
-As you see, we simply define a view with proper selector so it only apply to a
-result set containing :class:`IEmailable` entities, and so that only users in the
-managers or users group can use it. Then in the `call()` method for this view we
-simply select the above form and write what its `.render()` method returns.
-
-When this form is submitted, a controller with id 'sendmail' will be called (as
-specified using `action`). This controller will be responsible to actually send
-the mail to specified recipients.
-
-Here is what it looks like:
-
-.. sourcecode:: python
-
- class SendMailController(Controller):
- __regid__ = 'sendmail'
- __select__ = authenticated_user() & match_form_params('recipient', 'mailbody', 'subject')
-
- def publish(self, rset=None):
- body = self._cw.form['mailbody']
- subject = self._cw.form['subject']
- eids = self._cw.form['recipient']
- # eids may be a string if only one recipient was specified
- if isinstance(eids, basestring):
- rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
- else:
- rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
- recipients = list(rset.entities())
- msg = format_mail({'email' : self._cw.user.get_email(),
- 'name' : self._cw.user.dc_title()},
- recipients, body, subject)
- if not self._cw.vreg.config.sendmails([(msg, recipients]):
- msg = self._cw._('could not connect to the SMTP server')
- else:
- msg = self._cw._('emails successfully sent')
- raise Redirect(self._cw.build_url(__message=msg))
-
-
-The entry point of a controller is the publish method. In that case we simply get
-back post values in request's `form` attribute, get user instances according
-to eids found in the 'recipient' form value, and send email after calling
-:func:`format_mail` to get a proper email message. If we can't send email or
-if we successfully sent email, we redirect to the index page with proper message
-to inform the user.
-
-Also notice that our controller has a selector that deny access to it to
-anonymous users (we don't want our instance to be used as a spam relay), but also
-check expected parameters are specified in forms. That avoid later defensive
-programming (though it's not enough to handle all possible error cases).
-
-To conclude our example, suppose we wish a different form layout and that existent
-renderers are not satisfying (we would check that first of course :). We would then
-have to define our own renderer:
-
-.. sourcecode:: python
-
- class MassMailingFormRenderer(formrenderers.FormRenderer):
- __regid__ = 'massmailing'
-
- def _render_fields(self, fields, w, form):
- w(u'<table class="headersform">')
- for field in fields:
- if field.name == 'mailbody':
- w(u'</table>')
- w(u'<div id="toolbar">')
- w(u'<ul>')
- for button in form.form_buttons:
- w(u'<li>%s</li>' % button.render(form))
- w(u'</ul>')
- w(u'</div>')
- w(u'<div>')
- w(field.render(form, self))
- w(u'</div>')
- else:
- w(u'<tr>')
- w(u'<td class="hlabel">%s</td>' % self.render_label(form, field))
- w(u'<td class="hvalue">')
- w(field.render(form, self))
- w(u'</td></tr>')
-
- def render_buttons(self, w, form):
- pass
-
-We simply override the `_render_fields` and `render_buttons` method of the base form renderer
-to arrange fields as we desire it: here we'll have first a two columns table with label and
-value of the sender, recipients and subject field (form order respected), then form controls,
-then a div containing the textarea for the email's content.
-
-To bind this renderer to our form, we should add to our form definition above:
-
-.. sourcecode:: python
-
- form_renderer_id = 'massmailing'
-
-
-.. Example of entity fields form
--- a/doc/book/en/development/devweb/httpcaching.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-HTTP cache management
----------------------
-XXX feedme
\ No newline at end of file
--- a/doc/book/en/development/devweb/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-Web development
-===============
-
-In this chapter, we will describe the core APIs for web development in
-the *CubicWeb* framework.
-
-.. toctree::
- :maxdepth: 2
-
- publisher
- controllers
- request
- views/index
- rtags
- js
- css
- form
- facets
- internationalization
- property
- httpcaching
--- a/doc/book/en/development/devweb/internationalization.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,222 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _internationalization:
-
-Internationalization
----------------------
-
-Cubicweb fully supports the internalization of its content and interface.
-
-Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
-
-.. _`GNU gettext`: http://www.gnu.org/software/gettext/
-
-Cubicweb' internalization involves two steps:
-
-* in your Python code and cubicweb-tal templates : mark translatable strings
-
-* in your instance : handle the translation catalog, edit translations
-
-String internationalization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-User defined string
-```````````````````
-
-In the Python code and cubicweb-tal templates translatable strings can be
-marked in one of the following ways :
-
- * by using the *built-in* function `_` ::
-
- class PrimaryView(EntityView):
- """the full view of an non final entity"""
- __regid__ = 'primary'
- title = _('primary')
-
- OR
-
- * by using the equivalent request's method ::
-
- class NoResultView(View):
- """default view when no result has been found"""
- __regid__ = 'noresult'
-
- def call(self, **kwargs):
- self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
- % self._cw._('No result matching query'))
-
-The goal of the *built-in* function `_` is only **to mark the
-translatable strings**, it will only return the string to translate
-itself, but not its translation (it's actually another name for the
-`unicode` builtin).
-
-In the other hand the request's method `self._cw._` is also meant to
-retrieve the proper translation of translation strings in the
-requested language.
-
-Finally you can also use the `__` attribute of request object to get a
-translation for a string *which should not itself added to the catalog*,
-usually in case where the actual msgid is created by string interpolation ::
-
- self._cw.__('This %s' % etype)
-
-In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
-messages catalogs.
-
-Translations in cubicweb-tal template can also be done with TAL tags
-`i18n:content` and `i18n:replace`.
-
-If you need to add messages on top of those that can be found in the source,
-you can create a file named `i18n/static-messages.pot`.
-
-You could put there messages not found in the python sources or
-overrides for some messages of used cubes.
-
-Generated string
-````````````````
-
-We do not need to mark the translation strings of entities/relations used by a
-particular instance's schema as they are generated automatically. String for
-various actions are also generated.
-
-For exemple the following schema ::
-
- Class EntityA(EntityType):
- relation_a2b = SubjectRelation('EntityB')
-
- class EntityB(EntityType):
- pass
-
-May generate the following message ::
-
- add EntityA relation_a2b EntityB subject
-
-This message will be used in views of ``EntityA`` for creation of a new
-``EntityB`` with a preset relation ``relation_a2b`` between the current
-``EntityA`` and the new ``EntityB``. The opposite message ::
-
- add EntityA relation_a2b EntityB object
-
-Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
-title of they respective creation form will be ::
-
- creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
-
- creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
-
-In the translated string you can use ``%(linkto)s`` for reference to the source
-``entity``.
-
-Handling the translation catalog
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Once the internationalization is done in your code, you need to populate and
-update the translation catalog. Cubicweb provides the following commands for this
-purpose:
-
-
-* `i18ncubicweb` updates Cubicweb framework's translation
- catalogs. Unless you actually work on the framework itself, you
- don't need to use this command.
-
-* `i18ncube` updates the translation catalogs of *one particular cube*
- (or of all cubes). After this command is executed you must update
- the translation files *.po* in the "i18n" directory of your
- cube. This command will of course not remove existing translations
- still in use. It will mark unused translation but not remove them.
-
-* `i18ninstance` recompiles the translation catalogs of *one particular
- instance* (or of all instances) after the translation catalogs of
- its cubes have been updated. This command is automatically
- called every time you create or update your instance. The compiled
- catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
- instance where `lang` is the language identifier ('en' or 'fr'
- for exemple).
-
-
-Example
-```````
-
-You have added and/or modified some translation strings in your cube
-(after creating a new view or modifying the cube's schema for exemple).
-To update the translation catalogs you need to do:
-
-1. `cubicweb-ctl i18ncube <cube>`
-2. Edit the <cube>/i18n/xxx.po files and add missing translations (empty `msgstr`)
-3. `hg ci -m "updated i18n catalogs"`
-4. `cubicweb-ctl i18ninstance <myinstance>`
-
-Editing po files
-~~~~~~~~~~~~~~~~
-
-Using a PO aware editor
-````````````````````````
-
-Many tools exist to help maintain .po (PO) files. Common editors or
-development environment provides modes for these. One can also find
-dedicated PO files editor, such as `poedit`_.
-
-.. _`poedit`: http://www.poedit.net/
-
-While usage of such a tool is commendable, PO files are perfectly
-editable with a (unicode aware) plain text editor. It is also useful
-to know their structure for troubleshooting purposes.
-
-Structure of a PO file
-``````````````````````
-
-In this section, we selectively quote passages of the `GNU gettext`_
-manual chapter on PO files, available there::
-
- http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
-
-One PO file entry has the following schematic structure::
-
- white-space
- # translator-comments
- #. extracted-comments
- #: reference...
- #, flag...
- #| msgid previous-untranslated-string
- msgid untranslated-string
- msgstr translated-string
-
-
-A simple entry can look like this::
-
- #: lib/error.c:116
- msgid "Unknown system error"
- msgstr "Error desconegut del sistema"
-
-It is also possible to have entries with a context specifier. They
-look like this::
-
- white-space
- # translator-comments
- #. extracted-comments
- #: reference...
- #, flag...
- #| msgctxt previous-context
- #| msgid previous-untranslated-string
- msgctxt context
- msgid untranslated-string
- msgstr translated-string
-
-
-The context serves to disambiguate messages with the same
-untranslated-string. It is possible to have several entries with the
-same untranslated-string in a PO file, provided that they each have a
-different context. Note that an empty context string and an absent
-msgctxt line do not mean the same thing.
-
-Contexts and CubicWeb
-`````````````````````
-
-CubicWeb PO files have both non-contextual and contextual msgids.
-
-Contextual entries are automatically used in some cases. For instance,
-entity.dc_type(), eschema.display_name(req) or display_name(etype,
-req, form, context) methods/function calls will use them.
-
-It is also possible to explicitly use the with _cw.pgettext(context,
-msgid).
--- a/doc/book/en/development/devweb/js.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,355 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Javascript
-----------
-
-*CubicWeb* uses quite a bit of javascript in its user interface and
-ships with jquery (1.3.x) and parts of the jquery UI library, plus a
-number of homegrown files and also other third party libraries.
-
-All javascript files are stored in cubicweb/web/data/. There are
-around thirty js files there. In a cube it goes to data/.
-
-Obviously one does not want javascript pieces to be loaded all at
-once, hence the framework provides a number of mechanisms and
-conventions to deal with javascript resources.
-
-Conventions
-~~~~~~~~~~~
-
-It is good practice to name cube specific js files after the name of
-the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
-
-XXX external_resources variable (which needs love)
-
-CubicWeb javascript API
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Javascript resources are typically loaded on demand, from views. The
-request object (available as self._cw from most application objects,
-for instance views and entities objects) has a few methods to do that:
-
-* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
- javascript files and writes proper entries into the HTML header
- section. The localfile parameter allows to declare resources which
- are not from web/data (for instance, residing on a content delivery
- network).
-
-* `add_onload(self, jscode)` which adds one raw javascript code
- snippet inline in the html headers. This is quite useful for setting
- up early jQuery(document).ready(...) initialisations.
-
-CubicWeb javascript events
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* ``server-response``: this event is triggered on HTTP responses (both
- standard and ajax). The two following extra parameters are passed
- to callbacks :
-
- - ``ajax``: a boolean that says if the reponse was issued by an
- ajax request
-
- - ``node``: the DOM node returned by the server in case of an
- ajax request, otherwise the document itself for standard HTTP
- requests.
-
-Important AJAX APIS
-~~~~~~~~~~~~~~~~~~~
-
-* `asyncRemoteExec` and `remoteExec` are the base building blocks for
- doing arbitrary async (resp. sync) communications with the server
-
-* `reloadComponent` is a convenience function to replace a DOM node
- with server supplied content coming from a specific registry (this
- is quite handy to refresh the content of some boxes for instances)
-
-* `jQuery.fn.loadxhtml` is an important extension to jQuery which
- allows proper loading and in-place DOM update of xhtml views. It is
- suitably augmented to trigger necessary events, and process CubicWeb
- specific elements such as the facet system, fckeditor, etc.
-
-
-A simple example with asyncRemoteExec
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In the python side, we have to extend the BaseController class. The
-@jsonize decorator ensures that the `return value` of the method is
-encoded as JSON data. By construction, the JSonController inputs
-everything in JSON format.
-
-.. sourcecode: python
-
- from cubicweb.web.views.basecontrollers import JSonController, jsonize
-
- @monkeypatch(JSonController)
- @jsonize
- def js_say_hello(self, name):
- return u'hello %s' % name
-
-In the javascript side, we do the asynchronous call. Notice how it
-creates a `deferred` object. Proper treatment of the return value or
-error handling has to be done through the addCallback and addErrback
-methods.
-
-.. sourcecode: javascript
-
- function asyncHello(name) {
- var deferred = asyncRemoteExec('say_hello', name);
- deferred.addCallback(function (response) {
- alert(response);
- });
- deferred.addErrback(function (error) {
- alert('something fishy happened');
- });
- }
-
- function syncHello(name) {
- alert( remoteExec('say_hello', name) );
- }
-
-Anatomy of a reloadComponent call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`reloadComponent` allows to dynamically replace some DOM node with new
-elements. It has the following signature:
-
-* `compid` (mandatory) is the name of the component to be reloaded
-
-* `rql` (optional) will be used to generate a result set given as
- argument to the selected component
-
-* `registry` (optional) defaults to 'components' but can be any other
- valid registry name
-
-* `nodeid` (optional) defaults to compid + 'Component' but can be any
- explicitly specified DOM node id
-
-* `extraargs` (optional) should be a dictionary of values that will be
- given to the cell_call method of the component
-
-A simple reloadComponent example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The server side implementation of `reloadComponent` is the
-js_component method of the JSonController.
-
-The following function implements a two-steps method to delete a
-standard bookmark and refresh the UI, while keeping the UI responsive.
-
-.. sourcecode:: javascript
-
- function removeBookmark(beid) {
- d = asyncRemoteExec('delete_bookmark', beid);
- d.addCallback(function(boxcontent) {
- reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
- document.location.hash = '#header';
- updateMessage(_("bookmark has been removed"));
- });
- }
-
-`reloadComponent` is called with the id of the bookmark box as
-argument, no rql expression (because the bookmarks display is actually
-independant of any dataset context), a reference to the 'boxes'
-registry (which hosts all left, right and contextual boxes) and
-finally an explicit 'bookmarks_box' nodeid argument that stipulates
-the target DOM node.
-
-Anatomy of a loadxhtml call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
-proper loading and in-place DOM update of xhtml views. The existing
-`jQuery.load`_ function does not handle xhtml, hence the addition. The
-API of loadxhtml is roughly similar to that of `jQuery.load`_.
-
-.. _`jQuery.load`: http://api.jquery.com/load/
-
-
-* `url` (mandatory) should be a complete url (typically referencing
- the JSonController, but this is not strictly mandatory)
-
-* `data` (optional) is a dictionary of values given to the
- controller specified through an `url` argument; some keys may have a
- special meaning depending on the choosen controller (such as `fname`
- for the JSonController); the `callback` key, if present, must refer
- to a function to be called at the end of loadxhtml (more on this
- below)
-
-* `reqtype` (optional) specifies the request method to be used (get or
- post); if the argument is 'post', then the post method is used,
- otherwise the get method is used
-
-* `mode` (optional) is one of `replace` (the default) which means the
- loaded node will replace the current node content, `swap` to replace
- the current node with the loaded node, and `append` which will
- append the loaded node to the current node content
-
-About the `callback` option:
-
-* it is called with two parameters: the current node, and a list
- containing the loaded (and post-processed node)
-
-* whenever is returns another function, this function is called in
- turn with the same parameters as above
-
-This mechanism allows callback chaining.
-
-
-A simple example with loadxhtml
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here we are concerned with the retrieval of a specific view to be
-injected in the live DOM. The view will be of course selected
-server-side using an entity eid provided by the client side.
-
-.. sourcecode:: python
-
- from cubicweb import typed_eid
- from cubicweb.web.views.basecontrollers import JSonController, xhtmlize
-
- @monkeypatch(JSonController)
- @xhtmlize
- def js_frob_status(self, eid, frobname):
- entity = self._cw.entity_from_eid(typed_eid(eid))
- return entity.view('frob', name=frobname)
-
-.. sourcecode:: javascript
-
- function update_some_div(divid, eid, frobname) {
- var params = {fname:'frob_status', eid: eid, frobname:frobname};
- jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
- }
-
-In this example, the url argument is the base json url of a cube
-instance (it should contain something like
-`http://myinstance/json?`). The actual JSonController method name is
-encoded in the `params` dictionary using the `fname` key.
-
-A more real-life example from CubicWeb
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A frequent use case of Web 2 applications is the delayed (or
-on-demand) loading of pieces of the DOM. This is typically achieved
-using some preparation of the initial DOM nodes, jQuery event handling
-and proper use of loadxhtml.
-
-We present here a skeletal version of the mecanism used in CubicWeb
-and available in web/views/tabs.py, in the `LazyViewMixin` class.
-
-.. sourcecode:: python
-
- def lazyview(self, vid, rql=None):
- """ a lazy version of wview """
- w = self.w
- self._cw.add_js('cubicweb.lazy.js')
- urlparams = {'vid' : vid, 'fname' : 'view'}
- if rql is not None:
- urlparams['rql'] = rql
- w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
- vid, xml_escape(self._cw.build_url('json', **urlparams))))
- w(u'</div>')
- self._cw.add_onload(u"""
- jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
- load_now('#lazy-%(vid)s');});"""
- % {'event': 'load_%s' % vid, 'vid': vid})
-
-This creates a `div` with a specific event associated to it.
-
-The full version deals with:
-
-* optional parameters such as an entity eid, an rset
-
-* the ability to further reload the fragment
-
-* the ability to display a spinning wheel while the fragment is still
- not loaded
-
-* handling of browsers that do not support ajax (search engines,
- text-based browsers such as lynx, etc.)
-
-The javascript side is quite simple, due to loadxhtml awesomeness.
-
-.. sourcecode:: javascript
-
- function load_now(eltsel) {
- var lazydiv = jQuery(eltsel);
- lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
- }
-
-This is all significantly different of the previous `simple example`
-(albeit this example actually comes from real-life code).
-
-Notice how the `cubicweb:loadurl` is used to convey the url
-information. The base of this url is similar to the global javascript
-JSON_BASE_URL. According to the pattern described earlier,
-the `fname` parameter refers to the standard `js_view` method of the
-JSonController. This method renders an arbitrary view provided a view
-id (or `vid`) is provided, and most likely an rql expression yielding
-a result set against which a proper view instance will be selected.
-
-The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML
-in a specific cubicweb namespace. It is a means to pass information
-without breaking HTML nor XHTML compliance and without resorting to
-ungodly hacks.
-
-Given all this, it is easy to add a small nevertheless useful feature
-to force the loading of a lazy view (for instance, a very
-computation-intensive web page could be scinded into one fast-loading
-part and a delayed part).
-
-On the server side, a simple call to a javascript function is
-sufficient.
-
-.. sourcecode:: python
-
- def forceview(self, vid):
- """trigger an event that will force immediate loading of the view
- on dom readyness
- """
- self._cw.add_onload("trigger_load('%s');" % vid)
-
-The browser-side definition follows.
-
-.. sourcecode:: javascript
-
- function trigger_load(divid) {
- jQuery('#lazy-' + divd).trigger('load_' + divid);
- }
-
-
-
-
-XXX reloadComponent
-XXX userCallback / user_callback
-
-Javascript library: overview
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* jquery.* : jquery and jquery UI library
-
-* cubicweb.ajax.js : concentrates all ajax related facilities (it
- extends jQuery with the loahxhtml function, provides a handfull of
- high-level ajaxy operations like asyncRemoteExec, reloadComponent,
- replacePageChunk, getDomFromResponse)
-
-* cubicweb.python.js : adds a number of practical extension to stdanrd
- javascript objects (on Date, Array, String, some list and dictionary
- operations), and a pythonesque way to build classes. Defines a
- CubicWeb namespace.
-
-* cubicweb.htmlhelpers.js : a small bag of convenience functions used
- in various other cubicweb javascript resources (baseuri, progress
- cursor handling, popup login box, html2dom function, etc.)
-
-* cubicweb.widgets.js : provides a widget namespace and constructors
- and helpers for various widgets (mainly facets and timeline)
-
-* cubicweb.edition.js : used by edition forms
-
-* cubicweb.preferences.js : used by the preference form
-
-* cubicweb.facets.js : used by the facets mechanism
-
-There is also javascript support for massmailing, gmap (google maps),
-fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
-AppEngine), flot (charts drawing), tabs and bookmarks.
--- a/doc/book/en/development/devweb/property.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-The property mecanism
----------------------
-XXX CWProperty and co
-
-
-Property API
-~~~~~~~~~~~~
-XXX feed me
-
-Registering and using your own property
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-XXX feed me
--- a/doc/book/en/development/devweb/publisher.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-.. _publisher:
-
-Publisher
----------
-
-What happens when an HTTP request is issued ?
-
-The story begins with the ``CubicWebPublisher.main_publish``
-method. We do not get upper in the bootstrap process because it is
-dependant on the used HTTP library. With `twisted`_ however,
-``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the
-real entry point.
-
-What main_publish does:
-
-* get a controller id and a result set from the path (this is actually
- delegated to the `urlpublisher` component)
-
-* the controller is then selected (if not, this is considered an
- authorization failure and signaled as such) and called
-
-* then either a proper result is returned, in which case the
- request/connection object issues a ``commit`` and returns the result
-
-* or error handling must happen:
-
- * ``ValidationErrors`` pop up there and may lead to a redirect to a
- previously arranged url or standard error handling applies
- * an HTTP 500 error (`Internal Server Error`) is issued
-
-
-Now, let's turn to the controller. There are many of them in
-:mod:`cubicweb.web.views.basecontrollers`. We can just follow the
-default `view` controller that is selected on a `view` path. See the
-:ref:`controllers` chapter for more information on controllers.
-
-The `View` controller's entry point is the `publish` method. It does
-the following:
-
-* compute the `main` view to be applied, using either the given result
- set or building one from a user provided rql string (`rql` and `vid`
- can be forced from the url GET parameters), that is:
-
- * compute the `vid` using the result set and the schema (see
- `cubicweb.web.views.vid_from_rset`)
- * handle all error cases that could happen in this phase
-
-* do some cache management chores
-
-* select a main template (typically `TheMainTemplate`, see chapter
- :ref:`templates`)
-
-* call it with the result set and the computed view.
-
-What happens next actually depends on the template and the view, but
-in general this is the rendering phase.
-
-
-CubicWebPublisher API
-`````````````````````
-
-.. autoclass:: cubicweb.web.application.CubicWebPublisher
- :members:
--- a/doc/book/en/development/devweb/request.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-The `Request` class (`cubicweb.web`)
-------------------------------------
-
-Overview
-````````
-
-A request instance is created when an HTTP request is sent to the web server.
-It contains informations such as form parameters, user authenticated, etc.
-
-**Globally, a request represents a user query, either through HTTP or not
-(we also talk about RQL queries on the server side for example).**
-
-An instance of `Request` has the following attributes:
-
-* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
- user
-* `form`, dictionary containing the values of a web form
-* `encoding`, character encoding to use in the response
-
-But also:
-
-* `Session data handling`
-
- * `session_data()`, returns a dictionary containing all the session data
- * `get_session_data(key, default=None)`, returns a value associated to the given
- key or the value `default` if the key is not defined
- * `set_session_data(key, value)`, assign a value to a key
- * `del_session_data(key)`, suppress the value associated to a key
-
-* `Cookies handling`
-
- * `get_cookie()`, returns a dictionary containing the value of the header
- HTTP 'Cookie'
- * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
- with a minimal 5 minutes length of duration by default (`maxage` = None
- returns a *session* cookie which will expire when the user closes the browser
- window)
- * `remove_cookie(cookie, key)`, forces a value to expire
-
-* `URL handling`
-
- * `url()`, returns the full URL of the HTTP request
- * `base_url()`, returns the root URL of the web application
- * `relative_path()`, returns the relative path of the request
-
-* `And more...`
-
- * `set_content_type(content_type, filename=None)`, adds the header HTTP
- 'Content-Type'
- * `get_header(header)`, returns the value associated to an arbitrary header
- of the HTTP request
- * `set_header(header, value)`, adds an arbitrary header in the response
- * `cursor()` returns a RQL cursor on the session
- * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
- * `property_value(key)`, properties management (`CWProperty`)
- * dictionary `data` to store data to share informations between components
- *while a request is executed*
-
-Please note that this class is abstract and that a concrete implementation
-will be provided by the *frontend* web used (in particular *twisted* as of
-today). For the views or others that are executed on the server side,
-most of the interface of `Request` is defined in the session associated
-to the client.
-
-API
-```
-
-The elements we gave in overview for above are built in three layers,
-from ``cubicweb.req.RequestSessionBase``, ``cubicweb.dbapi.DBAPIRequest`` and
-``cubicweb.web.CubicWebRequestBase``.
-
-.. autoclass:: cubicweb.req.RequestSessionBase
- :members:
-
-.. autoclass:: cubicweb.dbapi.DBAPIRequest
- :members:
-
-.. autoclass:: cubicweb.web.request.CubicWebRequestBase
- :members:
--- a/doc/book/en/development/devweb/rtags.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-Configuring the user interface
-------------------------------
-
-.. _relation_tags:
-
-Relation tags
-~~~~~~~~~~~~~
-.. automodule:: cubicweb.rtags
-
-.. _uicfg:
-
-The ``uicfg`` module
-~~~~~~~~~~~~~~~~~~~~
-
-.. note::
-
- The part of uicfg that deals with primary views is in the
- :ref:`primary_view_configuration` chapter.
-
-.. automodule:: cubicweb.web.uicfg
-
--- a/doc/book/en/development/devweb/views/basetemplates.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. |cubicweb| replace:: *CubicWeb*
-
-.. _templates:
-
-Templates
-=========
-
-Templates are the entry point for the |cubicweb| view system. As seen
-in :ref:`views_base_class`, there are two kinds of views: the
-templatable and non-templatable.
-
-Non-templatable views are standalone. They are responsible for all the
-details such as setting a proper content type (or mime type), the
-proper document headers, namespaces, etc. Examples are pure xml views
-such as RSS or Semantic Web views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked
-Data`_, etc.).
-
-.. _`SIOC`: http://sioc-project.org/
-.. _`DOAP`: http://trac.usefulinc.com/doap
-.. _`FOAF`: http://www.foaf-project.org/
-.. _`Linked Data`: http://linkeddata.org/
-
-Templatable views are not concerned with such pesky details. They
-leave it to the template. Conversely, the template's main job is to:
-
-* set up the proper document header and content type
-* define the general layout of a document
-* invoke adequate views in the various sections of the document
-
-
-Look at :mod:`cubicweb.web.views.basetemplates` and you will find the
-base templates used to generate (X)HTML for your application. The most
-important template there is `TheMainTemplate`.
-
-.. _the_main_template_layout:
-
-TheMainTemplate
----------------
-
-.. _the_main_template_sections:
-
-Layout and sections
-```````````````````
-
-A page is composed as indicated on the schema below :
-
-.. image:: ../../../images/main_template.png
-
-The sections dispatches specific views:
-
-* `header`: the rendering of the header is delegated to the
- `htmlheader` view, whose default implementation can be found in
- ``basetemplates.py`` and which does the following things:
-
- * inject the favicon if there is one
- * inject the global style sheets and javascript resources
- * call and display a link to an rss component if there is one available
-
- it also sets up the page title, and fills the actual
- `header` section with top-level components, using the `header` view, which:
-
- * tries to display a logo, the name of the application and the `breadcrumbs`
- * provides a login status area
- * provides a login box (hiden by default)
-
-* `left column`: this is filled with all selectable boxes matching the
- `left` context (there is also a right column but nowadays it is
- seldom used due to bad usability)
-
-* `contentcol`: this is the central column; it is filled with:
-
- * the `rqlinput` view (hidden by default)
- * the `applmessages` component
- * the `contentheader` view which in turns dispatches all available
- content navigation components having the `navtop` context (this
- is used to navigate through entities implementing the IPrevNext
- interface)
- * the view that was given as input to the template's `call`
- method, also dealing with pagination concerns
- * the `contentfooter`
-
-* `footer`: adds all footer actions
-
-.. note::
-
- How and why a view object is given to the main template is explained
- in the :ref:`publisher` chapter.
-
-Class attributes
-````````````````
-
-We can also control certain aspects of the main template thanks to the following
-forms parameters:
-
-* `__notemplate`, if present (whatever the value assigned), only the content view
- is returned
-* `__force_display`, if present and its value is not null, no navigation
- whatever the number of entities to display
-* `__method`, if the result set to render contains only one entity and this
- parameter is set, it refers to a method to call on the entity by passing it
- the dictionary of the forms parameters, before going the classic way (through
- step 1 and 2 described juste above)
-
-Other templates
----------------
-
-Other standard templates include:
-
-* `login` and `logout`
-
-* `error-template` specializes TheMainTemplate to do proper end-user
- output if an error occurs during the computation of TheMainTemplate
- (it is a fallback view).
--- a/doc/book/en/development/devweb/views/baseviews.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Base views
-----------
-
-*CubicWeb* provides a lot of standard views, that can be found in
- :mod:`cubicweb.web.views` and :mod:`cubicweb.web.views.baseviews`.
-
-A certain number of views are used to build the web interface, which
-apply to one or more entities. Their identifier is what distinguish
-them from each others and the main ones are:
-
-HTML views
-~~~~~~~~~~
-
-Special views
-`````````````
-
-*noresult*
- This view is the default view used when no result has been found
- (e.g. empty result set).
-
-*final*
- Display the value of a cell without trasnformation (in case of a non final
- entity, we see the eid). Applicable on any result set.
-
-.. note::
-
- `final` entities are merely attributes.
-
-*null*
- This view is the default view used when nothing needs to be rendered.
- It is always applicable.
-
-Entity views
-````````````
-
-*incontext, outofcontext*
- Those are used to display a link to an entity, depending on the
- entity having to be displayed in or out of context
- (of another entity). By default it respectively produces the
- result of `textincontext` and `textoutofcontext` wrapped in a link
- leading to the primary view of the entity.
-
-*oneline*
- This view is used when we can't tell if the entity should be considered as
- displayed in or out of context. By default it produces the result of `text`
- in a link leading to the primary view of the entity.
-
-List
-`````
-
-*list*
- This view displays a list of entities by creating a HTML list (`<ul>`)
- and call the view `listitem` for each entity of the result set.
-
-*listitem*
- This view redirects by default to the `outofcontext` view.
-
-*sameetypelist*
- This view displays a list of entities of the same type, in HTML section (`<div>`)
- and call the view `sameetypelistitem` for each entity of the result set.
-
-*sameetypelistitem*
- This view redirects by default to the `listitem` view.
-
-*csv*
- This view applies to entity groups, which are individually
- displayed using the `incontext` view. It displays each entity as a
- coma separated list. It is NOT related to the well-known text file
- format.
-
-Text entity views
-~~~~~~~~~~~~~~~~~
-
-*text*
- This is the simplest text view for an entity. By default it returns the
- result of the `.dc_title` method, which is cut to fit the
- `navigation.short-line-size` property if necessary.
-
-*textincontext, textoutofcontext*
- Similar to the `text` view, but called when an entity is considered out or
- in context. By default it returns respectively the result of the
- methods `.dc_title` and `.dc_long_title` of the entity.
--- a/doc/book/en/development/devweb/views/boxes.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-Boxes
------
-
-(:mod:`cubicweb.web.views.boxes`)
-
-*sidebox*
- This view displays usually a side box of some related entities
- in a primary view.
-
-The action box
-~~~~~~~~~~~~~~~
-
-The ``add_related`` is an automatic menu in the action box that allows to create
-an entity automatically related to the initial entity (context in
-which the box is displayed). By default, the links generated in this
-box are computed from the schema properties of the displayed entity,
-but it is possible to explicitly specify them thanks to the
-`cubicweb.web.uicfg.rmode` *relation tag*:
-
-* `link`, indicates that a relation is in general created pointing
- to an existing entity and that we should not to display a link
- for this relation
-
-* `create`, indicates that a relation is in general created pointing
- to new entities and that we should display a link to create a new
- entity and link to it automatically
-
-
-If necessary, it is possible to overwrite the method
-`relation_mode(rtype, targettype, x='subject')` to dynamically
-compute a relation creation category.
-
-Please note that if at least one action belongs to the `addrelated` category,
-the automatic behavior is desactivated in favor of an explicit behavior
-(e.g. display of `addrelated` category actions only).
-
--- a/doc/book/en/development/devweb/views/breadcrumbs.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-Breadcrumbs
------------
-
-Breadcrumbs are a navigation component to help the user locate himself
-along a path of entities.
-
-Display
-~~~~~~~
-
-Breadcrumbs are displayed by default in the header section (see
-:ref:`the_main_template_sections`). With the default main
-template, the header section is composed by the logo, the application
-name, breadcrumbs and, at the most right, the login box. Breadcrumbs
-are displayed just next to the application name, thus breadcrumbs
-begin with a separator.
-
-Here is the header section of the CubicWeb's forge:
-
-.. image:: ../../../images/breadcrumbs_header.png
-
-There are three breadcrumbs components defined in
-:mod:`cubicweb.web.views.ibreadcrumbs`:
-
-- `BreadCrumbEntityVComponent`: displayed for a result set with one line
- if the entity implements the ``IBreadCrumbs`` interface.
-- `BreadCrumbETypeVComponent`: displayed for a result set with more than
- one line, but with all entities of the same type which implement the
- ``IBreadCrumbs`` interface.
-- `BreadCrumbAnyRSetVComponent`: displayed for any other result set.
-
-Building breadcrumbs
-~~~~~~~~~~~~~~~~~~~~
-
-The ``IBreadCrumbs`` interface is defined in the
-:mod:`cubicweb.interfaces` module. It specifies that an entity which
-implements this interface must have a ``breadcrumbs`` method.
-
-.. note::
-
- Redefining the breadcrumbs is the hammer way to do it. Another way
- is to define the `parent` method on an entity (as defined in the
- `ITree` interface). If available, it will be used to compute
- breadcrumbs.
-
-Here is the API of the ``breadcrumbs`` method:
-
-.. automethod:: cubicweb.interfaces.IBreadCrumbs.breadcrumbs
-
-If the breadcrumbs method return a list of entities, the
-``cubicweb.web.views.ibreadcrumbs.BreadCrumbView`` is used to display
-the elements.
-
-By default, for any entity, if recurs=True, breadcrumbs method returns
-a list of entities, else a list of a simple string.
-
-In order to see a hierarchical breadcrumbs, entities must have a
-``parent`` method which returns the parent entity. By default this
-method doesn't exist on entity, given that it can not be guessed.
--- a/doc/book/en/development/devweb/views/editforms.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-Standard forms
---------------
-
- (:mod:`cubicweb.web.views.editforms`)
-
-XXX feed me
--- a/doc/book/en/development/devweb/views/embedding.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Embedding external pages
-------------------------
-
-(:mod:`cubicweb.web.views.embedding`)
-
-including external content
-
--- a/doc/book/en/development/devweb/views/idownloadable.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-The 'download' view
--------------------
-
-(:mod:`cubicweb.web.views.idownloadable`)
-
--- a/doc/book/en/development/devweb/views/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-The View system
-===============
-
-This chapter aims to describe the concept of a `view` used all along
-the development of a web application and how it has been implemented
-in |cubicweb|.
-
-
-.. toctree::
- :maxdepth: 3
-
- views
- basetemplates
- primary
- baseviews
- startup
- boxes
- table
- xmlrss
-.. editforms
-
-.. toctree::
- :maxdepth: 3
-
- urlpublish
- breadcrumbs
-.. wdoc
-.. embedding
-.. idownloadable
-
--- a/doc/book/en/development/devweb/views/primary.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,312 +0,0 @@
-.. _primary_view:
-
-The Primary View
------------------
-
-(:mod:`cubicweb.web.views.primary`)
-
-By default, *CubicWeb* provides a view that fits every available
-entity type. This is the first view you might be interested in
-modifying. It is also one of the richest and most complex.
-
-It is automatically selected on a one line result set containing an
-entity.
-
-This view is supposed to render a maximum of informations about the
-entity.
-
-.. _primary_view_layout:
-
-Layout
-``````
-
-The primary view has the following layout.
-
-.. image:: ../../../images/primaryview_template.png
-
-.. _primary_view_configuration:
-
-Primary view configuration
-``````````````````````````
-
-If you want to customize the primary view of an entity, overriding the primary
-view class may not be necessary. For simple adjustments (attributes or relations
-display locations and styles), a much simpler way is to use uicfg.
-
-Attributes/relations display location
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-In the primary view, there are 3 sections where attributes and
-relations can be displayed (represented in pink in the image above):
-
-* attributes
-* relations
-* sideboxes
-
-**Attributes** can only be displayed in the attributes section (default
- behavior). They can also be hidden.
-
-For instance, to hide the ``title`` attribute of the ``Blog`` entity:
-
-.. sourcecode:: python
-
- from cubicweb.web import uicfg
- uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
-
-**Relations** can be either displayed in one of the three sections or hidden.
-
-For relations, there are two methods:
-
-* ``tag_object_of`` for modifying the primary view of the object
-* ``tag_subject_of`` for modifying the primary view of the subject
-
-These two methods take two arguments:
-
-* a triplet ``(subject, relation_name, object)``, where subject or object can be replaced with ``'*'``
-* the section name or ``hidden``
-
-.. sourcecode:: python
-
- pv_section = uicfg.primaryview_section
- # hide every relation `entry_of` in the `Blog` primary view
- pv_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
-
- # display `entry_of` relations in the `relations`
- # section in the `BlogEntry` primary view
- pv_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations')
-
-
-Display content
-^^^^^^^^^^^^^^^
-
-You can use ``primaryview_display_ctrl`` to customize the display of attributes
-or relations. Values of ``primaryview_display_ctrl`` are dictionaries.
-
-
-Common keys for attributes and relations are:
-
-* ``vid``: specifies the regid of the view for displaying the attribute or the relation.
-
- If ``vid`` is not specified, the default value depends on the section:
- * ``attributes`` section: 'reledit' view
- * ``relations`` section: 'autolimited' view
- * ``sideboxes`` section: 'sidebox' view
-
-* ``order``: int used to control order within a section. When not specified,
- automatically set according to order in which tags are added.
-
-.. sourcecode:: python
-
- # let us remind the schema of a blog entry
- class BlogEntry(EntityType):
- title = String(required=True, fulltextindexed=True, maxsize=256)
- publish_date = Date(default='TODAY')
- content = String(required=True, fulltextindexed=True)
- entry_of = SubjectRelation('Blog', cardinality='?*')
-
- # now, we want to show attributes
- # with an order different from that in the schema definition
- view_ctrl = uicfg.primaryview_display_ctrl
- for index, attr in enumerate('title', 'content', 'publish_date'):
- view_ctrl.tag_attribute(('BlogEntry', attr), {'order': index})
-
-Keys for relations only:
-
-* ``label``: label for the relations section or side box
-
-* ``showlabel``: boolean telling whether the label is displayed
-
-* ``limit``: boolean telling if the results should be limited. If so, a link to all results is displayed
-
-* ``filter``: callback taking the related result set as argument and returning it filtered
-
-.. sourcecode:: python
-
- pv_section = uicfg.primaryview_section
- # in `CWUser` primary view, display `created_by`
- # relations in relations section
- pv_section.tag_object_of(('*', 'created_by', 'CWUser'), 'relations')
-
- # display this relation as a list, sets the label,
- # limit the number of results and filters on comments
- def filter_comment(rset):
- return rset.filtered_rset(lambda x: x.e_schema == 'Comment')
- pv_ctrl = uicfg.primaryview_display_ctrl
- pv_ctrl.tag_object_of(('*', 'created_by', 'CWUser'),
- {'vid': 'list', 'label': _('latest comment(s):'),
- 'limit': True,
- 'filter': filter_comment})
-
-.. warning:: with the ``primaryview_display_ctrl`` rtag, the subject or the
- object of the relation is ignored for respectively ``tag_object_of`` or
- ``tag_subject_of``. To avoid warnings during execution, they should be set to
- ``'*'``.
-
-Rendering methods and attributes
-````````````````````````````````
-
-The basic layout of a primary view is as in the
-:ref:`primary_view_layout` section. This layout is actually drawn by
-the `render_entity` method.
-
-The methods you may want to modify while customizing a ``PrimaryView``
-are:
-
-*render_entity_title(self, entity)*
- Renders the entity title using the ``def dc_title(self)`` method.
-
-*render_entity_metadata(self, entity)*
- Renders the entity metadata by calling the ``metadata`` view on the
- entity. This generic view is in cubicweb.views.baseviews.
-
-*render_entity_attributes(self, entity)*
- Renders all the attribute of an entity with the exception of
- attribute of type `Password` and `Bytes`. The skip_none class
- attribute controls the display of None valued attributes.
-
-*render_entity_relations(self, entity)*
- Renders all the relations of the entity in the main section of the page.
-
-*render_side_boxes(self, entity, boxes)*
- Renders relations of the entity in a side box.
-
-The placement of relations in the relations section or in side boxes
-can be controlled through the :ref:`primary_view_configuration` mechanism.
-
-*content_navigation_components(self, context)*
- This method is applicable only for entity type implementing the interface
- `IPrevNext`. This interface is for entities which can be linked to a previous
- and/or next entity. This method will render the navigation links between
- entities of this type, either at the top or at the bottom of the page
- given the context (navcontent{top|bottom}).
-
-Also, please note that by setting the following attributes in your
-subclass, you can already customize some of the rendering:
-
-*show_attr_label*
- Renders the attribute label next to the attribute value if set to True.
- Otherwise, does only display the attribute value.
-
-*show_rel_label*
- Renders the relation label next to the relation value if set to True.
- Otherwise, does only display the relation value.
-
-*skip_none*
- Does not render an attribute value that is None if set to True.
-
-*main_related_section*
- Renders the relations of the entity if set to True.
-
-A good practice is for you to identify the content of your entity type for which
-the default rendering does not answer your need so that you can focus on the specific
-method (from the list above) that needs to be modified. We do not advise you to
-overwrite ``render_entity`` unless you want a completely different layout.
-
-Example of customization and creation
-`````````````````````````````````````
-
-We'll show you now an example of a ``primary`` view and how to customize it.
-
-We continue along the basic tutorial :ref:`tuto_blog`.
-
-If you want to change the way a ``BlogEntry`` is displayed, just override
-the method ``cell_call()`` of the view ``primary`` in ``BlogDemo/views.py``.
-
-.. sourcecode:: python
-
- from cubicweb.selectors import implements
- from cubicweb.web.views.primary import Primaryview
-
- class BlogEntryPrimaryView(PrimaryView):
- __select__ = PrimaryView.__select__ & implements('BlogEntry')
-
- def render_entity_attributes(self, entity):
- self.w(u'<p>published on %s</p>' %
- entity.publish_date.strftime('%Y-%m-%d'))
- super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
-
-The above source code defines a new primary view for
-``BlogEntry``. The `id` class attribute is not repeated there since it
-is inherited through the `primary.PrimaryView` class.
-
-The selector for this view chains the selector of the inherited class
-with its own specific criterion.
-
-The view method ``self.w()`` is used to output data. Here `lines
-08-09` output HTML for the publication date of the entry.
-
-.. image:: ../../../images/lax-book.09-new-view-blogentry.en.png
- :alt: blog entries now look much nicer
-
-Let us now improve the primary view of a blog
-
-.. sourcecode:: python
-
- from logilab.mtconverter import xml_escape
- from cubicweb.selectors import implements, one_line_rset
- from cubicweb.web.views.primary import Primaryview
-
- class BlogPrimaryView(PrimaryView):
- __regid__ = 'primary'
- __select__ = PrimaryView.__select__ & implements('Blog')
- rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
-
- def render_entity_relations(self, entity):
- rset = self._cw.execute(self.rql, {'b' : entity.eid})
- for entry in rset.entities():
- self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
-
- class BlogEntryInBlogView(EntityView):
- __regid__ = 'inblogcontext'
- __select__ = implements('BlogEntry')
-
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- self.w(u'<a href="%s" title="%s">%s</a>' %
- entity.absolute_url(),
- xml_escape(entity.content[:50]),
- xml_escape(entity.description))
-
-This happens in two places. First we override the
-render_entity_relations method of a Blog's primary view. Here we want
-to display our blog entries in a custom way.
-
-At `line 10`, a simple request is made to build a result set with all
-the entities linked to the current ``Blog`` entity by the relationship
-``entry_of``. The part of the framework handling the request knows
-about the schema and infers that such entities have to be of the
-``BlogEntry`` kind and retrieves them (in the prescribed publish_date
-order).
-
-The request returns a selection of data called a result set. Result
-set objects have an .entities() method returning a generator on
-requested entities (going transparently through the `ORM` layer).
-
-At `line 13` the view 'inblogcontext' is applied to each blog entry to
-output HTML. (Note that the 'inblogcontext' view is not defined
-whatsoever in *CubicWeb*. You are absolutely free to define whole view
-families.) We juste arrange to wrap each blogentry output in a 'p'
-html element.
-
-Next, we define the 'inblogcontext' view. This is NOT a primary view,
-with its well-defined sections (title, metadata, attribtues,
-relations/boxes). All a basic view has to define is cell_call.
-
-Since views are applied to result sets which can be tables of data, we
-have to recover the entity from its (row,col)-coordinates (`line
-20`). Then we can spit some HTML.
-
-.. warning::
-
- Be careful: all strings manipulated in *CubicWeb* are actually
- unicode strings. While web browsers are usually tolerant to
- incoherent encodings they are being served, we should not abuse
- it. Hence we have to properly escape our data. The xml_escape()
- function has to be used to safely fill (X)HTML elements from Python
- unicode strings.
-
-Assuming we added entries to the blog titled `MyLife`, displaying it
-now allows to read its description and all its entries.
-
-.. image:: ../../../images/lax-book.10-blog-with-two-entries.en.png
- :alt: a blog and all its entries
--- a/doc/book/en/development/devweb/views/startup.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-Startup views
--------------
-
-(:mod:`cubicweb.web.views.startup`)
-
-The usual selectors are no_rset or yes. These views don't apply to a
-result set.
-
-*index*
- This view defines the home page of your application. It does not require
- a result set to apply to.
-
-*schema*
- A view dedicated to the display of the schema of the instance
-
--- a/doc/book/en/development/devweb/views/table.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-Table view
-----------
-
-(:mod:`cubicweb.web.views.tableview`)
-
-*table*
- Creates a HTML table (`<table>`) and call the view `cell` for each cell of
- the result set. Applicable on any result set.
-
-*cell*
- By default redirects to the `final` view if this is a final entity or
- `outofcontext` view otherwise
-
-
-API
-```
-
-.. autoclass:: cubicweb.web.views.tableview.TableView
- :members:
--- a/doc/book/en/development/devweb/views/urlpublish.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-URL publishing
---------------
-
-(:mod:`cubicweb.web.views.urlpublishing`)
-
-.. automodule:: cubicweb.web.views.urlpublishing
-
-.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent
- :members:
-
-URL rewriting
--------------
-
-(:mod:`cubicweb.web.views.urlrewrite`)
-
-.. autoclass:: cubicweb.web.views.urlrewrite.URLRewriter
- :members:
-
-.. autoclass:: cubicweb.web.views.urlrewrite.SimpleReqRewriter
- :members:
-
-.. autoclass:: cubicweb.web.views.urlrewrite.SchemaBasedRewriter
- :members:
-
-
-``SimpleReqRewriter`` is enough for a certain number of simple cases. If it is not sufficient, ``SchemaBasedRewriter`` allows to do more elaborate things.
-
-Here is an example of ``SimpleReqRewriter`` usage with plain string:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.urlrewrite import SimpleReqRewriter
- class TrackerSimpleReqRewriter(SimpleReqRewriter):
- rules = [
- ('/versions', dict(vid='versionsinfo')),
- ]
-
-When the url is `<base_url>/versions`, the view with the __regid__ `versionsinfo` is displayed.
-
-Here is an example of ``SimpleReqRewriter`` usage with regular expressions:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.urlrewrite import (
- SimpleReqRewriter, rgx)
-
- class BlogReqRewriter(SimpleReqRewriter):
- rules = [
- (rgx('/blogentry/([a-z_]+)\.rss'),
- dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
- 'X creation_date CD, X created_by U, '
- 'U login "%(user)s"'
- % {'user': r'\1'}, vid='rss'))),
- ]
-
-When a url matches the regular expression, the view with the __regid__
-`rss` which match the result set is displayed.
-
-Here is an example of ``SchemaBasedRewriter`` usage:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.urlrewrite import (
- SchemaBasedRewriter, rgx, build_rset)
-
- class TrackerURLRewriter(SchemaBasedRewriter):
- rules = [
- (rgx('/project/([^/]+)/([^/]+)/tests'),
- build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
- rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
- ]
--- a/doc/book/en/development/devweb/views/views.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-
-.. _Views:
-
-Principles
-----------
-
-We'll start with a description of the interface providing a basic
-understanding of the available classes and methods, then detail the
-view selection principle.
-
-A `View` is an object responsible for the rendering of data from the
-model into an end-user consummable form. They typically churn out an
-XHTML stream, but there are views concerned with email other non-html
-outputs.
-
-.. _views_base_class:
-
-Discovering possible views
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is possible to configure the web user interface to have a left box
-showing all the views than can be applied to the current result set.
-
-To enable this, click on your login at the top right corner. Chose
-"user preferences", then "boxes", then "possible views box" and check
-"visible = yes" before validating your changes.
-
-The views listed there we either not selected because of a lower
-score, or they were deliberately excluded by the main template logic.
-
-
-Basic class for views
-~~~~~~~~~~~~~~~~~~~~~
-
-Class `View` (`cubicweb.view`)
-```````````````````````````````
-
-This class is an abstraction of a view class, used as a base class for
-every renderable object such as views, templates and other user
-interface components.
-
-A `View` is instantiated to render a result set or part of a result
-set. `View` subclasses may be parametrized using the following class
-attributes:
-
-* `templatable` indicates if the view may be embedded in a main
- template or if it has to be rendered standalone (i.e. pure XML views
- must not be embedded in the main template of HTML pages)
-
-* if the view is not templatable, it should set the `content_type`
- class attribute to the correct MIME type (text/xhtml being the
- default)
-
-* the `category` attribute may be used in the interface to regroup
- related view kinds together
-
-A view writes to its output stream thanks to its attribute `w` (the
-append method of an `UStreamIO`, except for binary views).
-
-At instantiation time, the standard `_cw` and `cw_rset` attributes are
-added and the `w` attribute will be set at rendering time.
-
-The basic interface for views is as follows (remember that the result
-set has a tabular structure with rows and columns, hence cells):
-
-* `render(**context)`, render the view by calling `call` or
- `cell_call` depending on the context
-
-* `call(**kwargs)`, call the view for a complete result set or null
- (the default implementation calls `cell_call()` on each cell of the
- result set)
-
-* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
- result set (`row` and `col` being integers used to access the cell)
-
-* `url()`, returns the URL enabling us to get the view with the current
- result set
-
-* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of
- identifier `__vid` on the given result set. It is possible to give a
- fallback view identifier that will be used if the requested view is
- not applicable to the result set.
-
-* `html_headers()`, returns a list of HTML headers to be set by the
- main template
-
-* `page_title()`, returns the title to use in the HTML header `title`
-
-Other basic view classes
-````````````````````````
-Here are some of the subclasses of `View` defined in `cubicweb.common.view`
-that are more concrete as they relate to data rendering within the application:
-
-* `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
-* `StartupView`, start view that does not require a result set to apply to
-* `AnyRsetView`, view applicable to any result set
-
-Examples of views class
-```````````````````````
-
-- Using `templatable`, `content_type` and HTTP cache configuration
-
-.. sourcecode:: python
-
- class RSSView(XMLView):
- __regid__ = 'rss'
- title = _('rss')
- templatable = False
- content_type = 'text/xml'
- http_cache_manager = MaxAgeHTTPCacheManager
- cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
-
-
-- Using a custom selector
-
-.. sourcecode:: python
-
- class SearchForAssociationView(EntityView):
- """view called by the edition view when the user asks
- to search for something to link to the edited eid
- """
- __regid__ = 'search-associate'
- title = _('search for association')
- __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
-
-
-XML views, binaries views...
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-For views generating other formats than HTML (an image generated dynamically
-for example), and which can not simply be included in the HTML page generated
-by the main template (see above), you have to:
-
-* set the attribute `templatable` of the class to `False`
-* set, through the attribute `content_type` of the class, the MIME
- type generated by the view to `application/octet-stream` or any
- relevant and more specialised mime type
-
-For views dedicated to binary content creation (like dynamically generated
-images), we have to set the attribute `binary` of the class to `True` (which
-implies that `templatable == False`, so that the attribute `w` of the view could be
-replaced by a binary flow instead of unicode).
--- a/doc/book/en/development/devweb/views/wdoc.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Online documentation system
----------------------------
-
-(:mod:`cubicweb.web.views.wdoc`)
-
-XXX describe the on-line documentation system
-
--- a/doc/book/en/development/devweb/views/xmlrss.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-.. _XmlAndRss:
-
-XML and RSS views
------------------
-
-(:mod:`cubicweb.web.views.xmlrss`)
-
-Overview
-+++++++++
-
-*rss*
- Creates a RSS/XML view and call the view `rssitem` for each entity of
- the result set.
-
-*rssitem*
- Create a RSS/XML view for each entity based on the results of the dublin core
- methods of the entity (`dc_*`)
-
-RSS Channel Example
-++++++++++++++++++++
-
-Assuming you have several blog entries, click on the title of the
-search box in the left column. A larger search box should appear. Enter::
-
- Any X ORDERBY D WHERE X is BlogEntry, X creation_date D
-
-and you get a list of blog entries.
-
-Click on your login at the top right corner. Chose "user preferences",
-then "boxes", then "possible views box" and check "visible = yes"
-before validating your changes.
-
-Enter the same query in the search box and you will see the same list,
-plus a box titled "possible views" in the left column. Click on
-"entityview", then "RSS".
-
-You just applied the "RSS" view to the RQL selection you requested.
-
-That's it, you have a RSS channel for your blog.
-
-Try again with::
-
- Any X ORDERBY D WHERE X is BlogEntry, X creation_date D,
- X entry_of B, B title "MyLife"
-
-Another RSS channel, but a bit more focused.
-
-A last one for the road::
-
- Any C ORDERBY D WHERE C is Comment, C creation_date D LIMIT 15
-
-displayed with the RSS view, that's a channel for the last fifteen
-comments posted.
-
-[WRITE ME]
-
-* show that the RSS view can be used to display an ordered selection
- of blog entries, thus providing a RSS channel
-
-* show that a different selection (by category) means a different channel
--- a/doc/book/en/development/entityclasses/application-logic.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,166 +0,0 @@
-How to use entities objects
----------------------------
-
-The previous chapters detailed the classes and methods available to
-the developper at the so-called `ORM`_ level. However they say little
-about the common patterns of usage of these objects.
-
-.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
-
-Entities objects are used in the repository and web sides of
-CubicWeb. On the repository side of things, one should manipulate them
-in Hooks and Operations.
-
-Hooks and Operations provide support for the implementation of rules
-such as computed attributes, coherency invariants, etc (they play the
-same role as database triggers, but in a way that is independant of
-the actual data sources).
-
-So a lot of an application's business rules will be written in Hooks
-(or Operations).
-
-On the web side, views also typically operate using entity
-objects. Obvious entity methods for use in views are the dublin code
-method like dc_title, etc. For separation of concerns reasons, one
-should ensure no ui logic pervades the entities level, and also no
-business logic should creep into the views.
-
-In the duration of a transaction, entities objects can be instantiated
-many times, in views and hooks, even for the same database entity. For
-instance, in a classic CubicWeb deployment setup, the repository and
-the web frontend are separated process communicating over the
-wire. There is no way state can be shared between these processes
-(there is a specific API for that). Hence, it is not possible to use
-entity objects as messengers between these components of an
-application. It means that an attribute set as in `obj.x = 42`,
-whether or not x is actually an entity schema attribute, has a short
-life span, limited to the hook, operation or view within which the
-object was built.
-
-Setting an attribute or relation value can be done in the context of a
-Hook/Operation, using the obj.set_attributes(x=42) notation or a plain
-RQL SET expression.
-
-In views, it would be preferable to encapsulate the necessary logic in
-a method of the concerned entity class(es). But of course, this advice
-is also reasonnable for Hooks/Operations, though the separation of
-concerns here is less stringent than in the case of views.
-
-This leads to the practical role of entity objects: it's where an
-important part of the application logic lie (the other part being
-located in the Hook/Operations).
-
-Anatomy of an entity class
---------------------------
-
-We can look now at a real life example coming from the `tracker`_
-cube. Let us begin to study the entities/project.py content.
-
-.. sourcecode:: python
-
- class Project(TreeMixIn, AnyEntity):
- __regid__ = 'Project'
- __implements__ = AnyEntity.__implements__ + (ITree,)
- fetch_attrs, fetch_order = fetch_config(('name', 'description',
- 'description_format', 'summary'))
-
- TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")'
-
- tree_attribute = 'subproject_of'
- parent_target = 'subject'
- children_target = 'object'
-
- def dc_title(self):
- return self.name
-
-First we see that it uses an ITree interface and the TreeMixIn default
-implementation. The attributes `tree_attribute`, `parent_target` and
-`children_target` are used by the TreeMixIn code. This is typically
-used in views concerned with the representation of tree-like
-structures (CubicWeb provides several such views).
-
-It is important that the views themselves try not to implement this
-logic, not only because such views would be hardly applyable to other
-tree-like relations, but also because it is perfectly fine and useful
-to use such an interface in Hooks.
-
-In fact, Tree nature is a property of the data model that cannot be
-fully and portably expressed at the level of database entities (think
-about the transitive closure of the child relation). This is a further
-argument to implement it at entity class level.
-
-The `dc_title` method provides a (unicode string) value likely to be
-consummed by views, but note that here we do not care about output
-encodings. We care about providing data in the most universal format
-possible, because the data could be used by a web view (which would be
-responsible of ensuring XHTML compliance), or a console or file
-oriented output (which would have the necessary context about the
-needed byte stream encoding).
-
-The fetch_attrs, fetch_order class attributes are parameters of the
-`ORM`_ layer. They tell which attributes should be loaded at once on
-entity object instantiation (by default, only the eid is known, other
-attributes are loaded on demand), and which attribute is to be used to
-order the .related() and .unrelated() methods output.
-
-Finally, we can observe the big TICKET_DEFAULT_STATE_RESTR is a pure
-application domain piece of data. There is, of course, no limitation
-to the amount of class attributes of this kind.
-
-Let us now dig into more substantial pieces of code.
-
-.. sourcecode:: python
-
- def latest_version(self, states=('published',), reverse=None):
- """returns the latest version(s) for the project in one of the given
- states.
-
- when no states specified, returns the latest published version.
- """
- order = 'DESC'
- if reverse is not None:
- warn('reverse argument is deprecated',
- DeprecationWarning, stacklevel=1)
- if reverse:
- order = 'ASC'
- rset = self.versions_in_state(states, order, True)
- if rset:
- return rset.get_entity(0, 0)
- return None
-
- def versions_in_state(self, states, order='ASC', limit=False):
- """returns version(s) for the project in one of the given states, sorted
- by version number.
-
- If limit is true, limit result to one version.
- If reverse, versions are returned from the smallest to the greatest.
- """
- if limit:
- order += ' LIMIT 1'
- rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \
- 'WHERE V num N, V in_state S, S name IN (%s), ' \
- 'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states))
- return self._cw.execute(rql, {'p': self.eid})
-
-.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/
-
-These few lines exhibit the important properties we want to outline:
-
-* entity code is concerned with the application domain
-
-* it is NOT concerned with database coherency (this is the realm of
- Hooks/Operations); in other words, it assumes a coherent world
-
-* it is NOT concerned with end-user interfaces
-
-* however it can be used in both contexts
-
-* it does not create or manipulate the internal object's state
-
-* it plays freely with RQL expression as needed
-
-* it is not concerned with internationalization
-
-* it does not raise exceptions
-
-
--- a/doc/book/en/development/entityclasses/data-as-objects.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,136 +0,0 @@
-Access to persistent data
---------------------------
-
-Python-level access to persistent data is provided by the
-:class:`Entity <cubicweb.entity>` class.
-
-An entity class is bound to a schema entity type. Descriptors are added when
-classes are registered in order to initialize the class according to its schema:
-
-* we can access the defined attributes in the schema thanks to the attributes of
- the same name on instances (typed value)
-
-* we can access the defined relations in the schema thanks to the relations of
- the same name on instances (entities instances list)
-
-
-:Formatting and output generation:
-
- * `view(__vid, __registry='views', **kwargs)`, applies the given view to the entity
- (and returns an unicode string)
-
- * `absolute_url(*args, **kwargs)`, returns an absolute URL to access the primary view
- of an entity
-
- * `rest_path()`, returns a relative REST URL to get the entity
-
- * `printable_value(attr, value=_marker, attrtype=None, format='text/html', displaytime=True)`,
- returns a string enabling the display of an attribute value in a given format
- (the value is automatically recovered if necessary)
-
-:Data handling:
-
- * `as_rset()`, converts the entity into an equivalent result set simulating the
- request `Any X WHERE X eid _eid_`
-
- * `complete(skip_bytes=True)`, executes a request that recovers at
- once all the missing attributes of an entity
-
- * `get_value(name)`, returns the value associated to the attribute name given
- in parameter
-
- * `related(rtype, role='subject', limit=None, entities=False)`,
- returns a list of entities related to the current entity by the
- relation given in parameter
-
- * `unrelated(rtype, targettype, role='subject', limit=None)`,
- returns a result set corresponding to the entities not (yet)
- related to the current entity by the relation given in parameter
- and satisfying its constraints
-
- * `set_attributes(**kwargs)`, updates the attributes list with the corresponding
- values given named parameters
-
- * `set_relations(**kwargs)`, add relations to the given object. To
- set a relation where this entity is the object of the relation,
- use `reverse_<relation>` as argument name. Values may be an
- entity, a list of entities, or None (meaning that all relations of
- the given type from or to this object should be deleted).
-
- * `copy_relations(ceid)`, copies the relations of the entities having the eid
- given in the parameters on the current entity
-
- * `delete()` allows to delete the entity
-
-
-The :class:`AnyEntity` class
-----------------------------
-
-To provide a specific behavior for each entity, we have to define a class
-inheriting from `cubicweb.entities.AnyEntity`. In general, we define this class
-in `mycube.entities` module (or in a submodule if we want to split code among
-multiple files) so that it will be available on both server and client side.
-
-The class `AnyEntity` is a sub-class of Entity that add methods to it,
-and helps specializing (by further subclassing) the handling of a
-given entity type.
-
-Most methods defined for `AnyEntity`, in addition to `Entity`, add
-support for the `Dublin Core`_ metadata.
-
-.. _`Dublin Core`: http://dublincore.org/
-
-:Standard meta-data (Dublin Core):
-
- * `dc_title()`, returns a unicode string corresponding to the
- meta-data `Title` (used by default is the first non-meta attribute
- of the entity schema)
-
- * `dc_long_title()`, same as dc_title but can return a more
- detailed title
-
- * `dc_description(format='text/plain')`, returns a unicode string
- corresponding to the meta-data `Description` (looks for a
- description attribute by default)
-
- * `dc_authors()`, returns a unicode string corresponding to the meta-data
- `Authors` (owners by default)
-
- * `dc_creator()`, returns a unicode string corresponding to the
- creator of the entity
-
- * `dc_date(date_format=None)`, returns a unicode string corresponding to
- the meta-data `Date` (update date by default)
-
- * `dc_type(form='')`, returns a string to display the entity type by
- specifying the preferred form (`plural` for a plural form)
-
- * `dc_language()`, returns the language used by the entity
-
-
-:Misc methods:
-
- * `after_deletion_path`, return (path, parameters) which should be
- used as redirect information when this entity is being deleted
-
- * `pre_web_edit`, callback called by the web editcontroller when an
- entity will be created/modified, to let a chance to do some entity
- specific stuff (does nothing by default)
-
-Inheritance
------------
-
-When describing a data model, entities can inherit from other entities as is
-common in object-oriented programming.
-
-You have the possibility to adapt some entity attributes, as follow:
-
-.. sourcecode:: python
-
- from cubes.OTHER_CUBE import entities
- class EntityExample(entities.EntityExample):
- def dc_long_title(self):
- return '%s (%s)' % (self.name, self.description)
-
-Notice this is different than yams schema inheritance.
-
--- a/doc/book/en/development/entityclasses/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-Data as objects
-===============
-
-In this chapter, we will introduce the objects that are used to handle
-the logic associated to the data stored in the database.
-
-.. toctree::
- :maxdepth: 1
-
- data-as-objects
- load-sort
- interfaces
- application-logic
--- a/doc/book/en/development/entityclasses/interfaces.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-Interfaces
-----------
-
-This is the same thing as object-oriented programming `interfaces`_.
-
-.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
-
-Definition of an interface is quite trivial. An example from cubicweb
-itself (found in cubicweb/interfaces.py):
-
-.. sourcecode:: python
-
- class ITree(Interface):
-
- def parent(self):
- """returns the parent entity"""
-
- def children(self):
- """returns the item's children"""
-
- def children_rql(self):
- """returns RQL to get children"""
-
- def iterchildren(self):
- """iterates over the item's children"""
-
- def is_leaf(self):
- """returns true if this node as no child"""
-
- def is_root(self):
- """returns true if this node has no parent"""
-
- def root(self):
- """returns the root object"""
-
-
-Declaration of interfaces implemented by a class
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. sourcecode:: python
-
- from cubicweb.interfaces import ITree
- from cubicweb.mixins import TreeMixIn
-
- class MyEntity(TreeMixIn, AnyEntity):
- __regid__ = 'MyEntity'
- __implements__ = AnyEntity.__implements__ + ('ITree',)
-
- tree_attribute = 'filed_under'
-
-The TreeMixIn here provides a default implementation for the
-interface. The tree_attribute class attribute is actually used by this
-implementation to help implement correct behaviour.
-
-Interfaces (and some implementations as mixins) defined in the library
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: cubicweb.interfaces
- :members:
-
-.. automodule:: cubicweb.mixins
- :members:
-
-
-
--- a/doc/book/en/development/entityclasses/load-sort.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-
-.. _FetchAttrs:
-
-Loaded attributes and default sorting management
-````````````````````````````````````````````````
-
-* The class attribute `fetch_attrs` allows to define in an entity class a list
- of names of attributes or relations that should be automatically loaded when
- entities of this type are fetched from the database. In the case of relations,
- we are limited to *subject of cardinality `?` or `1`* relations.
-
-* The class method `fetch_order(attr, var)` expects an attribute (or relation)
- name as a parameter and a variable name, and it should return a string
- to use in the requirement `ORDERBY` of an RQL query to automatically
- sort the list of entities of such type according to this attribute, or
- `None` if we do not want to sort on the attribute given in the parameter.
- By default, the entities are sorted according to their creation date.
-
-* The class method `fetch_unrelated_order(attr, var)` is similar to
- the method `fetch_order` except that it is essentially used to
- control the sorting of drop-down lists enabling relations creation
- in the editing view of an entity. The default implementation uses
- the modification date. Here's how to adapt it for one entity (sort
- on the name attribute): ::
-
- class MyEntity(AnyEntity):
- __regid__ = 'MyEntity'
- fetch_attrs = ('modification_date', 'name')
-
- @classmethod
- def fetch_unrelated_order(cls, attr, var):
- if attr == 'name':
- return '%s ASC' % var
- return None
-
-
-The function `fetch_config(fetchattrs, mainattr=None)` simplifies the
-definition of the attributes to load and the sorting by returning a
-list of attributes to pre-load (considering automatically the
-attributes of `AnyEntity`) and a sorting function based on the main
-attribute (the second parameter if specified, otherwise the first
-attribute from the list `fetchattrs`). This function is defined in
-`cubicweb.entities`.
-
-For example: ::
-
- class Transition(AnyEntity):
- """..."""
- __regid__ = 'Transition'
- fetch_attrs, fetch_order = fetch_config(['name'])
-
-Indicates that for the entity type "Transition", you have to pre-load
-the attribute `name` and sort by default on this attribute.
--- a/doc/book/en/development/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-.. _Part2:
-
------------
-Development
------------
-
-This part is about developing web applications with the *CubicWeb* framework.
-
-.. toctree::
- :maxdepth: 2
- :numbered:
-
- cubes/index
- vreg.rst
- datamodel/index
- entityclasses/index
- devcore/index
- devweb/index
- devrepo/index
- testing.rst
- migration.rst
- profiling.rst
--- a/doc/book/en/development/migration.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,198 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _migration:
-
-Migration
-=========
-
-One of the main design goals of *CubicWeb* was to support iterative and agile
-development. For this purpose, multiple actions are provided to facilitate the
-improvement of an instance, and in particular to handle the changes to be
-applied to the data model, without loosing existing data.
-
-The current version of a cube (and of cubicweb itself) is provided in the file
-`__pkginfo__.py` as a tuple of 3 integers.
-
-Migration scripts management
-----------------------------
-
-Migration scripts has to be located in the directory `migration` of your
-cube and named accordingly:
-
-::
-
- <version n° X.Y.Z>[_<description>]_<mode>.py
-
-in which :
-
-* X.Y.Z is the model version number to which the script enables to migrate.
-
-* *mode* (between the last "_" and the extension ".py") is used for
- distributed installation. It indicates to which part
- of the application (RQL server, web server) the script applies.
- Its value could be :
-
- * `common`, applies to the RQL server as well as the web server and updates
- files on the hard drive (configuration files migration for example).
-
- * `web`, applies only to the web server and updates files on the hard drive.
-
- * `repository`, applies only to the RQL server and updates files on the
- hard drive.
-
- * `Any`, applies only to the RQL server and updates data in the database
- (schema and data migration for example).
-
-Again in the directory `migration`, the file `depends.map` allows to indicate
-that for the migration to a particular model version, you always have to first
-migrate to a particular *CubicWeb* version. This file can contain comments (lines
-starting by `#`) and a dependancy is listed as follows: ::
-
- <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
-
-For example: ::
-
- 0.12.0: 2.26.0
- 0.13.0: 2.27.0
- # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
- 0.15.0: 2.28.0
-
-Base context
-------------
-
-The following identifiers are pre-defined in migration scripts:
-
-* `config`, instance configuration
-
-* `interactive_mode`, boolean indicating that the script is executed in
- an interactive mode or not
-
-* `versions_map`, dictionary of migrated versions (key are cubes
- names, including 'cubicweb', values are (from version, to version)
-
-* `confirm(question)`, function asking the user and returning true
- if the user answers yes, false otherwise (always returns true in
- non-interactive mode)
-
-* `_()` is equivalent to `unicode` allowing to flag the strings to
- internationalize in the migration scripts.
-
-In the `repository` scripts, the following identifiers are also defined:
-
-* `commit(ask_confirm=True)`, request confirming and executing a "commit"
-
-* `schema`, instance schema (readen from the database)
-
-* `fsschema`, installed schema on the file system (e.g. schema of
- the updated model and cubicweb)
-
-* `repo`, repository object
-
-* `session`, repository session object
-
-
-Schema migration
-----------------
-The following functions for schema migration are available in `repository`
-scripts:
-
-* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
- attribute to an existing entity type. If the attribute type is not specified,
- then it is extracted from the updated schema.
-
-* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
- existing entity type.
-
-* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
-
-* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
- If `auto` is True, all the relations using this entity type and having a known
- entity type on the other hand will automatically be added.
-
-* `drop_entity_type(etype, commit=True)`, removes an entity type and all the
- relations using it.
-
-* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
-
-* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
- type. If `addrdef` is True, all the relations definitions of this type will
- be added.
-
-* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
- definitions of this type.
-
-* `rename_relation(oldname, newname, commit=True)`, renames a relation.
-
-* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
- relation definition.
-
-* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
- a relation definition.
-
-* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
- synchronizes properties and/or permissions on:
- - the whole schema if ertype is None
- - an entity or relation type schema if ertype is a string
- - a relation definition if ertype is a 3-uple (subject, relation, object)
-
-* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
- properties of a relation definition by using the named parameters of the properties
- to change.
-
-* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
- relation <rtype> of entity type <etype>.
-
-* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
- for the relation <rtype> of entity type <etype>.
-
-Data migration
---------------
-The following functions for data migration are available in `repository` scripts:
-
-* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
- query, either to interrogate or update. A result set object is returned.
-
-* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given
- type. The attribute and relation values are specified using the named and
- positionned parameters.
-
-Workflow creation
------------------
-
-The following functions for workflow creation are available in `repository`
-scripts:
-
-* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
- for a given type(s)
-
-You can find more details about workflows in the chapter :ref:`Workflow` .
-
-Configuration migration
------------------------
-
-The following functions for configuration migration are available in all
-scripts:
-
-* `option_renamed(oldname, newname)`, indicates that an option has been renamed
-
-* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
- belong anymore to the same group.
-
-* `option_added(oldname, newname)`, indicates that an option has been added.
-
-* `option_removed(oldname, newname)`, indicates that an option has been deleted.
-
-
-Others migration functions
---------------------------
-Those functions are only used for low level operations that could not be
-accomplished otherwise or to repair damaged databases during interactive
-session. They are available in `repository` scripts:
-
-* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
-* `add_entity_type_table(etype, commit=True)`
-* `add_relation_type_table(rtype, commit=True)`
-* `uninline_relation(rtype, commit=True)`
-
-
-[FIXME] Add explanation on how to use cubicweb-ctl shell
--- a/doc/book/en/development/profiling.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-Profiling and performance
-=========================
-
-If you feel that one of your pages takes more time than it should to be
-generated, chances are that you're making too many RQL queries. Obviously,
-there are other reasons but experience tends to show this is the first thing to
-track down. Luckily, CubicWeb provides a configuration option to log RQL
-queries. In your ``all-in-one.conf`` file, set the **query-log-file** option::
-
- # web application query log file
- query-log-file=~/myapp-rql.log
-
-Then restart your application, reload your page and stop your application.
-The file ``myapp-rql.log`` now contains the list of RQL queries that were
-executed during your test. It's a simple text file containing lines such as::
-
- Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec)
- Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec)
-
-The structure of each line is::
-
- <RQL QUERY> <QUERY ARGS IF ANY> -- <TIME SPENT>
-
-CubicWeb also provides the **exlog** command to examine and summarize data found
-in such a file:
-
-.. sourcecode:: sh
-
- $ cubicweb-ctl exlog < ~/myapp-rql.log
- 0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
- 0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
- 0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
- 0.01 1 Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s {, }
- 0.01 1 Any B,T,P ORDERBY lower(T) WHERE B is Bookmark,B title T, B path P, B bookmarked_by U, U eid %(x)s {}
- 0.01 1 Any A,B,C,D WHERE A eid %(x)s,A name B,A creation_date C,A modification_date D {}
-
-This command sorts and uniquifies queries so that it's easy to see where
-is the hot spot that needs optimization.
-
-Do not neglect to set the **fetch_attrs** attribute you can define in your
-entity classes because it can greatly reduce the number of queries executed (see
-:ref:`FetchAttrs`).
-
-You should also know about the **profile** option in the ``all-in-on.conf``. If
-set, this option will make your application run in an `hotshot`_ session and
-store the results in the specified file.
-
-.. _hotshot: http://docs.python.org/library/hotshot.html#module-hotshot
-
-Last but no least, if you're using the PostgreSQL database backend, VACUUMing
-your database can significantly improve the performance of the queries (by
-updating the statistics used by the query optimizer). Nowadays, this is done
-automatically from time to time, but if you've just imported a large amount of
-data in your db, you will want to vacuum it (with the analyse option on). Read
-the documentation of your database for more information.
--- a/doc/book/en/development/testing.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tests
-=====
-
-Unit tests
-----------
-
-The *CubicWeb* framework provides the `CubicWebTC` test base class in
-the module `cubicweb.devtools.testlib`.
-
-Tests shall be put into the mycube/test directory. Additional test
-data shall go into mycube/test/data.
-
-It is much advised to write tests concerning entities methods, hooks
-and operations, security. The CubicWebTC base class has convenience
-methods to help test all of this.
-
-.. note::
-
- In the realm of views, there is not much to do but check that the
- views are valid XHTML. See :ref:`automatic_views_tests` for
- details. Integration of CubicWeb tests with UI testing tools such as
- `selenium`_ are currently under invesitgation.
-
-.. _selenium: http://seleniumhq.org/projects/ide/
-
-Most unit tests need a live database to work against. This is achieved
-by CubicWeb using automatically sqlite (bundled with Python, see
-http://docs.python.org/library/sqlite3.html) as a backend.
-
-The database is stored in the mycube/test/tmpdb,
-mycube/test/tmpdb-template files. If it does not (yet) exists, it will
-be built automatically when the test suit starts.
-
-.. warning::
-
- Whenever the schema changes (new entities, attributes, relations)
- one must delete these two files. Changes concerned only with entity
- or relation type properties (constraints, cardinalities,
- permissions) and generally dealt with using the
- `sync_schema_props_perms()` fonction of the migration environment
- need not a database regeneration step.
-
-Unit test by example
-````````````````````
-
-We start with an example extracted from the keyword cube (available
-from http://www.cubicweb.org/project/cubicweb-keyword).
-
-.. sourcecode:: python
-
- from cubicweb.devtools.testlib import CubicWebTC
- from cubicweb import ValidationError
-
- class ClassificationHooksTC(CubicWebTC):
-
- def setup_database(self):
- req = self.request()
- group_etype = req.execute('Any X WHERE X name "CWGroup"').get_entity(0,0)
- c1 = req.create_entity('Classification', name=u'classif1',
- classifies=group_etype)
- user_etype = req.execute('Any X WHERE X name "CWUser"').get_entity(0,0)
- c2 = req.create_entity('Classification', name=u'classif2',
- classifies=user_etype)
- self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1)
- self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2)
-
- def test_cannot_create_cycles(self):
- # direct obvious cycle
- self.assertRaises(ValidationError, self.kw1.set_relations,
- subkeyword_of=self.kw1)
- # testing indirect cycles
- kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
- 'SK subkeyword_of K WHERE C name "classif1", K eid %s'
- % self.kw1.eid).get_entity(0,0)
- self.kw1.set_relations(subkeyword_of=kw3)
- self.assertRaises(ValidationError, self.commit)
-
-The test class defines a `setup_database` method which populates the
-database with initial data. Each test of the class runs with this
-pre-populated database.
-
-The test case itself checks that an Operation does it job of
-preventing cycles amongst Keyword entities.
-
-You can see an example of security tests in the
-:ref:`adv_tuto_security`.
-
-It is possible to have these tests run continuously using `apycot`_.
-
-.. _apycot: http://www.logilab.org/project/apycot
-
-Managing connections or users
-+++++++++++++++++++++++++++++
-
-Since unit tests are done with the SQLITE backend and this does not
-support multiple connections at a time, you must be careful when
-simulating security, changing users.
-
-By default, tests run with a user with admin privileges. This
-user/connection must never be closed.
-
-Before a self.login, one has to release the connection pool in use
-with a self.commit, self.rollback or self.close.
-
-The `login` method returns a connection object that can be used as a
-context manager:
-
-.. sourcecode:: python
-
- with self.login('user1') as user:
- req = user.req
- req.execute(...)
-
-On exit of the context manager, either a commit or rollback is issued,
-which releases the connection.
-
-When one is logged in as a normal user and wants to switch back to the
-admin user without committing, one has to use
-self.restore_connection().
-
-Usage with restore_connection:
-
-.. sourcecode:: python
-
- # execute using default admin connection
- self.execute(...)
- # I want to login with another user, ensure to free admin connection pool
- # (could have used rollback but not close here
- # we should never close defaut admin connection)
- self.commit()
- cnx = self.login('user')
- # execute using user connection
- self.execute(...)
- # I want to login with another user or with admin user
- self.commit(); cnx.close()
- # restore admin connection, never use cnx = self.login('admin'), it will return
- # the default admin connection and one may be tempted to close it
- self.restore_connection()
-
-.. warning::
-
- Do not use the references kept to the entities created with a
- connection from another !
-
-Email notifications tests
--------------------------
-
-When running tests potentially generated e-mails are not really sent
-but is found in the list `MAILBOX` of module
-`cubicweb.devtools.testlib`.
-
-You can test your notifications by analyzing the contents of this list, which
-contains objects with two attributes:
-
-* `recipients`, the list of recipients
-* `msg`, object email.Message
-
-Let us look at simple example from the ``blog`` cube.
-
-.. sourcecode:: python
-
- from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
-
- class BlogTestsCubicWebTC(CubicWebTC):
- """test blog specific behaviours"""
-
- def test_notifications(self):
- req = self.request()
- cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
- description=u'cubicweb is beautiful')
- blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
- content=u'cubicweb hop')
- blog_entry_1.set_relations(entry_of=cubicweb_blog)
- blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
- content=u'cubicweb yes')
- blog_entry_2.set_relations(entry_of=cubicweb_blog)
- self.assertEquals(len(MAILBOX), 0)
- self.commit()
- self.assertEquals(len(MAILBOX), 2)
- mail = MAILBOX[0]
- self.assertEquals(mail.subject, '[data] hop')
- mail = MAILBOX[1]
- self.assertEquals(mail.subject, '[data] yes')
-
-.. _automatic_views_tests:
-
-Automatic views testing
------------------------
-
-This is done automatically with the AutomaticWebTest class. At cube
-creation time, the mycube/test/test_mycube.py file contains such a
-test. The code here has to be uncommented to be usable, without
-further modification.
-
-The ``auto_populate`` method uses a smart algorithm to create
-pseudo-random data in the database, thus enabling the views to be
-invoked and tested.
-
-Depending on the schema, hooks and operations constraints, it is not
-always possible for the automatic auto_populate to proceed.
-
-It is possible of course to completely redefine auto_populate. A
-lighter solution is to give hints (fill some class attributes) about
-what entities and relations have to be skipped by the auto_populate
-mechanism. These are:
-
-* `no_auto_populate`, may contain a list of entity types to skip
-* `ignored_relations`, may contain a list of relation types to skip
-* `application_rql`, may contain a list of rql expressions that
- auto_populate cannot guess by itself; these must yield resultsets
- against which views may be selected.
-
-
-Test APIS
----------
-
-Using Pytest
-````````````
-
-The `pytest` utility (shipping with `logilab-common`_, which is a
-mandatory dependency of CubicWeb) extends the Python unittest
-functionality and is the preferred way to run the CubicWeb test
-suites. Bare unittests also work the usual way.
-
-.. _logilab-common: http://www.logilab.org/project/logilab-common
-
-To use it, you may:
-
-* just launch `pytest` in your cube to execute all tests (it will
- discover them automatically)
-* launch `pytest unittest_foo.py` to execute one test file
-* launch `pytest unittest_foo.py bar` to execute all test methods and
- all test cases whose name contain `bar`
-
-Additionally, the `-x` option tells pytest to exit at the first error
-or failure. The `-i` option tells pytest to drop into pdb whenever an
-exception occurs in a test.
-
-When the `-x` option has been used and the run stopped on a test, it
-is possible, after having fixed the test, to relaunch pytest with the
-`-R` option to tell it to start testing again from where it previously
-failed.
-
-Using the `TestCase` base class
-```````````````````````````````
-
-The base class of CubicWebTC is logilab.common.testlib.TestCase, which
-provides a lot of convenient assertion methods.
-
-.. autoclass:: logilab.common.testlib.TestCase
- :members:
-
-CubicWebTC API
-``````````````
-.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
- :members:
--- a/doc/book/en/development/vreg.rst Fri Apr 23 13:36:43 2010 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,107 +0,0 @@
-The VRegistry, selectors and application objects
-================================================
-
-This chapter talks about core concepts of the |cubicweb| framework,
-that make it different from other frameworks (and maybe not easy to
-grasp at a first glance). To be able to do advanced development with
-|cubicweb| you need a good understanding of what is explained below.
-
-This chapter goes deep into details. You don't have to remember them
-all but keep it in mind so you can go back there later.
-
-An overview of AppObjects, the VRegistry and Selectors is given in the
-:ref:`VRegistryIntro` chapter.
-
-.. autodocstring:: cubicweb.cwvreg
-.. autodocstring:: cubicweb.selectors
-.. automodule:: cubicweb.appobject
-
-Base selectors
---------------
-
-Selectors are scoring functions that are called by the registry to tell whenever
-an appobject can be selected in a given context. Selector sets are for instance
-the glue that tie views to the data model. Using them appropriately is an
-essential part of the construction of well behaved cubes.
-
-Of course you may have to write your own set of selectors as your needs grows and
-you get familiar with the framework (see :ref:`CustomSelectors`).
-
-Here is a description of generic selectors provided by CubicWeb that should suit
-most of your needs.
-
-Bare selectors
-~~~~~~~~~~~~~~
-Those selectors are somewhat dumb, which doesn't mean they're not (very) useful.
-
-.. autoclass:: cubicweb.appobject.yes
-.. autoclass:: cubicweb.selectors.match_kwargs
-.. autoclass:: cubicweb.selectors.appobject_selectable
-
-
-Result set selectors
-~~~~~~~~~~~~~~~~~~~~~
-Those selectors are looking for a result set in the context ('rset' argument or
-the input context) and match or not according to its shape. Some of these
-selectors have different behaviour if a particular cell of the result set is
-specified using 'row' and 'col' arguments of the input context or not.
-
-.. autoclass:: cubicweb.selectors.none_rset
-.. autoclass:: cubicweb.selectors.any_rset
-.. autoclass:: cubicweb.selectors.nonempty_rset
-.. autoclass:: cubicweb.selectors.empty_rset
-.. autoclass:: cubicweb.selectors.one_line_rset
-.. autoclass:: cubicweb.selectors.multi_lines_rset
-.. autoclass:: cubicweb.selectors.multi_columns_rset
-.. autoclass:: cubicweb.selectors.paginated_rset
-.. autoclass:: cubicweb.selectors.sorted_rset
-.. autoclass:: cubicweb.selectors.one_etype_rset
-.. autoclass:: cubicweb.selectors.multi_etypes_rset
-
-
-Entity selectors
-~~~~~~~~~~~~~~~~
-Those selectors are looking for either an `entity` argument in the input context,
-or entity found in the result set ('rset' argument or the input context) and
-match or not according to entity's (instance or class) properties.
-
-.. autoclass:: cubicweb.selectors.non_final_entity
-.. autoclass:: cubicweb.selectors.implements
-.. autoclass:: cubicweb.selectors.score_entity
-.. autoclass:: cubicweb.selectors.rql_condition
-.. autoclass:: cubicweb.selectors.relation_possible
-.. autoclass:: cubicweb.selectors.partial_relation_possible
-.. autoclass:: cubicweb.selectors.has_related_entities
-.. autoclass:: cubicweb.selectors.partial_has_related_entities
-.. autoclass:: cubicweb.selectors.has_permission
-.. autoclass:: cubicweb.selectors.has_add_permission
-
-
-Logged user selectors
-~~~~~~~~~~~~~~~~~~~~~
-Those selectors are looking for properties of the user issuing the request.
-
-.. autoclass:: cubicweb.selectors.anonymous_user
-.. autoclass:: cubicweb.selectors.authenticated_user
-.. autoclass:: cubicweb.selectors.match_user_groups
-
-
-Web request selectors
-~~~~~~~~~~~~~~~~~~~~~
-Those selectors are looking for properties of *web* request, they can not be
-used on the data repository side.
-
-.. autoclass:: cubicweb.selectors.match_form_params
-.. autoclass:: cubicweb.selectors.match_search_state
-.. autoclass:: cubicweb.selectors.match_context_prop
-.. autoclass:: cubicweb.selectors.match_view
-.. autoclass:: cubicweb.selectors.primary_view
-.. autoclass:: cubicweb.selectors.specified_etype_implements
-
-
-Other selectors
-~~~~~~~~~~~~~~~
-.. autoclass:: cubicweb.selectors.match_transition
-
-You'll also find some other (very) specific selectors hidden in other modules
-than :mod:`cubicweb.selectors`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/available-cubes.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,64 @@
+
+Available cubes
+---------------
+
+An instance is based on several basic cubes. In the set of available
+basic cubes we can find for example :
+
+Base entity types
+~~~~~~~~~~~~~~~~~
+* addressbook_: PhoneNumber and PostalAddress
+* card_: Card, generic documenting card
+* event_: Event (define events, display them in calendars)
+* file_: File (to allow users to upload and store binary or text files)
+* link_: Link (to collect links to web resources)
+* mailinglist_: MailingList (to reference a mailing-list and the URLs
+ for its archives and its admin interface)
+* person_: Person (easily mixed with addressbook)
+* task_: Task (something to be done between start and stop date)
+* zone_: Zone (to define places within larger places, for example a
+ city in a state in a country)
+
+
+Classification
+~~~~~~~~~~~~~~
+* folder_: Folder (to organize things but grouping them in folders)
+* keyword_: Keyword (to define classification schemes)
+* tag_: Tag (to tag anything)
+
+Other features
+~~~~~~~~~~~~~~
+* basket_: Basket (like a shopping cart)
+* blog_: a blogging system uxing Blog and BlogEntry entity types
+* comment_: system to attach comment threads to entities)
+* email_: archiving management for emails (`Email`, `Emailpart`,
+ `Emailthread`), trigger action in cubicweb through email
+
+
+
+
+
+.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
+.. _basket: http://www.cubicweb.org/project/cubicweb-basket
+.. _card: http://www.cubicweb.org/project/cubicweb-card
+.. _blog: http://www.cubicweb.org/project/cubicweb-blog
+.. _comment: http://www.cubicweb.org/project/cubicweb-comment
+.. _email: http://www.cubicweb.org/project/cubicweb-email
+.. _event: http://www.cubicweb.org/project/cubicweb-event
+.. _file: http://www.cubicweb.org/project/cubicweb-file
+.. _folder: http://www.cubicweb.org/project/cubicweb-folder
+.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
+.. _link: http://www.cubicweb.org/project/cubicweb-link
+.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
+.. _person: http://www.cubicweb.org/project/cubicweb-person
+.. _tag: http://www.cubicweb.org/project/cubicweb-tag
+.. _task: http://www.cubicweb.org/project/cubicweb-task
+.. _zone: http://www.cubicweb.org/project/cubicweb-zone
+
+To declare the use of a component, once installed, add the name of the component
+to the variable `__use__` in the file `__pkginfo__.py` of your own component.
+
+.. note::
+ The listed cubes above are available as debian-packages on `CubicWeb's forge`_.
+
+.. _`CubicWeb's forge`: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/cc-newcube.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,50 @@
+Creating a new cube from scratch using :command:`cubicweb-ctl newcube`
+----------------------------------------------------------------------
+
+Let's start by creating the cube environment in which we will develop ::
+
+ cd ~/cubes
+ # use cubicweb-ctl to generate a template for the cube
+ # will ask some questions, most with nice default
+ cubicweb-ctl newcube mycube
+ # makes the cube source code managed by mercurial
+ cd mycube
+ hg init
+ hg add .
+ hg ci
+
+If all went well, you should see the cube you just created in the list
+returned by ``cubicweb-ctl list`` in the section *Available cubes*,
+and if it is not the case please refer to :ref:`ConfigurationEnv`.
+
+To reuse an existing cube, add it to the list named
+``__depends_cubes__`` and defined in :file:`__pkginfo__.py`. This
+variable is used for the instance packaging (dependencies handled by
+system utility tools such as APT) and the usable cubes at the time the
+base is created (import_erschema('MyCube') will not properly work
+otherwise).
+
+.. note::
+
+ Please note that if you do not wish to use default directory for your cubes
+ library, you should set the :envvar:`CW_CUBES_PATH` environment variable to
+ add extra directories where cubes will be search, and you'll then have to use
+ the option `--directory` to specify where you would like to place the source
+ code of your cube:
+
+ ``cubicweb-ctl newcube --directory=/path/to/cubes/library mycube``
+
+
+.. XXX resurrect once live-server is back
+.. Usage of :command:`cubicweb-ctl liveserver`
+.. -------------------------------------------
+
+.. To quickly test a new cube, you can also use the `liveserver` command for cubicweb-ctl
+.. which allows to create an instance in memory (using an SQLite database by
+.. default) and make it accessible through a web server ::
+
+.. cubicweb-ctl live-server mycube
+
+.. or by using an existing database (SQLite or Postgres)::
+
+.. cubicweb-ctl live-server -s myfile_sources mycube
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,11 @@
+Cubes
+=====
+
+This chapter describes how to define your own cubes and reuse already available cubes.
+
+.. toctree::
+ :maxdepth: 1
+
+ layout.rst
+ cc-newcube.rst
+ available-cubes.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/cubes/layout.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,134 @@
+
+.. _foundationsCube:
+
+.. _cubelayout:
+
+Standard structure for a cube
+-----------------------------
+
+A cube is structured as follows:
+
+::
+
+ mycube/
+ |
+ |-- data/
+ | |-- cubes.mycube.css
+ | |-- cubes.mycube.js
+ | `-- external_resources
+ |
+ |-- debian/
+ | |-- changelog
+ | |-- compat
+ | |-- control
+ | |-- copyright
+ | |-- cubicweb-mycube.prerm
+ | `-- rules
+ |
+ |-- entities.py
+ |
+ |-- i18n/
+ | |-- en.po
+ | |-- es.po
+ | `-- fr.po
+ |
+ |-- __init__.py
+ |
+ |-- MANIFEST.in
+ |
+ |-- migration/
+ | |-- postcreate.py
+ | `-- precreate.py
+ |
+ |-- __pkginfo__.py
+ |
+ |-- schema.py
+ |
+ |-- setup.py
+ |
+ |-- site_cubicweb.py
+ |
+ |-- hooks.py
+ |
+ |-- test/
+ | |-- data/
+ | | `-- bootstrap_cubes
+ | |-- pytestconf.py
+ | |-- realdb_test_mycube.py
+ | `-- test_mycube.py
+ |
+ `-- views.py
+
+
+We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
+``schema.py`` or ``hooks.py``. For example, we could have:
+
+::
+
+ mycube/
+ |
+ |-- entities.py
+ |-- hooks.py
+ `-- views/
+ |-- forms.py
+ |-- primary.py
+ `-- widgets.py
+
+
+where :
+
+* ``schema`` contains the schema definition (server side only)
+* ``entities`` contains the entities definition (server side and web interface)
+* ``hooks`` contains hooks and/or views notifications (server side only)
+* ``views`` contains the web interface components (web interface only)
+* ``test`` contains tests related to the cube (not installed)
+* ``i18n`` contains message catalogs for supported languages (server side and
+ web interface)
+* ``data`` contains data files for static content (images, css, javascripts)
+ ...(web interface only)
+* ``migration`` contains initialization files for new instances (``postcreate.py``)
+ and a file containing dependencies of the component depending on the version
+ (``depends.map``)
+* ``debian`` contains all the files managing debian packaging (you will find
+ the usual files ``control``, ``rules``, ``changelog``... not installed)
+* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
+ and the current version (server side and web interface) or sub-cubes used by
+ the cube.
+
+
+At least you should have the file ``__pkginfo__.py``.
+
+
+The :file:`__init__.py` and :file:`site_cubicweb.py` files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :file:`__pkginfo__.py` file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It contains metadata describing your cubes, mostly useful for
+packaging.
+
+
+:file:`migration/precreate.py` and :file:`migration/postcreate.py`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX detail steps of instance creation
+
+
+External resources such as image, javascript and css files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX naming convention external_resources file
+
+
+Out-of the box testing
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
+
+
+Packaging and distribution
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/baseschema.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,43 @@
+.. _pre_defined_entity_types:
+
+Pre-defined entities in the library
+-----------------------------------
+
+The library defines a set of entity schemas that are required by the system
+or commonly used in *CubicWeb* instances.
+
+
+Entity types used to store the schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`CWEType`, entity type
+* _`CWRType`, relation type
+* _`CWRelation`, relation definition
+* _`CWAttribute`, attribute relation definition
+* _`CWConstraint`, `CWConstraintType`, `RQLExpression`
+
+Entity types used to manage users and permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`CWUser`, system users
+* _`CWGroup`, users groups
+* _`CWPermission`, used to configure the security of the instance
+
+Entity types used to manage workflows
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`Workflow`, workflow entity, linked to some entity types which may use this workflow
+* _`State`, workflow state
+* _`Transition`, workflow transition
+* _`TrInfo`, record of a transition trafic for an entity
+
+Other entity types
+~~~~~~~~~~~~~~~~~~
+* _`CWCache`, cache entities used to improve performances
+* _`CWProperty`, used to configure the instance
+
+* _`EmailAddress`, email address, used by the system to send notifications
+ to the users and also used by others optionnals schemas
+
+* _`Bookmark`, an entity type used to allow a user to customize his links within
+ the instance
+
+* _`ExternalUri`, used for semantic web site to indicate that an entity is the
+ same as another from an external site
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/define-workflows.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,161 @@
+.. -*- coding: utf-8 -*-
+
+.. _Workflow:
+
+Defining a Workflow
+===================
+
+General
+-------
+
+A workflow describes how certain entities have to evolve between
+different states. Hence we have a set of states, and a "transition
+graph", i.e. a set of possible transitions from one state to another
+state.
+
+We will define a simple workflow for a blog, with only the following
+two states: `submitted` and `published`. So first, we create a simple
+|cubicweb| instance in five minutes (see :ref:`BlogFiveMinutes`).
+
+Setting up a workflow
+---------------------
+
+We want to create a workflow to control the quality of the BlogEntry
+submitted on the instance. When a BlogEntry is created by a user
+its state should be `submitted`. To be visible to all, it has to
+be in the state `published`. To move it from `submitted` to `published`,
+we need a transition that we can call `approve_blogentry`.
+
+A BlogEntry state should not be modifiable by every user.
+So we have to define a group of users, `moderators`, and
+this group will have appropriate permissions to publish a BlogEntry.
+
+There are two ways to create a workflow: from the user interface, or
+by defining it in ``migration/postcreate.py``. This script is executed
+each time a new ``cubicweb-ctl db-init`` is done. We strongly
+recommend to create the workflow in ``migration/postcreate.py`` and we
+will now show you how. Read `Two bits of warning`_ to understand why.
+
+The state of an entity is managed by the `in_state` attribute which
+can be added to your entity schema by inheriting from
+`cubicweb.schema.WorkflowableEntityType`.
+
+
+About our example of BlogEntry, we must have:
+
+.. sourcecode:: python
+
+ from cubicweb.schema import WorkflowableEntityType
+
+ class BlogEntry(WorkflowableEntityType):
+ ...
+
+
+Creating states, transitions and group permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :mod:`postcreate` script is executed in a special environment,
+adding several |cubicweb| primitives that can be used.
+
+They are all defined in the :class:`ServerMigrationHelper` class.
+We will only discuss the methods we use to create a workflow in this example.
+
+A workflow is a collection of entities of type ``State`` and of type
+``Transition`` which are standard *CubicWeb* entity types.
+
+To define a workflow for BlogDemo, please add the following lines
+to ``migration/postcreate.py``:
+
+.. sourcecode:: python
+
+ _ = unicode
+
+ moderators = add_entity('CWGroup', name=u"moderators")
+
+This adds the `moderators` user group.
+
+.. sourcecode:: python
+
+ wf = add_workflow(u'blog publication workflow', 'BlogEntry')
+
+At first, instanciate a new workflow object with a gentle description
+and the concerned entity types (this one can be a tuple for multiple
+value).
+
+.. sourcecode:: python
+
+ submitted = wf.add_state(_('submitted'), initial=True)
+ published = wf.add_state(_('published'))
+
+This will create two entities of type ``State``, one with name
+'submitted', and the other with name 'published'.
+
+``add_state`` expects as first argument the name of the state you want
+to create and an optional argument to say if it is supposed to be the
+initial state of the entity type.
+
+.. sourcecode:: python
+
+ wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
+
+This will create an entity of type ``Transition`` with name
+`approve_blogentry` which will be linked to the ``State`` entities
+created before.
+
+``add_transition`` expects
+
+ * as the first argument: the name of the transition
+ * then the list of states on which the transition can be triggered,
+ * the target state of the transition,
+ * and the permissions
+ (e.g. a list of user groups who can apply the transition; the user
+ has to belong to at least one of the listed group to perform the action).
+
+.. sourcecode:: python
+
+ checkpoint()
+
+.. note::
+ Do not forget to add the `_()` in front of all states and
+ transitions names while creating a workflow so that they will be
+ identified by the i18n catalog scripts.
+
+In addition to the user groups (one of which the user needs to belong
+to), we could have added a RQL condition. In this case, the user can
+only perform the action if the two conditions are satisfied.
+
+If we use an RQL condition on a transition, we can use the following variables:
+
+* `X`, the entity on which we may pass the transition
+* `U`, the user executing that may pass the transition
+
+
+.. image:: ../../images/03-transitions-view_en.png
+
+You can notice that in the action box of a BlogEntry, the state is now
+listed as well as the possible transitions for the current state
+defined by the workflow.
+
+The transitions will only be displayed for users having the right permissions.
+In our example, the transition `approve_blogentry` will only be displayed
+for the users belonging to the group `moderators` or `managers`.
+
+
+Two bits of warning
+~~~~~~~~~~~~~~~~~~~
+
+We could perfectly use the administration interface to do these
+operations. It is a convenient thing to do at times (when doing
+development, to quick-check things). But it is not recommended beyond
+that because it is a bit complicated to do it right and it will be
+only local to your instance (or, said a bit differently, such a
+workflow only exists in an instance database). Furthermore, you cannot
+write unit tests against deployed instances, and experience shows it
+is mandatory to have tests for any mildly complicated workflow
+setup.
+
+Indeed, if you create the states and transitions through the user
+interface, next time you initialize the database you will have to
+re-create all the workflow entities. The user interface should only be
+a reference for you to view the states and transitions, but is not the
+appropriate interface to define your application workflow.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/definition.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,631 @@
+ .. -*- coding: utf-8 -*-
+
+Yams *schema*
+-------------
+
+The **schema** is the core piece of a *CubicWeb* instance as it
+defines and handles the data model. It is based on entity types that
+are either already defined in `Yams`_ and the *CubicWeb* standard
+library; or more specific types defined in cubes. The schema for a
+cube is defined in a `schema` python module or package.
+
+.. _`Yams`: http://www.logilab.org/project/yams
+
+Overview
+~~~~~~~~
+
+The core idea of the yams schema is not far from the classical
+`Entity-relationship`_ model. But while an E/R model (or `logical
+model`) traditionally has to be manually translated to a lower-level
+data description language (such as the SQL `create table`
+sublanguage), also often described as the `physical model`, no such
+step is required with |yams| and |cubicweb|.
+
+.. _`Entity-relationship`: http://en.wikipedia.org/wiki/Entity-relationship_model
+
+This is because in addition to high-level, logical |yams| models, one
+uses the |rql| data manipulation language to query, insert, update and
+delete data. |rql| abstracts as much of the underlying SQL database as
+a |yams| schema abstracts from the physical layout. The vagaries of
+SQL are avoided.
+
+As a bonus point, such abstraction make it quite comfortable to build
+or use different backends to which |rql| queries apply.
+
+So, as in the E/R formalism, the building blocks are ``entities``
+(:ref:`EntityType`), ``relationships`` (:ref:`RelationType`,
+:ref:`RelationDefinition`) and ``attributes`` (handled like relation
+with |yams|).
+
+Let us detail a little the divergences between E/R and |yams|:
+
+* all relationship are binary which means that to represent a
+ non-binary relationship, one has to use an entity,
+* relationships do not support attributes (yet, see:
+ http://www.cubicweb.org/ticket/341318), hence the need to reify it
+ as an entity if need arises,
+* all entities have an `eid` attribute (an integer) that is its
+ primary key (but it is possible to declare uniqueness on other
+ attributes)
+
+Also |yams| supports the notions of:
+
+* entity inheritance (quite experimental yet, and completely
+ undocumented),
+* relation type: that is, relationships can be established over a set
+ of couple of entity types (henre the distinction made between
+ `RelationType` and `RelationDefinition` below)
+
+Finally |yams| has a few concepts of its own:
+
+* relationships being oriented and binary, we call the left hand
+ entity type the `subject` and the right hand entity type the
+ `object`
+
+.. note::
+
+ The |yams| schema is available at run time through the .schema
+ attribute of the `vregistry`. It's an instance of
+ :class:`cubicweb.schema.Schema`, which extends
+ :class:`yams.schema.Schema`.
+
+.. _EntityType:
+
+Entity type
+~~~~~~~~~~~
+
+An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
+a set of attributes and relations, and some permissions which define who can add, read,
+update or delete entities of this type.
+
+The following built-in types are available: ``String``, ``Int``,
+``Float``, ``Decimal``, ``Boolean``, ``Date``, ``Datetime``, ``Time``,
+``Interval``, ``Byte`` and ``Password``. They can only be used as
+attributes of an other entity type.
+
+You can find more base entity types in
+:ref:`pre_defined_entity_types`.
+
+.. XXX yams inheritance
+
+.. _RelationType:
+
+Relation type
+~~~~~~~~~~~~~
+
+A relation type is an instance of
+:class:`yams.schema.RelationSchema`. A relation type is simply a
+semantic definition of a kind of relationship that may occur in an
+application.
+
+It may be referenced by zero, one or more relation definitions.
+
+It is important to choose a good name, at least to avoid conflicts
+with some semantically different relation defined in other cubes
+(since there's only a shared name space for these names).
+
+A relation type holds the following properties (which are hence shared
+between all relation definitions of that type):
+
+* `inlined`: boolean handling the physical optimization for archiving
+ the relation in the subject entity table, instead of creating a specific
+ table for the relation. This applies to relations where cardinality
+ of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
+ definitions.
+
+* `symmetric`: boolean indicating that the relation is symmetrical, which
+ means that `X relation Y` implies `Y relation X`.
+
+.. _RelationDefinition:
+
+Relation definition
+~~~~~~~~~~~~~~~~~~~
+
+A relation definition is an instance of
+:class:`yams.schema.RelationDefinition`. It is a complete triplet
+"<subject entity type> <relation type> <object entity type>".
+
+When creating a new instance of that class, the corresponding
+:class:`RelationType` instance is created on the fly if necessary.
+
+Properties
+``````````
+
+The available properties for relation definitions are enumerated
+here. There are several kind of properties, as some relation
+definitions are actually attribute definitions, and other are not.
+
+Some properties may be completely optional, other may have a default
+value.
+
+Common properties for attributes and relations:
+
+* `description`: an unicode string describing an attribute or a
+ relation. By default this string will be used in the editing form of
+ the entity, which means that it is supposed to help the end-user and
+ should be flagged by the function `_` to be properly
+ internationalized.
+
+* `constraints`: a list of conditions/constraints that the relation has to
+ satisfy (c.f. `Constraints`_)
+
+* `cardinality`: a two character string specifying the cardinality of
+ the relation. The first character defines the cardinality of the
+ relation on the subject, and the second on the object. When a
+ relation can have multiple subjects or objects, the cardinality
+ applies to all, not on a one-to-one basis (so it must be
+ consistent...). Default value is '**'. The possible values are
+ inspired from regular expression syntax:
+
+ * `1`: 1..1
+ * `?`: 0..1
+ * `+`: 1..n
+ * `*`: 0..n
+
+Attributes properties:
+
+* `unique`: boolean indicating if the value of the attribute has to be
+ unique or not within all entities of the same type (false by
+ default)
+
+* `indexed`: boolean indicating if an index needs to be created for
+ this attribute in the database (false by default). This is useful
+ only if you know that you will have to run numerous searches on the
+ value of this attribute.
+
+* `default`: default value of the attribute. In case of date types, the values
+ which could be used correspond to the RQL keywords `TODAY` and `NOW`.
+
+Properties for `String` attributes:
+
+* `fulltextindexed`: boolean indicating if the attribute is part of
+ the full text index (false by default) (*applicable on the type
+ `Byte` as well*)
+
+* `internationalizable`: boolean indicating if the value of the
+ attribute is internationalizable (false by default)
+
+Relation properties:
+
+* `composite`: string indicating that the subject (composite ==
+ 'subject') is composed of the objects of the relations. For the
+ opposite case (when the object is composed of the subjects of the
+ relation), we just set 'object' as value. The composition implies
+ that when the relation is deleted (so when the composite is deleted,
+ at least), the composed are also deleted.
+
+* `fulltext_container`: string indicating if the value if the full
+ text indexation of the entity on one end of the relation should be
+ used to find the entity on the other end. The possible values are
+ 'subject' or 'object'. For instance the use_email relation has that
+ property set to 'subject', since when performing a full text search
+ people want to find the entity using an email address, and not the
+ entity representing the email address.
+
+Constraints
+```````````
+
+By default, the available constraint types are:
+
+General Constraints
+......................
+
+* `SizeConstraint`: allows to specify a minimum and/or maximum size on
+ string (generic case of `maxsize`)
+
+* `BoundConstraint`: allows to specify a minimum and/or maximum value
+ on numeric types and date
+
+.. sourcecode:: python
+
+ from yams.constraints import BoundConstraint, TODAY
+ BoundConstraint('<=', TODAY())
+
+* `IntervalBoundConstraint`: allows to specify an interval with
+ included values
+
+.. sourcecode:: python
+
+ class Node(EntityType):
+ latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
+
+* `UniqueConstraint`: identical to "unique=True"
+
+* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
+
+.. XXX Attribute, NOW
+
+RQL Based Constraints
+......................
+
+RQL based constraints may take three arguments. The first one is the ``WHERE``
+clause of a RQL query used by the constraint. The second argument ``mainvars``
+is the ``Any`` clause of the query. By default this include `S` reserved for the
+subject of the relation and `O` for the object. Additional variables could be
+specified using ``mainvars``. The argument expects a single string with all
+variable's name separated by spaces. The last one, ``msg``, is the error message
+displayed when the constraint fails. As RQLVocabularyConstraint never fails the
+third argument is not available.
+
+* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
+ by the subject and/or the object of relation. In this query the variables
+ `S` and `O` are reserved for the relation subject and object entities.
+
+* `RQLVocabularyConstraint`: similar to the previous type of constraint except
+ that it does not express a "strong" constraint, which means it is only used to
+ restrict the values listed in the drop-down menu of editing form, but it does
+ not prevent another entity to be selected.
+
+* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
+ attribute is unique in a specific context. The Query must **never** return more
+ than a single result to be satisfied. In this query the variables `S` is
+ reserved for the relation subject entity. The other variables should be
+ specified with the second constructor argument (mainvars). This constraints
+ should be used when UniqueConstraint doesn't fit. Here is a simple example.
+
+.. sourcecode:: python
+
+ # Check that in the same Workflow each state's name is unique. Using
+ # UniqueConstraint (or unique=True) here would prevent states in different
+ # workflows to have the same name.
+
+ # With: State S, Workflow W, String N ; S state_of W, S name N
+
+ RQLUniqueConstraint('S name N, S state_of WF, Y state_of WF, Y name N',
+ mainvars='Y',
+ msg=_('workflow already has a state of that name'))
+
+.. XXX note about how to add new constraint
+
+.. _securitymodel:
+
+The security model
+~~~~~~~~~~~~~~~~~~
+
+The security model of `CubicWeb` is based on `Access Control List`.
+The main principles are:
+
+* users and groups of users
+* a user belongs to at least one group of user
+* permissions (read, update, create, delete)
+* permissions are assigned to groups (and not to users)
+
+For *CubicWeb* in particular:
+
+* we associate rights at the entities/relations schema level
+* for each entity, we distinguish four kinds of permissions: `read`,
+ `add`, `update` and `delete`
+* for each relation, we distinguish three kinds of permissions: `read`,
+ `add` and `delete` (it is not possible to `modify` a relation)
+* the default groups are: `administrators`, `users` and `guests`
+* by default, users belong to the `users` group
+* there is a virtual group called `owners` to which we
+ can associate only `delete` and `update` permissions
+
+ * we can not add users to the `Owners` group, they are
+ implicitly added to it according to the context of the objects
+ they own
+ * the permissions of this group are only checked on `update`/`delete`
+ actions if all the other groups the user belongs to do not provide
+ those permissions
+
+Setting permissions is done with the attribute `__permissions__` of entities and
+relation types. The value of this attribute is a dictionary where the keys are the access types
+(action), and the values are the authorized groups or expressions.
+
+For an entity type, the possible actions are `read`, `add`, `update` and
+`delete`.
+
+For a relation type, the possible actions are `read`, `add`, and `delete`.
+
+For each access type, a tuple indicates the name of the authorized groups and/or
+one or multiple RQL expressions to satisfy to grant access. The access is
+provided if the user is in one of the listed groups or if one of the RQL condition
+is satisfied.
+
+The standard user groups
+````````````````````````
+
+* `guests`
+
+* `users`
+
+* `managers`
+
+* `owners`: virtual group corresponding to the entity's owner.
+ This can only be used for the actions `update` and `delete` of an entity
+ type.
+
+It is also possible to use specific groups if they are defined in the
+precreate script of the cube (``migration/precreate.py``). Defining groups in
+postcreate script or later makes them unavailable for security
+purposes (in this case, an `sync_schema_props_perms` command has to
+be issued in a CubicWeb shell).
+
+
+Use of RQL expression for write permissions
+```````````````````````````````````````````
+It is possible to define RQL expression to provide update permission
+(`add`, `delete` and `update`) on relation and entity types.
+
+RQL expression for entity type permission:
+
+* you have to use the class `ERQLExpression`
+
+* the used expression corresponds to the WHERE statement of an RQL query
+
+* in this expression, the variables `X` and `U` are pre-defined references
+ respectively on the current entity (on which the action is verified) and
+ on the user who send the request
+
+* it is possible to use, in this expression, a special relation
+ "has_<ACTION>_permission" where the subject is the user and the
+ object is any variable, meaning that the user needs to have
+ permission to execute the action <ACTION> on the entities related
+ to this variable
+
+For RQL expressions on a relation type, the principles are the same except
+for the following:
+
+* you have to use the class `RRQLExpression` in the case of a non-final relation
+
+* in the expression, the variables `S`, `O` and `U` are pre-defined references
+ to respectively the subject and the object of the current relation (on
+ which the action is being verified) and the user who executed the query
+
+* we can also define rights over attributes of an entity (non-final relation),
+ knowing that:
+
+ - to define RQL expression, we have to use the class `ERQLExpression`
+ in which `X` represents the entity the attribute belongs to
+
+ - the permissions `add` and `delete` are equivalent. Only `add`/`read`
+ are actually taken in consideration.
+
+.. note::
+
+ Potentially, the `use of an RQL expression to add an entity or a
+ relation` can cause problems for the user interface, because if the
+ expression uses the entity or the relation to create, then we are
+ not able to verify the permissions before we actually add the entity
+ (please note that this is not a problem for the RQL server at all,
+ because the permissions checks are done after the creation). In such
+ case, the permission check methods (CubicWebEntitySchema.check_perm
+ and has_perm) can indicate that the user is not allowed to create
+ this entity but can obtain the permission. To compensate this
+ problem, it is usually necessary, for such case, to use an action
+ that reflects the schema permissions but which enables to check
+ properly the permissions so that it would show up if necessary.
+
+
+Use of RQL expression for reading rights
+````````````````````````````````````````
+
+The principles are the same but with the following restrictions:
+
+* we can not use `RRQLExpression` on relation types for reading
+
+* special relations "has_<ACTION>_permission" can not be used
+
+
+
+
+Defining your schema using yams
+-------------------------------
+
+Entity type definition
+~~~~~~~~~~~~~~~~~~~~~~
+
+An entity type is defined by a Python class which inherits from
+:class:`yams.buildobjs.EntityType`. The class definition contains the
+description of attributes and relations for the defined entity type.
+The class name corresponds to the entity type name. It is expected to
+be defined in the module ``mycube.schema``.
+
+:Note on schema definition:
+
+ The code in ``mycube.schema`` is not meant to be executed. The class
+ EntityType mentioned above is different from the EntitySchema class
+ described in the previous chapter. EntityType is a helper class to
+ make Entity definition easier. Yams will process EntityType classes
+ and create EntitySchema instances from these class definitions. Similar
+ manipulation happen for relations.
+
+When defining a schema using python files, you may use the following shortcuts:
+
+- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
+
+- `vocabulary`: specify static possible values of an attribute
+
+- `maxsize`: integer providing the maximum size of a string (no limit by default)
+
+For example:
+
+.. sourcecode:: python
+
+ class Person(EntityType):
+ """A person with the properties and the relations necessary for my
+ application"""
+
+ last_name = String(required=True, fulltextindexed=True)
+ first_name = String(required=True, fulltextindexed=True)
+ title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
+ date_of_birth = Date()
+ works_for = SubjectRelation('Company', cardinality='?*')
+
+
+The entity described above defines three attributes of type String,
+last_name, first_name and title, an attribute of type Date for the date of
+birth and a relation that connects a `Person` to another entity of type
+`Company` through the semantic `works_for`.
+
+:Naming convention:
+
+ Entity class names must start with an uppercase letter. The common
+ usage is to use ``CamelCase`` names.
+
+ Attribute and relation names must start with a lowercase letter. The
+ common usage is to use ``underscore_separated_words``. Attribute and
+ relation names starting with a single underscore are permitted, to
+ denote a somewhat "protected" or "private" attribute.
+
+ In any case, identifiers starting with "CW" or "cw" are reserved for
+ internal use by the framework.
+
+
+The name of the Python attribute corresponds to the name of the attribute
+or the relation in *CubicWeb* application.
+
+An attribute is defined in the schema as follows::
+
+ attr_name = attr_type(properties)
+
+where `attr_type` is one of the type listed above and `properties` is
+a list of the attribute needs to satisfy (see `Properties`_
+for more details).
+
+* it is possible to use the attribute `meta` to flag an entity type as a `meta`
+ (e.g. used to describe/categorize other entities)
+
+.. XXX the paragraph below needs clarification and / or moving out in
+.. another place
+
+*Note*: if you end up with an `if` in the definition of your entity, this probably
+means that you need two separate entities that implement the `ITree` interface and
+get the result from `.children()` which ever entity is concerned.
+
+Inheritance
+```````````
+XXX feed me
+
+
+Definition of relations
+~~~~~~~~~~~~~~~~~~~~~~~
+
+XXX add note about defining relation type / definition
+
+A relation is defined by a Python class heriting `RelationType`. The name
+of the class corresponds to the name of the type. The class then contains
+a description of the properties of this type of relation, and could as well
+contain a string for the subject and a string for the object. This allows to create
+new definition of associated relations, (so that the class can have the
+definition properties from the relation) for example ::
+
+ class locked_by(RelationType):
+ """relation on all entities indicating that they are locked"""
+ inlined = True
+ cardinality = '?*'
+ subject = '*'
+ object = 'CWUser'
+
+If provided, the `subject` and `object` attributes denote the subject
+and object of the various relation definitions related to the relation
+type. Allowed values for these attributes are:
+
+* a string corresponding to an entity type
+* a tuple of string corresponding to multiple entity types
+* special string such as follows:
+
+ - "**": all types of entities
+ - "*": all types of non-meta entities
+ - "@": all types of meta entities but not system entities (e.g. used for
+ the basic schema description)
+
+When a relation is not inlined and not symmetrical, and it does not require
+specific permissions, it can be defined using a `SubjectRelation`
+attribute in the EntityType class. The first argument of `SubjectRelation` gives
+the entity type for the object of the relation.
+
+:Naming convention:
+
+ Although this way of defining relations uses a Python class, the
+ naming convention defined earlier prevails over the PEP8 conventions
+ used in the framework: relation type class names use
+ ``underscore_separated_words``.
+
+:Historical note:
+
+ It has been historically possible to use `ObjectRelation` which
+ defines a relation in the opposite direction. This feature is soon to be
+ deprecated and therefore should not be used in newly written code.
+
+:Future deprecation note:
+
+ In an even more remote future, it is quite possible that the
+ SubjectRelation shortcut will become deprecated, in favor of the
+ RelationType declaration which offers some advantages in the context
+ of reusable cubes.
+
+Definition of permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+The entity type `CWPermission` from the standard library
+allows to build very complex and dynamic security architectures. The schema of
+this entity type is as follow:
+
+.. sourcecode:: python
+
+ class CWPermission(EntityType):
+ """entity type that may be used to construct some advanced security configuration
+ """
+ name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
+ require_group = SubjectRelation('CWGroup', cardinality='+*',
+ description=_('groups to which the permission is granted'))
+ require_state = SubjectRelation('State',
+ description=_("entity's state in which the permission is applicable"))
+ # can be used on any entity
+ require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
+ description=_("link a permission to the entity. This "
+ "permission should be used in the security "
+ "definition of the entity's type to be useful."))
+
+
+Example of configuration:
+
+.. sourcecode:: python
+
+ class Version(EntityType):
+ """a version is defining the content of a particular project's release"""
+
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
+ 'update': ('managers', 'logilab', 'owners',),
+ 'delete': ('managers', ),
+ 'add': ('managers', 'logilab',
+ ERQLExpression('X version_of PROJ, U in_group G,'
+ 'PROJ require_permission P, P name "add_version",'
+ 'P require_group G'),)}
+
+
+ class version_of(RelationType):
+ """link a version to its project. A version is necessarily linked to one and only one project.
+ """
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
+ 'delete': ('managers', ),
+ 'add': ('managers', 'logilab',
+ RRQLExpression('O require_permission P, P name "add_version",'
+ 'U in_group G, P require_group G'),)
+ }
+ inlined = True
+
+
+This configuration indicates that an entity `CWPermission` named
+"add_version" can be associated to a project and provides rights to create
+new versions on this project to specific groups. It is important to notice that:
+
+* in such case, we have to protect both the entity type "Version" and the relation
+ associating a version to a project ("version_of")
+
+* because of the genericity of the entity type `CWPermission`, we have to execute
+ a unification with the groups and/or the states if necessary in the expression
+ ("U in_group G, P require_group G" in the above example)
+
+
+
+Handling schema changes
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Also, it should be clear that to properly handle data migration, an
+instance's schema is stored in the database, so the python schema file
+used to defined it is only read when the instance is created or
+upgraded.
+
+.. XXX complete me
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,12 @@
+Data model
+==========
+
+This chapter describes how you define a schema and how to make it evolves as the time goes.
+
+.. toctree::
+ :maxdepth: 1
+
+ definition
+ metadata
+ baseschema
+ define-workflows
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/datamodel/metadata.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,37 @@
+
+Metadata
+--------
+
+.. index::
+ schema: meta-data;
+ schema: eid; creation_date; modification_data; cwuri
+ schema: created_by; owned_by; is; is_instance;
+
+Each entity type in |cubicweb| has at least the following meta-data attributes and relations:
+
+`eid`
+ entity's identifier which is unique in an instance. We usually call this identifier `eid` for historical reason.
+
+`creation_date`
+ Date and time of the creation of the entity.
+
+`modification_date`
+ Date and time of the latest modification of an entity.
+
+`cwuri`
+ Reference URL of the entity, which is not expected to change.
+
+`created_by`
+ Relation to the :ref:`users <CWUser>` who has created the entity
+
+`owned_by`
+ Relation to :ref:`users <CWUser>` whom the entity belongs; usually the creator but not
+ necessary, and it could have multiple owners notably for permission control
+
+`is`
+ Relation to the :ref:`entity type <CWEType>` of which type the entity is.
+
+`is_instance`
+ Relation to the :ref:`entity types <CWEType>` of which type the
+ entity is an instance of.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/cwconfig.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,5 @@
+Configuration
+-------------
+
+.. automodule:: cubicweb.cwconfig
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/dbapi.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,121 @@
+.. _dbapi:
+
+Python/RQL API
+~~~~~~~~~~~~~~
+
+The Python API developped to interface with RQL is inspired from the standard db-api,
+with a Connection object having the methods cursor, rollback and commit essentially.
+The most important method is the `execute` method of a cursor.
+
+.. sourcecode:: python
+
+ execute(rqlstring, args=None, build_descr=True)
+
+:rqlstring: the RQL query to execute (unicode)
+:args: if the query contains substitutions, a dictionary containing the values to use
+
+The `Connection` object owns the methods `commit` and `rollback`. You
+*should never need to use them* during the development of the web
+interface based on the *CubicWeb* framework as it determines the end
+of the transaction depending on the query execution success. They are
+however useful in other contexts such as tests or custom controllers.
+
+.. note::
+
+ While executing update queries (SET, INSERT, DELETE), if a query generates
+ an error related to security, a rollback is automatically done on the current
+ transaction.
+
+Executing RQL queries from a view or a hook
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you're within code of the web interface, the db-api like connexion is
+handled by the request object. You should not have to access it directly, but
+use the `execute` method directly available on the request, eg:
+
+.. sourcecode:: python
+
+ rset = self._cw.execute(rqlstring, kwargs)
+
+Similarly, on the server side (eg in hooks), there is no db-api connexion (since
+you're directly inside the data-server), so you'll have to use the execute method
+of the session object.
+
+
+Proper usage of `.execute`
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's say you want to get T which is in configuration C, this translates to:
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
+
+But it must be written in a syntax that will benefit from the use
+of a cache on the RQL server side:
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
+
+The syntax tree is built once for the "generic" RQL and can be re-used
+with a number of different eids. There rql IN operator is an exception
+to this rule.
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
+ % ','.join(['foo', 'bar']))
+
+Alternativelly, some of the common data related to an entity can be
+obtained from the `entity.related()` method (which is used under the
+hood by the orm when you use attribute access notation on an entity to
+get a relation. The initial request would then be translated to:
+
+.. sourcecode:: python
+
+ entity.related('in_conf', 'object')
+
+Additionnaly this benefits from the fetch_attrs policy (see
+:ref:`FetchAttrs`) eventually defined on the class element, which says
+which attributes must be also loaded when the entity is loaded through
+the orm.
+
+
+.. _resultset:
+
+The `ResultSet` API
+~~~~~~~~~~~~~~~~~~~
+
+ResultSet instances are a very commonly manipulated object. They have
+a rich API as seen below, but we would like to highlight a bunch of
+methods that are quite useful in day-to-day practice:
+
+* `__str__()` (applied by `print`) gives a very useful overview of both
+ the underlying RQL expression and the data inside; unavoidable for
+ debugging purposes
+
+* `printable_rql()` produces back a well formed RQL expression as a
+ string; it is very useful to build views
+
+* `entities()` returns a generator on all entities of the result set
+
+* `get_entity(row, col)` gets the entity at row, col coordinates; one
+ of the most used result set method
+
+.. autoclass:: cubicweb.rset.ResultSet
+ :members:
+
+
+The `Cursor` API
+~~~~~~~~~~~~~~~~
+
+The whole cursor API is developped below.
+
+.. note::
+
+ In practice we use the `.execute` method on the _cw object of
+ appobjects. Usage of other methods is quite rare.
+
+.. autoclass:: cubicweb.dbapi.Cursor
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,10 @@
+Core APIs
+=========
+
+.. toctree::
+ :maxdepth: 1
+
+ dbapi.rst
+ reqbase.rst
+ cwconfig.rst
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/devcore/reqbase.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,40 @@
+Request and ResultSet methods
+-----------------------------
+
+Those are methods you'll find on both request objects and on
+repository session.
+
+Request methods
+~~~~~~~~~~~~~~~
+
+`URL handling`:
+
+* `build_url(*args, **kwargs)`, returns an absolute URL based on the
+ given arguments. The *controller* supposed to handle the response,
+ can be specified through the first positional parameter (the
+ connection is theoretically done automatically :).
+
+`Data formatting`:
+
+* `format_date(date, date_format=None, time=False)` returns a string for a
+ date time according to instance's configuration
+
+* `format_time(time)` returns a string for a date time according to
+ instance's configuration
+
+`And more...`:
+
+* `tal_render(template, variables)`, renders a precompiled page template with
+ variables in the given dictionary as context
+
+
+Result set methods
+~~~~~~~~~~~~~~~~~~
+
+* `get_entity(row, col)`, returns the entity corresponding to the data position
+ in the *result set*
+
+* `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but
+ also call the method `complete()` on the entity before returning it
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/application-logic.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,166 @@
+How to use entities objects
+---------------------------
+
+The previous chapters detailed the classes and methods available to
+the developper at the so-called `ORM`_ level. However they say little
+about the common patterns of usage of these objects.
+
+.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
+
+Entities objects are used in the repository and web sides of
+CubicWeb. On the repository side of things, one should manipulate them
+in Hooks and Operations.
+
+Hooks and Operations provide support for the implementation of rules
+such as computed attributes, coherency invariants, etc (they play the
+same role as database triggers, but in a way that is independant of
+the actual data sources).
+
+So a lot of an application's business rules will be written in Hooks
+(or Operations).
+
+On the web side, views also typically operate using entity
+objects. Obvious entity methods for use in views are the dublin code
+method like dc_title, etc. For separation of concerns reasons, one
+should ensure no ui logic pervades the entities level, and also no
+business logic should creep into the views.
+
+In the duration of a transaction, entities objects can be instantiated
+many times, in views and hooks, even for the same database entity. For
+instance, in a classic CubicWeb deployment setup, the repository and
+the web frontend are separated process communicating over the
+wire. There is no way state can be shared between these processes
+(there is a specific API for that). Hence, it is not possible to use
+entity objects as messengers between these components of an
+application. It means that an attribute set as in `obj.x = 42`,
+whether or not x is actually an entity schema attribute, has a short
+life span, limited to the hook, operation or view within which the
+object was built.
+
+Setting an attribute or relation value can be done in the context of a
+Hook/Operation, using the obj.set_attributes(x=42) notation or a plain
+RQL SET expression.
+
+In views, it would be preferable to encapsulate the necessary logic in
+a method of the concerned entity class(es). But of course, this advice
+is also reasonnable for Hooks/Operations, though the separation of
+concerns here is less stringent than in the case of views.
+
+This leads to the practical role of entity objects: it's where an
+important part of the application logic lie (the other part being
+located in the Hook/Operations).
+
+Anatomy of an entity class
+--------------------------
+
+We can look now at a real life example coming from the `tracker`_
+cube. Let us begin to study the entities/project.py content.
+
+.. sourcecode:: python
+
+ class Project(TreeMixIn, AnyEntity):
+ __regid__ = 'Project'
+ __implements__ = AnyEntity.__implements__ + (ITree,)
+ fetch_attrs, fetch_order = fetch_config(('name', 'description',
+ 'description_format', 'summary'))
+
+ TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")'
+
+ tree_attribute = 'subproject_of'
+ parent_target = 'subject'
+ children_target = 'object'
+
+ def dc_title(self):
+ return self.name
+
+First we see that it uses an ITree interface and the TreeMixIn default
+implementation. The attributes `tree_attribute`, `parent_target` and
+`children_target` are used by the TreeMixIn code. This is typically
+used in views concerned with the representation of tree-like
+structures (CubicWeb provides several such views).
+
+It is important that the views themselves try not to implement this
+logic, not only because such views would be hardly applyable to other
+tree-like relations, but also because it is perfectly fine and useful
+to use such an interface in Hooks.
+
+In fact, Tree nature is a property of the data model that cannot be
+fully and portably expressed at the level of database entities (think
+about the transitive closure of the child relation). This is a further
+argument to implement it at entity class level.
+
+The `dc_title` method provides a (unicode string) value likely to be
+consummed by views, but note that here we do not care about output
+encodings. We care about providing data in the most universal format
+possible, because the data could be used by a web view (which would be
+responsible of ensuring XHTML compliance), or a console or file
+oriented output (which would have the necessary context about the
+needed byte stream encoding).
+
+The fetch_attrs, fetch_order class attributes are parameters of the
+`ORM`_ layer. They tell which attributes should be loaded at once on
+entity object instantiation (by default, only the eid is known, other
+attributes are loaded on demand), and which attribute is to be used to
+order the .related() and .unrelated() methods output.
+
+Finally, we can observe the big TICKET_DEFAULT_STATE_RESTR is a pure
+application domain piece of data. There is, of course, no limitation
+to the amount of class attributes of this kind.
+
+Let us now dig into more substantial pieces of code.
+
+.. sourcecode:: python
+
+ def latest_version(self, states=('published',), reverse=None):
+ """returns the latest version(s) for the project in one of the given
+ states.
+
+ when no states specified, returns the latest published version.
+ """
+ order = 'DESC'
+ if reverse is not None:
+ warn('reverse argument is deprecated',
+ DeprecationWarning, stacklevel=1)
+ if reverse:
+ order = 'ASC'
+ rset = self.versions_in_state(states, order, True)
+ if rset:
+ return rset.get_entity(0, 0)
+ return None
+
+ def versions_in_state(self, states, order='ASC', limit=False):
+ """returns version(s) for the project in one of the given states, sorted
+ by version number.
+
+ If limit is true, limit result to one version.
+ If reverse, versions are returned from the smallest to the greatest.
+ """
+ if limit:
+ order += ' LIMIT 1'
+ rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \
+ 'WHERE V num N, V in_state S, S name IN (%s), ' \
+ 'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states))
+ return self._cw.execute(rql, {'p': self.eid})
+
+.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/
+
+These few lines exhibit the important properties we want to outline:
+
+* entity code is concerned with the application domain
+
+* it is NOT concerned with database coherency (this is the realm of
+ Hooks/Operations); in other words, it assumes a coherent world
+
+* it is NOT concerned with end-user interfaces
+
+* however it can be used in both contexts
+
+* it does not create or manipulate the internal object's state
+
+* it plays freely with RQL expression as needed
+
+* it is not concerned with internationalization
+
+* it does not raise exceptions
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/data-as-objects.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,143 @@
+Access to persistent data
+--------------------------
+
+Python-level access to persistent data is provided by the
+:class:`Entity <cubicweb.entity>` class.
+
+An entity class is bound to a schema entity type. Descriptors are added when
+classes are registered in order to initialize the class according to its schema:
+
+* we can access the defined attributes in the schema thanks to the attributes of
+ the same name on instances (typed value)
+
+* we can access the defined relations in the schema thanks to the relations of
+ the same name on instances (entities instances list)
+
+
+`Formatting and output generation`:
+
+* `view(__vid, __registry='views', **kwargs)`, applies the given view to the entity
+ (and returns an unicode string)
+
+* `absolute_url(*args, **kwargs)`, returns an absolute URL to access the primary view
+ of an entity
+
+* `rest_path()`, returns a relative REST URL to get the entity
+
+* `printable_value(attr, value=_marker, attrtype=None, format='text/html', displaytime=True)`,
+ returns a string enabling the display of an attribute value in a given format
+ (the value is automatically recovered if necessary)
+
+`Data handling`:
+
+* `as_rset()`, converts the entity into an equivalent result set simulating the
+ request `Any X WHERE X eid _eid_`
+
+* `complete(skip_bytes=True)`, executes a request that recovers at
+ once all the missing attributes of an entity
+
+* `get_value(name)`, returns the value associated to the attribute name given
+ in parameter
+
+* `related(rtype, role='subject', limit=None, entities=False)`,
+ returns a list of entities related to the current entity by the
+ relation given in parameter
+
+* `unrelated(rtype, targettype, role='subject', limit=None)`,
+ returns a result set corresponding to the entities not (yet)
+ related to the current entity by the relation given in parameter
+ and satisfying its constraints
+
+* `set_attributes(**kwargs)`, updates the attributes list with the corresponding
+ values given named parameters
+
+* `set_relations(**kwargs)`, add relations to the given object. To
+ set a relation where this entity is the object of the relation,
+ use `reverse_<relation>` as argument name. Values may be an
+ entity, a list of entities, or None (meaning that all relations of
+ the given type from or to this object should be deleted).
+
+* `copy_relations(ceid)`, copies the relations of the entities having the eid
+ given in the parameters on the current entity
+
+* `delete()` allows to delete the entity
+
+
+The :class:`AnyEntity` class
+----------------------------
+
+To provide a specific behavior for each entity, we have to define a class
+inheriting from `cubicweb.entities.AnyEntity`. In general, we define this class
+in `mycube.entities` module (or in a submodule if we want to split code among
+multiple files) so that it will be available on both server and client side.
+
+The class `AnyEntity` is a sub-class of Entity that add methods to it,
+and helps specializing (by further subclassing) the handling of a
+given entity type.
+
+Most methods defined for `AnyEntity`, in addition to `Entity`, add
+support for the `Dublin Core`_ metadata.
+
+.. _`Dublin Core`: http://dublincore.org/
+
+`Standard meta-data (Dublin Core)`:
+
+* `dc_title()`, returns a unicode string corresponding to the
+ meta-data `Title` (used by default is the first non-meta attribute
+ of the entity schema)
+
+* `dc_long_title()`, same as dc_title but can return a more
+ detailed title
+
+* `dc_description(format='text/plain')`, returns a unicode string
+ corresponding to the meta-data `Description` (looks for a
+ description attribute by default)
+
+* `dc_authors()`, returns a unicode string corresponding to the meta-data
+ `Authors` (owners by default)
+
+* `dc_creator()`, returns a unicode string corresponding to the
+ creator of the entity
+
+* `dc_date(date_format=None)`, returns a unicode string corresponding to
+ the meta-data `Date` (update date by default)
+
+* `dc_type(form='')`, returns a string to display the entity type by
+ specifying the preferred form (`plural` for a plural form)
+
+* `dc_language()`, returns the language used by the entity
+
+
+`Misc methods`:
+
+* `after_deletion_path`, return (path, parameters) which should be
+ used as redirect information when this entity is being deleted
+
+* `pre_web_edit`, callback called by the web editcontroller when an
+ entity will be created/modified, to let a chance to do some entity
+ specific stuff (does nothing by default)
+
+Inheritance
+-----------
+
+When describing a data model, entities can inherit from other entities as is
+common in object-oriented programming.
+
+You have the possibility to redefine whatever pleases you, as follow:
+
+.. sourcecode:: python
+
+ from cubes.OTHER_CUBE import entities
+
+ class EntityExample(entities.EntityExample):
+
+ def dc_long_title(self):
+ return '%s (%s)' % (self.name, self.description)
+
+The most specific entity definition will always the one used by the
+ORM. For instance, the new EntityExample above in mycube replaces the
+one in OTHER_CUBE. These types are stored in the `etype` section of
+the `vregistry`.
+
+Notice this is different than yams schema inheritance.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,13 @@
+Data as objects
+===============
+
+In this chapter, we will introduce the objects that are used to handle
+the logic associated to the data stored in the database.
+
+.. toctree::
+ :maxdepth: 1
+
+ data-as-objects
+ load-sort
+ interfaces
+ application-logic
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/interfaces.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,65 @@
+Interfaces
+----------
+
+This is the same thing as object-oriented programming `interfaces`_.
+
+.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
+
+Definition of an interface is quite trivial. An example from cubicweb
+itself (found in cubicweb/interfaces.py):
+
+.. sourcecode:: python
+
+ class ITree(Interface):
+
+ def parent(self):
+ """returns the parent entity"""
+
+ def children(self):
+ """returns the item's children"""
+
+ def children_rql(self):
+ """returns RQL to get children"""
+
+ def iterchildren(self):
+ """iterates over the item's children"""
+
+ def is_leaf(self):
+ """returns true if this node as no child"""
+
+ def is_root(self):
+ """returns true if this node has no parent"""
+
+ def root(self):
+ """returns the root object"""
+
+
+Declaration of interfaces implemented by a class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. sourcecode:: python
+
+ from cubicweb.interfaces import ITree
+ from cubicweb.mixins import TreeMixIn
+
+ class MyEntity(TreeMixIn, AnyEntity):
+ __regid__ = 'MyEntity'
+ __implements__ = AnyEntity.__implements__ + ('ITree',)
+
+ tree_attribute = 'filed_under'
+
+The TreeMixIn here provides a default implementation for the
+interface. The tree_attribute class attribute is actually used by this
+implementation to help implement correct behaviour.
+
+Interfaces (and some implementations as mixins) defined in the library
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: cubicweb.interfaces
+ :members:
+
+.. automodule:: cubicweb.mixins
+ :members:
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/entityclasses/load-sort.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,53 @@
+
+.. _FetchAttrs:
+
+Loaded attributes and default sorting management
+````````````````````````````````````````````````
+
+* The class attribute `fetch_attrs` allows to define in an entity class a list
+ of names of attributes or relations that should be automatically loaded when
+ entities of this type are fetched from the database. In the case of relations,
+ we are limited to *subject of cardinality `?` or `1`* relations.
+
+* The class method `fetch_order(attr, var)` expects an attribute (or relation)
+ name as a parameter and a variable name, and it should return a string
+ to use in the requirement `ORDERBY` of an RQL query to automatically
+ sort the list of entities of such type according to this attribute, or
+ `None` if we do not want to sort on the attribute given in the parameter.
+ By default, the entities are sorted according to their creation date.
+
+* The class method `fetch_unrelated_order(attr, var)` is similar to
+ the method `fetch_order` except that it is essentially used to
+ control the sorting of drop-down lists enabling relations creation
+ in the editing view of an entity. The default implementation uses
+ the modification date. Here's how to adapt it for one entity (sort
+ on the name attribute): ::
+
+ class MyEntity(AnyEntity):
+ __regid__ = 'MyEntity'
+ fetch_attrs = ('modification_date', 'name')
+
+ @classmethod
+ def fetch_unrelated_order(cls, attr, var):
+ if attr == 'name':
+ return '%s ASC' % var
+ return None
+
+
+The function `fetch_config(fetchattrs, mainattr=None)` simplifies the
+definition of the attributes to load and the sorting by returning a
+list of attributes to pre-load (considering automatically the
+attributes of `AnyEntity`) and a sorting function based on the main
+attribute (the second parameter if specified, otherwise the first
+attribute from the list `fetchattrs`). This function is defined in
+`cubicweb.entities`.
+
+For example: ::
+
+ class Transition(AnyEntity):
+ """..."""
+ __regid__ = 'Transition'
+ fetch_attrs, fetch_order = fetch_config(['name'])
+
+Indicates that for the entity type "Transition", you have to pre-load
+the attribute `name` and sort by default on this attribute.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,23 @@
+.. _Part2:
+
+----------------------
+Repository development
+----------------------
+
+This part is about developing applications with the *CubicWeb*
+framework. It is not concerned with the web system, which is a
+separate layer and has its own whole chapter.
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ cubes/index
+ vreg.rst
+ datamodel/index
+ entityclasses/index
+ devcore/index
+ repo/index
+ testing.rst
+ migration.rst
+ profiling.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/migration.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,198 @@
+.. -*- coding: utf-8 -*-
+
+.. _migration:
+
+Migration
+=========
+
+One of the main design goals of *CubicWeb* was to support iterative and agile
+development. For this purpose, multiple actions are provided to facilitate the
+improvement of an instance, and in particular to handle the changes to be
+applied to the data model, without loosing existing data.
+
+The current version of a cube (and of cubicweb itself) is provided in the file
+`__pkginfo__.py` as a tuple of 3 integers.
+
+Migration scripts management
+----------------------------
+
+Migration scripts has to be located in the directory `migration` of your
+cube and named accordingly:
+
+::
+
+ <version n° X.Y.Z>[_<description>]_<mode>.py
+
+in which :
+
+* X.Y.Z is the model version number to which the script enables to migrate.
+
+* *mode* (between the last "_" and the extension ".py") is used for
+ distributed installation. It indicates to which part
+ of the application (RQL server, web server) the script applies.
+ Its value could be :
+
+ * `common`, applies to the RQL server as well as the web server and updates
+ files on the hard drive (configuration files migration for example).
+
+ * `web`, applies only to the web server and updates files on the hard drive.
+
+ * `repository`, applies only to the RQL server and updates files on the
+ hard drive.
+
+ * `Any`, applies only to the RQL server and updates data in the database
+ (schema and data migration for example).
+
+Again in the directory `migration`, the file `depends.map` allows to indicate
+that for the migration to a particular model version, you always have to first
+migrate to a particular *CubicWeb* version. This file can contain comments (lines
+starting by `#`) and a dependancy is listed as follows: ::
+
+ <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
+
+For example: ::
+
+ 0.12.0: 2.26.0
+ 0.13.0: 2.27.0
+ # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
+ 0.15.0: 2.28.0
+
+Base context
+------------
+
+The following identifiers are pre-defined in migration scripts:
+
+* `config`, instance configuration
+
+* `interactive_mode`, boolean indicating that the script is executed in
+ an interactive mode or not
+
+* `versions_map`, dictionary of migrated versions (key are cubes
+ names, including 'cubicweb', values are (from version, to version)
+
+* `confirm(question)`, function asking the user and returning true
+ if the user answers yes, false otherwise (always returns true in
+ non-interactive mode)
+
+* `_()` is equivalent to `unicode` allowing to flag the strings to
+ internationalize in the migration scripts.
+
+In the `repository` scripts, the following identifiers are also defined:
+
+* `commit(ask_confirm=True)`, request confirming and executing a "commit"
+
+* `schema`, instance schema (readen from the database)
+
+* `fsschema`, installed schema on the file system (e.g. schema of
+ the updated model and cubicweb)
+
+* `repo`, repository object
+
+* `session`, repository session object
+
+
+Schema migration
+----------------
+The following functions for schema migration are available in `repository`
+scripts:
+
+* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
+ attribute to an existing entity type. If the attribute type is not specified,
+ then it is extracted from the updated schema.
+
+* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
+ existing entity type.
+
+* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
+
+* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
+ If `auto` is True, all the relations using this entity type and having a known
+ entity type on the other hand will automatically be added.
+
+* `drop_entity_type(etype, commit=True)`, removes an entity type and all the
+ relations using it.
+
+* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
+
+* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
+ type. If `addrdef` is True, all the relations definitions of this type will
+ be added.
+
+* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
+ definitions of this type.
+
+* `rename_relation(oldname, newname, commit=True)`, renames a relation.
+
+* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
+ relation definition.
+
+* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
+ a relation definition.
+
+* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
+ synchronizes properties and/or permissions on:
+ - the whole schema if ertype is None
+ - an entity or relation type schema if ertype is a string
+ - a relation definition if ertype is a 3-uple (subject, relation, object)
+
+* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
+ properties of a relation definition by using the named parameters of the properties
+ to change.
+
+* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
+ relation <rtype> of entity type <etype>.
+
+* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
+ for the relation <rtype> of entity type <etype>.
+
+Data migration
+--------------
+The following functions for data migration are available in `repository` scripts:
+
+* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
+ query, either to interrogate or update. A result set object is returned.
+
+* `add_entity(etype, *args, **kwargs)`, adds a nes entity type of the given
+ type. The attribute and relation values are specified using the named and
+ positionned parameters.
+
+Workflow creation
+-----------------
+
+The following functions for workflow creation are available in `repository`
+scripts:
+
+* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
+ for a given type(s)
+
+You can find more details about workflows in the chapter :ref:`Workflow` .
+
+Configuration migration
+-----------------------
+
+The following functions for configuration migration are available in all
+scripts:
+
+* `option_renamed(oldname, newname)`, indicates that an option has been renamed
+
+* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
+ belong anymore to the same group.
+
+* `option_added(oldname, newname)`, indicates that an option has been added.
+
+* `option_removed(oldname, newname)`, indicates that an option has been deleted.
+
+
+Others migration functions
+--------------------------
+Those functions are only used for low level operations that could not be
+accomplished otherwise or to repair damaged databases during interactive
+session. They are available in `repository` scripts:
+
+* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
+* `add_entity_type_table(etype, commit=True)`
+* `add_relation_type_table(rtype, commit=True)`
+* `uninline_relation(rtype, commit=True)`
+
+
+[FIXME] Add explanation on how to use cubicweb-ctl shell
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/profiling.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,55 @@
+Profiling and performance
+=========================
+
+If you feel that one of your pages takes more time than it should to be
+generated, chances are that you're making too many RQL queries. Obviously,
+there are other reasons but experience tends to show this is the first thing to
+track down. Luckily, CubicWeb provides a configuration option to log RQL
+queries. In your ``all-in-one.conf`` file, set the **query-log-file** option::
+
+ # web application query log file
+ query-log-file=~/myapp-rql.log
+
+Then restart your application, reload your page and stop your application.
+The file ``myapp-rql.log`` now contains the list of RQL queries that were
+executed during your test. It's a simple text file containing lines such as::
+
+ Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec)
+ Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec)
+
+The structure of each line is::
+
+ <RQL QUERY> <QUERY ARGS IF ANY> -- <TIME SPENT>
+
+CubicWeb also provides the **exlog** command to examine and summarize data found
+in such a file:
+
+.. sourcecode:: sh
+
+ $ cubicweb-ctl exlog < ~/myapp-rql.log
+ 0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
+ 0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
+ 0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
+ 0.01 1 Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s {, }
+ 0.01 1 Any B,T,P ORDERBY lower(T) WHERE B is Bookmark,B title T, B path P, B bookmarked_by U, U eid %(x)s {}
+ 0.01 1 Any A,B,C,D WHERE A eid %(x)s,A name B,A creation_date C,A modification_date D {}
+
+This command sorts and uniquifies queries so that it's easy to see where
+is the hot spot that needs optimization.
+
+Do not neglect to set the **fetch_attrs** attribute you can define in your
+entity classes because it can greatly reduce the number of queries executed (see
+:ref:`FetchAttrs`).
+
+You should also know about the **profile** option in the ``all-in-on.conf``. If
+set, this option will make your application run in an `hotshot`_ session and
+store the results in the specified file.
+
+.. _hotshot: http://docs.python.org/library/hotshot.html#module-hotshot
+
+Last but no least, if you're using the PostgreSQL database backend, VACUUMing
+your database can significantly improve the performance of the queries (by
+updating the statistics used by the query optimizer). Nowadays, this is done
+automatically from time to time, but if you've just imported a large amount of
+data in your db, you will want to vacuum it (with the analyse option on). Read
+the documentation of your database for more information.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/hooks.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,436 @@
+.. -*- coding: utf-8 -*-
+
+.. _hooks:
+
+Hooks and Operations
+====================
+
+Generalities
+------------
+
+Paraphrasing the `emacs`_ documentation, let us say that hooks are an
+important mechanism for customizing an application. A hook is
+basically a list of functions to be called on some well-defined
+occasion (this is called `running the hook`).
+
+.. _`emacs`: http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html
+
+In CubicWeb, hooks are subclasses of the Hook class in
+`server/hook.py`, implementing their own `call` method, and selected
+over a set of pre-defined `events` (and possibly more conditions,
+hooks being selectable AppObjects like views and components).
+
+There are two families of events: data events and server events. In a
+typical application, most of the Hooks are defined over data
+events.
+
+The purpose of data hooks is to complement the data model as defined
+in the schema.py, which is static by nature, with dynamic or value
+driven behaviours. It is functionally equivalent to a `database
+trigger`_, except that database triggers definition languages are not
+standardized, hence not portable (for instance, PL/SQL works with
+Oracle and PostgreSQL but not SqlServer nor Sqlite).
+
+.. _`database trigger`: http://en.wikipedia.org/wiki/Database_trigger
+
+Data hooks can serve the following purposes:
+
+* enforcing constraints that the static schema cannot express
+ (spanning several entities/relations, exotic value ranges and
+ cardinalities, etc.)
+
+* implement computed attributes
+
+Operations are Hook-like objects that may be created by Hooks and
+scheduled to happen just before (or after) the `commit` event. Hooks
+being fired immediately on data operations, it is sometime necessary
+to delay the actual work down to a time where all other Hooks have
+run, for instance a validation check which needs that all relations be
+already set on an entity. Also while the order of execution of Hooks
+is data dependant (and thus hard to predict), it is possible to force
+an order on Operations.
+
+Operations also may be used to process various side effects associated
+with a transaction such as filesystem udpates, mail notifications,
+etc.
+
+Operations are subclasses of the Operation class in `server/hook.py`,
+implementing `precommit_event` and other standard methods (wholly
+described in :ref:`operations_api`).
+
+Events
+------
+
+Hooks are mostly defined and used to handle `dataflow`_ operations. It
+means as data gets in (entities added, updated, relations set or
+unset), specific events are issued and the Hooks matching these events
+are called.
+
+.. _`dataflow`: http://en.wikipedia.org/wiki/Dataflow
+
+Below comes a list of the dataflow events related to entities operations:
+
+* before_add_entity
+
+* before_update_entity
+
+* before_delete_entity
+
+* after_add_entity
+
+* after_update_entity
+
+* after_delete_entity
+
+These define ENTTIES HOOKS. RELATIONS HOOKS are defined
+over the following events:
+
+* after_add_relation
+
+* after_delete_relation
+
+* before_add_relation
+
+* before_delete_relation
+
+This is an occasion to remind us that relations support the add/delete
+operation, but no update.
+
+Non data events also exist. These are called SYSTEM HOOKS.
+
+* server_startup
+
+* server_shutdown
+
+* server_maintenance
+
+* server_backup
+
+* server_restore
+
+* session_open
+
+* session_close
+
+
+Using dataflow Hooks
+--------------------
+
+Dataflow hooks either automate data operations or maintain the
+consistency of the data model. In the later case, we must use a
+specific exception named ValidationError
+
+Validation Errors
+~~~~~~~~~~~~~~~~~
+
+When a condition is not met in a Hook/Operation, it must raise a
+`ValidationError`. Raising anything but a (subclass of)
+ValidationError is a programming error. Raising a ValidationError
+entails aborting the current transaction.
+
+The ValidationError exception is used to convey enough information up
+to the user interface. Hence its constructor is different from the
+default Exception constructor. It accepts, positionally:
+
+* an entity eid,
+
+* a dict whose keys represent attribute (or relation) names and values
+ an end-user facing message (hence properly translated) relating the
+ problem.
+
+An entity hook
+~~~~~~~~~~~~~~
+
+We will use a very simple example to show hooks usage. Let us start
+with the following schema.
+
+.. sourcecode:: python
+
+ class Person(EntityType):
+ age = Int(required=True)
+
+We would like to add a range constraint over a person's age. Let's
+write an hook. It shall be placed into mycube/hooks.py. If this file
+were to grow too much, we can easily have a mycube/hooks/... package
+containing hooks in various modules.
+
+.. sourcecode:: python
+
+ from cubicweb import ValidationError
+ from cubicweb.selectors import implements
+ from cubicweb.server.hook import Hook
+
+ class PersonAgeRange(Hook):
+ __regid__ = 'person_age_range'
+ events = ('before_add_entity', 'before_update_entity')
+ __select__ = Hook.__select__ & implements('Person')
+
+ def __call__(self):
+ if 0 >= self.entity.age <= 120:
+ return
+ msg = self._cw._('age must be between 0 and 120')
+ raise ValidationError(self.entity.eid, {'age': msg})
+
+Hooks being AppObjects like views, they have a __regid__ and a
+__select__ class attribute. The base __select__ is augmented with an
+`implements` selector matching the desired entity type. The `events`
+tuple is used by the Hook.__select__ base selector to dispatch the
+hook on the right events. In an entity hook, it is possible to
+dispatch on any entity event (e.g. 'before_add_entity',
+'before_update_entity') at once if needed.
+
+Like all appobjects, hooks have the `self._cw` attribute which
+represents the current session. In entity hooks, a `self.entity`
+attribute is also present.
+
+
+A relation hook
+~~~~~~~~~~~~~~~
+
+Let us add another entity type with a relation to person (in
+mycube/schema.py).
+
+.. sourcecode:: python
+
+ class Company(EntityType):
+ name = String(required=True)
+ boss = SubjectRelation('Person', cardinality='1*')
+
+We would like to constrain the company's bosses to have a minimum
+(legal) age. Let's write an hook for this, which will be fired when
+the `boss` relation is established.
+
+.. sourcecode:: python
+
+ class CompanyBossLegalAge(Hook):
+ __regid__ = 'company_boss_legal_age'
+ events = ('before_add_relation',)
+ __select__ = Hook.__select__ & match_rtype('boss')
+
+ def __call__(self):
+ boss = self._cw.entity_from_eid(self.eidto)
+ if boss.age < 18:
+ msg = self._cw._('the minimum age for a boss is 18')
+ raise ValidationError(self.eidfrom, {'boss': msg})
+
+We use the `match_rtype` selector to select the proper relation type.
+
+The essential difference with respect to an entity hook is that there
+is no self.entity, but `self.eidfrom` and `self.eidto` hook attributes
+which represent the subject and object eid of the relation.
+
+
+Using Operations
+----------------
+
+Let's augment our example with a new `subsidiary_of` relation on Company.
+
+.. sourcecode:: python
+
+ class Company(EntityType):
+ name = String(required=True)
+ boss = SubjectRelation('Person', cardinality='1*')
+ subsidiary_of = SubjectRelation('Company', cardinality='*?')
+
+Base example
+~~~~~~~~~~~~
+
+We would like to check that there is no cycle by the `subsidiary_of`
+relation. This is best achieved in an Operation since all relations
+are likely to be set at commit time.
+
+.. sourcecode:: python
+
+ def check_cycle(self, session, eid, rtype, role='subject'):
+ parents = set([eid])
+ parent = session.entity_from_eid(eid)
+ while parent.related(rtype, role):
+ parent = parent.related(rtype, role)[0]
+ if parent.eid in parents:
+ msg = session._('detected %s cycle' % rtype)
+ raise ValidationError(eid, {rtype: msg})
+ parents.add(parent.eid)
+
+ class CheckSubsidiaryCycleOp(Operation):
+
+ def precommit_event(self):
+ check_cycle(self.session, self.eidto, 'subsidiary_of')
+
+
+ class CheckSubsidiaryCycleHook(Hook):
+ __regid__ = 'check_no_subsidiary_cycle'
+ events = ('after_add_relation',)
+ __select__ = Hook.__select__ & match_rtype('subsidiary_of')
+
+ def __call__(self):
+ CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
+
+The operation is instantiated in the Hook.__call__ method.
+
+An operation always takes a session object as first argument
+(accessible as `.session` from the operation instance), and optionally
+all keyword arguments needed by the operation. These keyword arguments
+will be accessible as attributes from the operation instance.
+
+Like in Hooks, ValidationError can be raised in Operations. Other
+exceptions are programming errors.
+
+Notice how our hook will instantiate an operation each time the Hook
+is called, i.e. each time the `subsidiary_of` relation is set.
+
+Using set_operation
+~~~~~~~~~~~~~~~~~~~
+
+There is an alternative method to schedule an Operation from a Hook,
+using the `set_operation` function.
+
+.. sourcecode:: python
+
+ from cubicweb.server.hook import set_operation
+
+ class CheckSubsidiaryCycleHook(Hook):
+ __regid__ = 'check_no_subsidiary_cycle'
+ events = ('after_add_relation',)
+ __select__ = Hook.__select__ & match_rtype('subsidiary_of')
+
+ def __call__(self):
+ set_operation(self._cw, 'subsidiary_cycle_detection', self.eidto,
+ CheckSubsidiaryCycleOp, rtype=self.rtype)
+
+ class CheckSubsidiaryCycleOp(Operation):
+
+ def precommit_event(self):
+ for eid in self._cw.transaction_data['subsidiary_cycle_detection']:
+ check_cycle(self.session, eid, self.rtype)
+
+Here, we call set_operation with a session object, a specially forged
+key, a value that is the actual payload of an individual operation (in
+our case, the object of the subsidiary_of relation) , the class of the
+Operation, and more optional parameters to give to the operation (here
+the rtype which do not vary accross operations).
+
+The body of the operation must then iterate over the values that have
+been mapped in the transaction_data dictionary to the forged key.
+
+This mechanism is especially useful on two occasions (not shown in our
+example):
+
+* massive data import (reduced memory consumption within a large
+ transaction)
+
+* when several hooks need to instantiate the same operation (e.g. an
+ entity and a relation hook).
+
+.. note::
+
+ A more realistic example can be found in the advanced tutorial
+ chapter :ref:`adv_tuto_security_propagation`.
+
+.. _operations_api:
+
+Operation: a small API overview
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: cubicweb.server.hook.Operation
+.. autoclass:: cubicweb.server.hook.LateOperation
+.. autofunction:: cubicweb.server.hook.set_operation
+
+Hooks writing rules
+-------------------
+
+Remainder
+~~~~~~~~~
+
+Never, ever use the `entity.foo = 42` notation to update an entity. It
+will not work.
+
+How to choose between a before and an after event ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before hooks give you access to the old attribute (or relation)
+values. By definition the database is not yet updated in a before
+hook.
+
+To access old and new values in an before_update_entity hook, one can
+use the `server.hook.entity_oldnewvalue` function which returns a
+tuple of the old and new values. This function takes an entity and an
+attribute name as parameters.
+
+In a 'before_add|update_entity' hook the self.entity contains the new
+values. One is allowed to further modify them before database
+operations, using the dictionary notation.
+
+.. sourcecode:: python
+
+ self.entity['age'] = 42
+
+This is because using self.entity.set_attributes(age=42) will
+immediately update the database (which does not make sense in a
+pre-database hook), and will trigger any existing
+before_add|update_entity hook, thus leading to infinite hook loops or
+such awkward situations.
+
+Beyond these specific cases, updating an entity attribute or relation
+must *always* be done using `set_attributes` and `set_relations`
+methods.
+
+(Of course, ValidationError will always abort the current transaction,
+whetever the event).
+
+Peculiarities of inlined relations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Some relations are defined in the schema as `inlined` (see
+:ref:`RelationType` for details). In this case, they are inserted in
+the database at the same time as entity attributes.
+
+Hence in the case of before_add_relation, such relations already exist
+in the database.
+
+Edited attributes
+~~~~~~~~~~~~~~~~~
+
+On udpates, it is possible to ask the `entity.edited_attributes`
+variable whether one attribute has been updated.
+
+.. sourcecode:: python
+
+ if 'age' not in entity.edited_attribute:
+ return
+
+Deleted in transaction
+~~~~~~~~~~~~~~~~~~~~~~
+
+The session object has a deleted_in_transaction method, which can help
+writing deletion Hooks.
+
+.. sourcecode:: python
+
+ if self._cw.deleted_in_transaction(self.eidto):
+ return
+
+Given this predicate, we can avoid scheduling an operation.
+
+Disabling hooks
+~~~~~~~~~~~~~~~
+
+It is sometimes convenient to disable some hooks. For instance to
+avoid infinite Hook loops. One uses the `hooks_control` context
+manager.
+
+This can be controlled more finely through the `category` Hook class
+attribute, which is a string.
+
+.. sourcecode:: python
+
+ with hooks_control(self.session, self.session.HOOKS_ALLOW_ALL, <category>):
+ # ... do stuff
+
+.. autoclass:: cubicweb.server.session.hooks_control
+
+The existing categories are: ``email``, ``syncsession``,
+``syncschema``, ``bookmark``, ``security``, ``worfklow``,
+``metadata``, ``notification``, ``integrity``, ``activeintegrity``.
+
+Nothing precludes one to invent new categories and use the
+hooks_control context manager to filter them (in or out).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,13 @@
+.. -*- coding: utf-8 -*-
+
+Repository customization
+++++++++++++++++++++++++
+.. toctree::
+ :maxdepth: 1
+
+ sessions
+ hooks
+ notifications
+ tasks
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/notifications.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,6 @@
+.. -*- coding: utf-8 -*-
+
+Notifications management
+========================
+
+.. XXX FILLME
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/sessions.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,27 @@
+.. -*- coding: utf-8 -*-
+
+Sessions
+========
+
+There are three kinds of sessions.
+
+* `user sessions` are the most common: they are related to users and
+ carry security checks coming with user credentials
+
+* `super sessions` are children of ordinary user sessions and allow to
+ bypass security checks (they are created by calling unsafe_execute
+ on a user session); this is often convenient in hooks which may
+ touch data that is not directly updatable by users
+
+* `internal sessions` have all the powers; they are also used in only a
+ few situations where you don't already have an adequate session at
+ hand, like: user authentication, data synchronisation in
+ multi-source contexts
+
+.. note::
+ Do not confuse the session type with their connection mode, for
+ instance : 'in memory' or 'pyro'.
+
+[WRITE ME]
+
+* authentication and management of sessions
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/repo/tasks.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Tasks
+=========
+
+[WRITE ME]
+
+* repository tasks
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/testing.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,258 @@
+.. -*- coding: utf-8 -*-
+
+Tests
+=====
+
+Unit tests
+----------
+
+The *CubicWeb* framework provides the `CubicWebTC` test base class in
+the module `cubicweb.devtools.testlib`.
+
+Tests shall be put into the mycube/test directory. Additional test
+data shall go into mycube/test/data.
+
+It is much advised to write tests concerning entities methods, hooks
+and operations, security. The CubicWebTC base class has convenience
+methods to help test all of this.
+
+.. note::
+
+ In the realm of views, there is not much to do but check that the
+ views are valid XHTML. See :ref:`automatic_views_tests` for
+ details. Integration of CubicWeb tests with UI testing tools such as
+ `selenium`_ are currently under invesitgation.
+
+.. _selenium: http://seleniumhq.org/projects/ide/
+
+Most unit tests need a live database to work against. This is achieved
+by CubicWeb using automatically sqlite (bundled with Python, see
+http://docs.python.org/library/sqlite3.html) as a backend.
+
+The database is stored in the mycube/test/tmpdb,
+mycube/test/tmpdb-template files. If it does not (yet) exists, it will
+be built automatically when the test suit starts.
+
+.. warning::
+
+ Whenever the schema changes (new entities, attributes, relations)
+ one must delete these two files. Changes concerned only with entity
+ or relation type properties (constraints, cardinalities,
+ permissions) and generally dealt with using the
+ `sync_schema_props_perms()` fonction of the migration environment
+ need not a database regeneration step.
+
+Unit test by example
+````````````````````
+
+We start with an example extracted from the keyword cube (available
+from http://www.cubicweb.org/project/cubicweb-keyword).
+
+.. sourcecode:: python
+
+ from cubicweb.devtools.testlib import CubicWebTC
+ from cubicweb import ValidationError
+
+ class ClassificationHooksTC(CubicWebTC):
+
+ def setup_database(self):
+ req = self.request()
+ group_etype = req.execute('Any X WHERE X name "CWGroup"').get_entity(0,0)
+ c1 = req.create_entity('Classification', name=u'classif1',
+ classifies=group_etype)
+ user_etype = req.execute('Any X WHERE X name "CWUser"').get_entity(0,0)
+ c2 = req.create_entity('Classification', name=u'classif2',
+ classifies=user_etype)
+ self.kw1 = req.create_entity('Keyword', name=u'kwgroup', included_in=c1)
+ self.kw2 = req.create_entity('Keyword', name=u'kwuser', included_in=c2)
+
+ def test_cannot_create_cycles(self):
+ # direct obvious cycle
+ self.assertRaises(ValidationError, self.kw1.set_relations,
+ subkeyword_of=self.kw1)
+ # testing indirect cycles
+ kw3 = self.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
+ 'SK subkeyword_of K WHERE C name "classif1", K eid %s'
+ % self.kw1.eid).get_entity(0,0)
+ self.kw1.set_relations(subkeyword_of=kw3)
+ self.assertRaises(ValidationError, self.commit)
+
+The test class defines a `setup_database` method which populates the
+database with initial data. Each test of the class runs with this
+pre-populated database.
+
+The test case itself checks that an Operation does it job of
+preventing cycles amongst Keyword entities.
+
+You can see an example of security tests in the
+:ref:`adv_tuto_security`.
+
+It is possible to have these tests run continuously using `apycot`_.
+
+.. _apycot: http://www.logilab.org/project/apycot
+
+Managing connections or users
++++++++++++++++++++++++++++++
+
+Since unit tests are done with the SQLITE backend and this does not
+support multiple connections at a time, you must be careful when
+simulating security, changing users.
+
+By default, tests run with a user with admin privileges. This
+user/connection must never be closed.
+
+Before a self.login, one has to release the connection pool in use
+with a self.commit, self.rollback or self.close.
+
+The `login` method returns a connection object that can be used as a
+context manager:
+
+.. sourcecode:: python
+
+ with self.login('user1') as user:
+ req = user.req
+ req.execute(...)
+
+On exit of the context manager, either a commit or rollback is issued,
+which releases the connection.
+
+When one is logged in as a normal user and wants to switch back to the
+admin user without committing, one has to use
+self.restore_connection().
+
+Usage with restore_connection:
+
+.. sourcecode:: python
+
+ # execute using default admin connection
+ self.execute(...)
+ # I want to login with another user, ensure to free admin connection pool
+ # (could have used rollback but not close here
+ # we should never close defaut admin connection)
+ self.commit()
+ cnx = self.login('user')
+ # execute using user connection
+ self.execute(...)
+ # I want to login with another user or with admin user
+ self.commit(); cnx.close()
+ # restore admin connection, never use cnx = self.login('admin'), it will return
+ # the default admin connection and one may be tempted to close it
+ self.restore_connection()
+
+.. warning::
+
+ Do not use the references kept to the entities created with a
+ connection from another !
+
+Email notifications tests
+-------------------------
+
+When running tests potentially generated e-mails are not really sent
+but is found in the list `MAILBOX` of module
+`cubicweb.devtools.testlib`.
+
+You can test your notifications by analyzing the contents of this list, which
+contains objects with two attributes:
+
+* `recipients`, the list of recipients
+* `msg`, object email.Message
+
+Let us look at simple example from the ``blog`` cube.
+
+.. sourcecode:: python
+
+ from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
+
+ class BlogTestsCubicWebTC(CubicWebTC):
+ """test blog specific behaviours"""
+
+ def test_notifications(self):
+ req = self.request()
+ cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
+ description=u'cubicweb is beautiful')
+ blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
+ content=u'cubicweb hop')
+ blog_entry_1.set_relations(entry_of=cubicweb_blog)
+ blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
+ content=u'cubicweb yes')
+ blog_entry_2.set_relations(entry_of=cubicweb_blog)
+ self.assertEquals(len(MAILBOX), 0)
+ self.commit()
+ self.assertEquals(len(MAILBOX), 2)
+ mail = MAILBOX[0]
+ self.assertEquals(mail.subject, '[data] hop')
+ mail = MAILBOX[1]
+ self.assertEquals(mail.subject, '[data] yes')
+
+.. _automatic_views_tests:
+
+Automatic views testing
+-----------------------
+
+This is done automatically with the AutomaticWebTest class. At cube
+creation time, the mycube/test/test_mycube.py file contains such a
+test. The code here has to be uncommented to be usable, without
+further modification.
+
+The ``auto_populate`` method uses a smart algorithm to create
+pseudo-random data in the database, thus enabling the views to be
+invoked and tested.
+
+Depending on the schema, hooks and operations constraints, it is not
+always possible for the automatic auto_populate to proceed.
+
+It is possible of course to completely redefine auto_populate. A
+lighter solution is to give hints (fill some class attributes) about
+what entities and relations have to be skipped by the auto_populate
+mechanism. These are:
+
+* `no_auto_populate`, may contain a list of entity types to skip
+* `ignored_relations`, may contain a list of relation types to skip
+* `application_rql`, may contain a list of rql expressions that
+ auto_populate cannot guess by itself; these must yield resultsets
+ against which views may be selected.
+
+
+Test APIS
+---------
+
+Using Pytest
+````````````
+
+The `pytest` utility (shipping with `logilab-common`_, which is a
+mandatory dependency of CubicWeb) extends the Python unittest
+functionality and is the preferred way to run the CubicWeb test
+suites. Bare unittests also work the usual way.
+
+.. _logilab-common: http://www.logilab.org/project/logilab-common
+
+To use it, you may:
+
+* just launch `pytest` in your cube to execute all tests (it will
+ discover them automatically)
+* launch `pytest unittest_foo.py` to execute one test file
+* launch `pytest unittest_foo.py bar` to execute all test methods and
+ all test cases whose name contain `bar`
+
+Additionally, the `-x` option tells pytest to exit at the first error
+or failure. The `-i` option tells pytest to drop into pdb whenever an
+exception occurs in a test.
+
+When the `-x` option has been used and the run stopped on a test, it
+is possible, after having fixed the test, to relaunch pytest with the
+`-R` option to tell it to start testing again from where it previously
+failed.
+
+Using the `TestCase` base class
+```````````````````````````````
+
+The base class of CubicWebTC is logilab.common.testlib.TestCase, which
+provides a lot of convenient assertion methods.
+
+.. autoclass:: logilab.common.testlib.TestCase
+ :members:
+
+CubicWebTC API
+``````````````
+.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devrepo/vreg.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,107 @@
+The VRegistry, selectors and application objects
+================================================
+
+This chapter talks about core concepts of the |cubicweb| framework,
+that make it different from other frameworks (and maybe not easy to
+grasp at a first glance). To be able to do advanced development with
+|cubicweb| you need a good understanding of what is explained below.
+
+This chapter goes deep into details. You don't have to remember them
+all but keep it in mind so you can go back there later.
+
+An overview of AppObjects, the VRegistry and Selectors is given in the
+:ref:`VRegistryIntro` chapter.
+
+.. autodocstring:: cubicweb.cwvreg
+.. autodocstring:: cubicweb.selectors
+.. automodule:: cubicweb.appobject
+
+Base selectors
+--------------
+
+Selectors are scoring functions that are called by the registry to tell whenever
+an appobject can be selected in a given context. Selector sets are for instance
+the glue that tie views to the data model. Using them appropriately is an
+essential part of the construction of well behaved cubes.
+
+Of course you may have to write your own set of selectors as your needs grows and
+you get familiar with the framework (see :ref:`CustomSelectors`).
+
+Here is a description of generic selectors provided by CubicWeb that should suit
+most of your needs.
+
+Bare selectors
+~~~~~~~~~~~~~~
+Those selectors are somewhat dumb, which doesn't mean they're not (very) useful.
+
+.. autoclass:: cubicweb.appobject.yes
+.. autoclass:: cubicweb.selectors.match_kwargs
+.. autoclass:: cubicweb.selectors.appobject_selectable
+
+
+Result set selectors
+~~~~~~~~~~~~~~~~~~~~~
+Those selectors are looking for a result set in the context ('rset' argument or
+the input context) and match or not according to its shape. Some of these
+selectors have different behaviour if a particular cell of the result set is
+specified using 'row' and 'col' arguments of the input context or not.
+
+.. autoclass:: cubicweb.selectors.none_rset
+.. autoclass:: cubicweb.selectors.any_rset
+.. autoclass:: cubicweb.selectors.nonempty_rset
+.. autoclass:: cubicweb.selectors.empty_rset
+.. autoclass:: cubicweb.selectors.one_line_rset
+.. autoclass:: cubicweb.selectors.multi_lines_rset
+.. autoclass:: cubicweb.selectors.multi_columns_rset
+.. autoclass:: cubicweb.selectors.paginated_rset
+.. autoclass:: cubicweb.selectors.sorted_rset
+.. autoclass:: cubicweb.selectors.one_etype_rset
+.. autoclass:: cubicweb.selectors.multi_etypes_rset
+
+
+Entity selectors
+~~~~~~~~~~~~~~~~
+Those selectors are looking for either an `entity` argument in the input context,
+or entity found in the result set ('rset' argument or the input context) and
+match or not according to entity's (instance or class) properties.
+
+.. autoclass:: cubicweb.selectors.non_final_entity
+.. autoclass:: cubicweb.selectors.implements
+.. autoclass:: cubicweb.selectors.score_entity
+.. autoclass:: cubicweb.selectors.rql_condition
+.. autoclass:: cubicweb.selectors.relation_possible
+.. autoclass:: cubicweb.selectors.partial_relation_possible
+.. autoclass:: cubicweb.selectors.has_related_entities
+.. autoclass:: cubicweb.selectors.partial_has_related_entities
+.. autoclass:: cubicweb.selectors.has_permission
+.. autoclass:: cubicweb.selectors.has_add_permission
+
+
+Logged user selectors
+~~~~~~~~~~~~~~~~~~~~~
+Those selectors are looking for properties of the user issuing the request.
+
+.. autoclass:: cubicweb.selectors.anonymous_user
+.. autoclass:: cubicweb.selectors.authenticated_user
+.. autoclass:: cubicweb.selectors.match_user_groups
+
+
+Web request selectors
+~~~~~~~~~~~~~~~~~~~~~
+Those selectors are looking for properties of *web* request, they can not be
+used on the data repository side.
+
+.. autoclass:: cubicweb.selectors.match_form_params
+.. autoclass:: cubicweb.selectors.match_search_state
+.. autoclass:: cubicweb.selectors.match_context_prop
+.. autoclass:: cubicweb.selectors.match_view
+.. autoclass:: cubicweb.selectors.primary_view
+.. autoclass:: cubicweb.selectors.specified_etype_implements
+
+
+Other selectors
+~~~~~~~~~~~~~~~
+.. autoclass:: cubicweb.selectors.match_transition
+
+You'll also find some other (very) specific selectors hidden in other modules
+than :mod:`cubicweb.selectors`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/controllers.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,201 @@
+.. _controllers:
+
+Controllers
+-----------
+
+Overview
+++++++++
+
+Controllers are responsible for taking action upon user requests
+(loosely following the terminology of the MVC meta pattern).
+
+The following controllers are provided out-of-the box in CubicWeb. We
+list them by category. They are all defined in
+(:mod:`cubicweb.web.views.basecontrollers`).
+
+`Browsing`:
+
+* the View controlleris associated with most browsing actions within a
+ CubicWeb application: it always instantiates a
+ :ref:`the_main_template` and lets the ResultSet/Views dispatch
+ system build up the whole content; it handles ObjectNotFound and
+ NoSelectableObject errors that may bubble up to its entry point, in
+ an end-user-friendly way (but other programming errors will slip
+ through)
+
+* the JSon controller (same module) provides services for Ajax calls,
+ typically using JSON as a serialization format for input, and
+ sometimes using either JSON or XML for output;
+
+* the Login/Logout controllers make effective user login or logout
+ requests
+
+`Edition`:
+
+* the Edit controller (see :ref:`edit_controller`) handles CRUD
+ operations in response to a form being submitted; it works in close
+ association with the Forms, to which it delegates some of the work
+
+* the Form validator controller provides form validation from Ajax
+ context, using the Edit controller, to implement the classic form
+ handling loop (user edits, hits 'submit/apply', validation occurs
+ server-side by way of the Form validator controller, and the UI is
+ decorated with failure information, either global or per-field ,
+ until it is valid)
+
+`Other`:
+
+* the SendMail controller (web/views/basecontrollers.py) is reponsible
+ for outgoing email notifications
+
+* the MailBugReport controller (web/views/basecontrollers.py) allows
+ to quickly have a `repotbug` feature in one's application
+
+Registration
+++++++++++++
+
+All controllers (should) live in the 'controllers' namespace within
+the global registry.
+
+API
++++
+
+Most API details should be resolved by source code inspection, as the
+various controllers have differing goals.
+
+`web/controller.py` contains the top-level abstract Controller class and
+its (NotImplemented) entry point `publish(rset=None)` method.
+
+A handful of helpers are also provided there:
+
+* process_rql builds a result set from an rql query typically issued
+ from the browser (and available through _cw.form['rql'])
+
+* validate_cache will force cache validation handling with respect to
+ the HTTP Cache directives (that were typically originally issued
+ from a previous server -> client response); concrete Controller
+ implementations dealing with HTTP (thus, for instance, not the
+ SendMail controller) may very well call this in their publication
+ process.
+
+
+.. _edit_controller:
+
+The `edit controller`
++++++++++++++++++++++
+
+It can be found in (:mod:`cubicweb.web.views.editcontroller`).
+
+Editing control
+~~~~~~~~~~~~~~~~
+
+.. XXX this look obsolete
+
+The parameters related to entities to edit are specified as follows ::
+
+ <field name>:<entity eid>
+
+where entity eid could be a letter in case of an entity to create. We
+name those parameters as *qualified*.
+
+1. Retrieval of entities to edit by looking for the forms parameters
+ starting by `eid:` and also having a parameter `__type` associated
+ (also *qualified* by eid)
+
+2. For all the attributes and the relations of an entity to edit:
+
+ 1. search for a parameter `edits-<relation name>` or `edito-<relation name>`
+ qualified in the case of a relation where the entity is object
+ 2. if found, the value returned is considered as the initial value
+ for this relaiton and we then look for the new value(s) in the parameter
+ <relation name> (qualified)
+ 3. if the value returned is different from the initial value, an database update
+ request is done
+
+3. For each entity to edit:
+
+ 1. if a qualified parameter `__linkto` is specified, its value has to be
+ a string (or a list of string) such as: ::
+
+ <relation type>:<eids>:<target>
+
+ where <target> is either `subject` or `object` and each eid could be
+ separated from the others by a `_`. Target specifies if the *edited entity*
+ is subject or object of the relation and each relation specified will
+ be inserted.
+
+ 2. if a qualified parameter `__clone_eid` is specified for an entity, the
+ relations of the specified entity passed as value of this parameter are
+ copied on the edited entity.
+
+ 3. if a qualified parameter `__delete` is specified, its value must be
+ a string or a list of string such as follows: ::
+
+ <ssubjects eids>:<relation type>:<objects eids>
+
+ where each eid subject or object can be seperated from the other
+ by `_`. Each relation specified will be deleted.
+
+ 4. if a qualified parameter `__insert` is specified, its value should
+ follow the same pattern as `__delete`, but each relation specified is
+ inserted.
+
+4. If the parameters `__insert` and/or `__delete` are found not qualified,
+ they are interpreted as explained above (independantly from the number
+ of entities edited).
+
+5. If no entity is edited but the form contains the parameters `__linkto`
+ and `eid`, this one is interpreted by using the value specified for `eid`
+ to designate the entity on which to add the relations.
+
+
+.. note::
+
+ * If the parameter `__action_delete` is found, all the entities specified
+ as to be edited will be deleted.
+
+ * If the parameter `__action_cancel` is found, no action is completed.
+
+ * If the parameter `__action_apply` is found, the editing is
+ applied normally but the redirection is done on the form (see
+ :ref:`RedirectionControl`).
+
+ * The parameter `__method` is also supported as for the main template
+
+ * If no entity is found to be edited and if there is no parameter
+ `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or
+ `__insert`, an error is raised.
+
+ * Using the parameter `__message` in the form will allow to use its value
+ as a message to provide the user once the editing is completed.
+
+
+.. _RedirectionControl:
+
+Redirection control
+~~~~~~~~~~~~~~~~~~~
+Once editing is completed, there is still an issue left: where should we go
+now? If nothing is specified, the controller will do his job but it does not
+mean we will be happy with the result. We can control that by using the
+following parameters:
+
+* `__redirectpath`: path of the URL (relative to the root URL of the site,
+ no form parameters
+
+* `__redirectparams`: forms parameters to add to the path
+
+* `__redirectrql`: redirection RQL request
+
+* `__redirectvid`: redirection view identifier
+
+* `__errorurl`: initial form URL, used for redirecting in case a validation
+ error is raised during editing. If this one is not specified, an error page
+ is displayed instead of going back to the form (which is, if necessary,
+ responsible for displaying the errors)
+
+* `__form_id`: initial view form identifier, used if `__action_apply` is
+ found
+
+In general we use either `__redirectpath` and `__redirectparams` or
+`__redirectrql` and `__redirectvid`.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/css.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,30 @@
+.. -*- coding: utf-8 -*-
+
+CSS Stylesheet
+---------------
+Conventions
+~~~~~~~~~~~
+
+.. XXX external_resources variable
+.. naming convention
+.. request.add_css
+
+
+Extending / overriding existing styles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We cannot modify the order in which the application is reading the CSS. In
+the case we want to create new CSS style, the best is to define it a in a new
+CSS located under ``myapp/data/`` and use those new styles while writing
+customized views and templates.
+
+If you want to modify an existing CSS styling property, you will have to use
+``!important`` declaration to override the existing property. The application
+apply a higher priority on the default CSS and you can not change that.
+Customized CSS will not be read first.
+
+
+CubicWeb stylesheets
+~~~~~~~~~~~~~~~~~~~~
+
+.. XXX explain diffenrent files and main classes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/facets.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,172 @@
+The facets system
+-----------------
+
+Facets allow to restrict searches according to some criteria. CubicWeb
+has a builtin `facet`_ system to define restrictions `filters`_ really
+as easily as possible. A few base classes for facets are provided in
+``cubicweb.web.facet.py``. All classes inherits from the base class
+``AbstractFacet``.
+
+Here is an overview of the facets rendering pick from the `tracker` cube:
+
+.. image:: ../images/facet_overview.png
+
+Facets will appear on each page presenting more than one entity.
+
+
+
+VocabularyFacet
+~~~~~~~~~~~~~~~~
+The ``VocabularyFacet`` inherits from the ``AbstractFacet``.
+A class which inherits from VocabularyFacets must redefine these methods:
+
+.. automethod:: cubicweb.web.facet.VocabularyFacet.vocabulary
+.. automethod:: cubicweb.web.facet.VocabularyFacet.possible_values
+
+RelationFacet
+~~~~~~~~~~~~~~
+
+The ``RelationFacet`` inherits from the ``VocabularyFacet``. It allows to filter entities according to certain relation's values. Generally, you just have to define some class attributes like:
+
+- rtype: the name of the relation
+- role: the default value is set to `subject`
+- target_attr: needed if it is not the default attribute of the entity
+
+
+To illustrate this facet, let's take for example an *excerpt* of the schema of an office location search application:
+
+.. sourcecode:: python
+
+ class Office(WorkflowableEntityType):
+ price = Int(description='euros / m2 / HC / HT')
+ surface = Int(description='m2')
+ description = RichString(fulltextindexed=True)
+ has_address = SubjectRelation('PostalAddress',
+ cardinality='1?',
+ composite='subject')
+ proposed_by = SubjectRelation('Agency')
+ comments = ObjectRelation('Comment',
+ cardinality='1*',
+ composite='object')
+ screenshots = SubjectRelation(('File', 'Image'),
+ cardinality='*1',
+ composite='subject')
+
+
+We define a facet to filter offices according to the attribute
+`postalcode` of their associated `PostalAdress`.
+
+.. sourcecode:: python
+
+ class PostalCodeFacet(RelationFacet):
+ __regid__ = 'postalcode-facet' # every registered class must have an id
+ __select__ = implements('Office') # this facet should only be selected when
+ # visualizing offices
+ rtype = 'has_address' # this facet is a filter on the entity linked to
+ # the office thrhough the relation
+ # has_address
+ target_attr = 'postalcode' # the filter's key is the attribute "postal_code"
+ # of the target PostalAddress entity
+
+
+AttributeFacet
+~~~~~~~~~~~~~~
+
+The ``AttributeFacet`` inherits from the ``RelationFacet``. It allows to filter entities according to certain attribute's values.
+
+The example below resumes the former schema. We define now a filter based on the `surface` attribute of the
+`Office`.
+
+.. sourcecode:: python
+
+ class SurfaceFacet(AttributeFacet):
+ __regid__ = 'surface-facet' # every registered class must have an id
+ __select__ = implements('Office') # this facet should only be selected when
+ # visualizing offices
+ rtype = 'surface' # the filter's key is the attribute "surface"
+ comparator = '>=' # override the default value of operator since
+ # we want to filter according to a
+ # minimal
+ # value, not an exact one
+
+ def rset_vocabulary(self, ___):
+ """override the default vocabulary method since we want to hard-code
+ our threshold values.
+ Not overriding would generate a filter box with all existing surfaces
+ defined in the database.
+ """
+ return [('> 200', '200'), ('> 250', '250'),
+ ('> 275', '275'), ('> 300', '300')]
+
+RangeFacet
+~~~~~~~~~~
+The ``RangeFacet`` inherits from the ``AttributeFacet``. It allows to filter entities according to certain attributes of numerical type.
+
+The ``RangeFacet`` displays a slider using `jquery`_ to choose a lower bound and an upper bound.
+
+The example below defines a facet to filter a selection of books according to their number of pages.
+
+.. sourcecode:: python
+
+ class BookPagesFacet(RangeFacet):
+ __regid__ = 'priority-facet'
+ __select__ = RangeFacet.__select__ & implements('Book')
+ rtype = 'pages'
+
+The image below display the rendering of the ``RangeFacet``:
+
+.. image:: ../images/facet_range.png
+
+DateRangeFacet
+~~~~~~~~~~~~~~
+The ``DateRangeFacet`` inherits from the ``RangeFacet``. It allows to filter entities according to certain attributes of date type.
+
+Here is an example of code that defines a facet to filter
+musical works according to their composition date:
+
+.. sourcecode:: python
+
+ class CompositionDateFacet(DateRangeFacet):
+ # 1. make sure this facet is displayed only on Track selection
+ __select__ = DateRangeFacet.__select__ & implements('Track')
+ # 2. give the facet an id required by CubicWeb)
+ __regid__ = 'compdate-facet'
+ # 3. specify the attribute name that actually stores the date in the DB
+ rtype = 'composition_date'
+
+With this facet, on each page displaying tracks, you'll be able to filter them
+according to their composition date with a jquery slider.
+
+The image below display the rendering of the ``DateRangeFacet``:
+
+.. image:: ../images/facet_date_range.png
+
+
+HasRelationFacet
+~~~~~~~~~~~~~~~~
+
+The ``DateRangeFacet`` inherits from the ``AbstractFacet``. It will
+display a simple checkbox and lets you refine your selection in order
+to get only entities that actually use this relation.
+
+Here is an example of the rendering of the ``HasRelationFacet`` to
+filter entities with image and the corresponding code:
+
+.. image:: ../images/facet_has_image.png
+
+.. sourcecode:: python
+
+ class HasImageFacet(HasRelationFacet):
+ __regid__ = 'hasimage-facet'
+ __select__ = HasRelationFacet.__select__ & implements('Book')
+ rtype = 'has_image'
+
+
+
+To use ``HasRelationFacet`` on a reverse relation add ``role = 'object'`` in
+it's definitions.
+
+.. _facet: http://en.wikipedia.org/wiki/Faceted_browser
+.. _filters: http://www.cubicweb.org/blogentry/154152
+.. _jquery: http://www.jqueryui.com/
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/form.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,213 @@
+HTML form construction
+----------------------
+
+CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
+to provide generic building blocks which will greatly help you in building forms
+properly integrated with CubicWeb (coherent display, error handling, etc...),
+while keeping things as flexible as possible.
+
+A **form** basically only holds a set of **fields**, and has te be bound to a
+**renderer** which is responsible to layout them. Each field is bound to a
+**widget** that will be used to fill in value(s) for that field (at form
+generation time) and 'decode' (fetch and give a proper Python type to) values
+sent back by the browser.
+
+The **field** should be used according to the type of what you want to edit.
+E.g. if you want to edit some date, you'll have to use the
+:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple
+widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a
+bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
+calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
+calendar). You can of course also write your own widget.
+
+
+.. automodule:: cubicweb.web.formfields
+.. automodule:: cubicweb.web.formwidgets
+.. automodule:: cubicweb.web.views.forms
+.. automodule:: cubicweb.web.views.autoform
+.. automodule:: cubicweb.web.views.formrenderers
+
+
+Now what ? Example of bare fields form
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We want to define a form doing something else than editing an entity. The idea is
+to propose a form to send an email to entities in a resultset which implements
+:class:`IEmailable`. Let's take a simplified version of what you'll find in
+:mod:`cubicweb.web.views.massmailing`.
+
+Here is the source code:
+
+.. sourcecode:: python
+
+ def sender_value(form):
+ return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
+
+ def recipient_choices(form, field):
+ return [(e.get_email(), e.eid) for e in form.cw_rset.entities()
+ if e.get_email()]
+
+ def recipient_value(form):
+ return [e.eid for e in form.cw_rset.entities() if e.get_email()]
+
+ class MassMailingForm(forms.FieldsForm):
+ __regid__ = 'massmailing'
+
+ needs_js = ('cubicweb.widgets.js',)
+ domid = 'sendmail'
+ action = 'sendmail'
+
+ sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
+ label=_('From:'),
+ value=sender_value)
+
+ recipient = ff.StringField(widget=CheckBox(),
+ label=_('Recipients:'),
+ choices=recipient_choices,
+ value=recipients_value)
+
+ subject = ff.StringField(label=_('Subject:'), max_length=256)
+
+ mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
+ inputid='mailbody'))
+
+ form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
+ _('send email'), 'SEND_EMAIL_ICON'),
+ ImgButton('cancelbutton', "javascript: history.back()",
+ stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
+
+Let's detail what's going on up there. Our form will hold four fields:
+
+* a sender field, which is disabled and will simply contains the user's name and
+ email
+
+* a recipients field, which will be displayed as a list of users in the context
+ result set with checkboxes so user can still choose who will receive his mailing
+ by checking or not the checkboxes. By default all of them will be checked since
+ field's value return a list containing same eids as those returned by the
+ vocabulary function.
+
+* a subject field, limited to 256 characters (hence we know a
+ :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
+ :class:`~cubicweb.web.formfields.StringField`)
+
+* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
+ and whose definition won't be shown here. Notice though that we tell this form
+ need this javascript file by using `needs_js`
+
+Last but not least, we add two buttons control: one to post the form using
+javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
+set to 'sendmail', which is our form DOM id as specified by its `domid`
+attribute), another to cancel the form which will go back to the previous page
+using another javascript call. Also we specify an image to use as button icon as a
+resource identifier (see :ref:`external_resources`) given as last argument to
+:class:`cubicweb.web.formwidgets.ImgButton`.
+
+To see this form, we still have to wrap it in a view. This is pretty simple:
+
+.. sourcecode:: python
+
+ class MassMailingFormView(form.FormViewMixIn, EntityView):
+ __regid__ = 'massmailing'
+ __select__ = implements(IEmailable) & authenticated_user()
+
+ def call(self):
+ form = self._cw.vreg['forms'].select('massmailing', self._cw,
+ rset=self.cw_rset)
+ self.w(form.render())
+
+As you see, we simply define a view with proper selector so it only apply to a
+result set containing :class:`IEmailable` entities, and so that only users in the
+managers or users group can use it. Then in the `call()` method for this view we
+simply select the above form and write what its `.render()` method returns.
+
+When this form is submitted, a controller with id 'sendmail' will be called (as
+specified using `action`). This controller will be responsible to actually send
+the mail to specified recipients.
+
+Here is what it looks like:
+
+.. sourcecode:: python
+
+ class SendMailController(Controller):
+ __regid__ = 'sendmail'
+ __select__ = authenticated_user() & match_form_params('recipient', 'mailbody', 'subject')
+
+ def publish(self, rset=None):
+ body = self._cw.form['mailbody']
+ subject = self._cw.form['subject']
+ eids = self._cw.form['recipient']
+ # eids may be a string if only one recipient was specified
+ if isinstance(eids, basestring):
+ rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
+ else:
+ rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
+ recipients = list(rset.entities())
+ msg = format_mail({'email' : self._cw.user.get_email(),
+ 'name' : self._cw.user.dc_title()},
+ recipients, body, subject)
+ if not self._cw.vreg.config.sendmails([(msg, recipients]):
+ msg = self._cw._('could not connect to the SMTP server')
+ else:
+ msg = self._cw._('emails successfully sent')
+ raise Redirect(self._cw.build_url(__message=msg))
+
+
+The entry point of a controller is the publish method. In that case we simply get
+back post values in request's `form` attribute, get user instances according
+to eids found in the 'recipient' form value, and send email after calling
+:func:`format_mail` to get a proper email message. If we can't send email or
+if we successfully sent email, we redirect to the index page with proper message
+to inform the user.
+
+Also notice that our controller has a selector that deny access to it to
+anonymous users (we don't want our instance to be used as a spam relay), but also
+check expected parameters are specified in forms. That avoids later defensive
+programming (though it's not enough to handle all possible error cases).
+
+To conclude our example, suppose we wish a different form layout and that existent
+renderers are not satisfying (we would check that first of course :). We would then
+have to define our own renderer:
+
+.. sourcecode:: python
+
+ class MassMailingFormRenderer(formrenderers.FormRenderer):
+ __regid__ = 'massmailing'
+
+ def _render_fields(self, fields, w, form):
+ w(u'<table class="headersform">')
+ for field in fields:
+ if field.name == 'mailbody':
+ w(u'</table>')
+ w(u'<div id="toolbar">')
+ w(u'<ul>')
+ for button in form.form_buttons:
+ w(u'<li>%s</li>' % button.render(form))
+ w(u'</ul>')
+ w(u'</div>')
+ w(u'<div>')
+ w(field.render(form, self))
+ w(u'</div>')
+ else:
+ w(u'<tr>')
+ w(u'<td class="hlabel">%s</td>' % self.render_label(form, field))
+ w(u'<td class="hvalue">')
+ w(field.render(form, self))
+ w(u'</td></tr>')
+
+ def render_buttons(self, w, form):
+ pass
+
+We simply override the `_render_fields` and `render_buttons` method of the base form renderer
+to arrange fields as we desire it: here we'll have first a two columns table with label and
+value of the sender, recipients and subject field (form order respected), then form controls,
+then a div containing the textarea for the email's content.
+
+To bind this renderer to our form, we should add to our form definition above:
+
+.. sourcecode:: python
+
+ form_renderer_id = 'massmailing'
+
+
+.. Example of entity fields form
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/httpcaching.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,3 @@
+HTTP cache management
+---------------------
+XXX feedme
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,21 @@
+Web side development
+====================
+
+In this chapter, we will describe the core APIs for web development in
+the *CubicWeb* framework.
+
+.. toctree::
+ :maxdepth: 2
+
+ publisher
+ controllers
+ request
+ views/index
+ rtags
+ js
+ css
+ form
+ facets
+ internationalization
+.. property
+ httpcaching
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/internationalization.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,222 @@
+.. -*- coding: utf-8 -*-
+
+.. _internationalization:
+
+Internationalization
+---------------------
+
+Cubicweb fully supports the internalization of its content and interface.
+
+Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
+
+.. _`GNU gettext`: http://www.gnu.org/software/gettext/
+
+Cubicweb' internalization involves two steps:
+
+* in your Python code and cubicweb-tal templates : mark translatable strings
+
+* in your instance : handle the translation catalog, edit translations
+
+String internationalization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+User defined string
+```````````````````
+
+In the Python code and cubicweb-tal templates translatable strings can be
+marked in one of the following ways :
+
+ * by using the *built-in* function `_` ::
+
+ class PrimaryView(EntityView):
+ """the full view of an non final entity"""
+ __regid__ = 'primary'
+ title = _('primary')
+
+ OR
+
+ * by using the equivalent request's method ::
+
+ class NoResultView(View):
+ """default view when no result has been found"""
+ __regid__ = 'noresult'
+
+ def call(self, **kwargs):
+ self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
+ % self._cw._('No result matching query'))
+
+The goal of the *built-in* function `_` is only **to mark the
+translatable strings**, it will only return the string to translate
+itself, but not its translation (it's actually another name for the
+`unicode` builtin).
+
+In the other hand the request's method `self._cw._` is also meant to
+retrieve the proper translation of translation strings in the
+requested language.
+
+Finally you can also use the `__` attribute of request object to get a
+translation for a string *which should not itself added to the catalog*,
+usually in case where the actual msgid is created by string interpolation ::
+
+ self._cw.__('This %s' % etype)
+
+In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
+messages catalogs.
+
+Translations in cubicweb-tal template can also be done with TAL tags
+`i18n:content` and `i18n:replace`.
+
+If you need to add messages on top of those that can be found in the source,
+you can create a file named `i18n/static-messages.pot`.
+
+You could put there messages not found in the python sources or
+overrides for some messages of used cubes.
+
+Generated string
+````````````````
+
+We do not need to mark the translation strings of entities/relations used by a
+particular instance's schema as they are generated automatically. String for
+various actions are also generated.
+
+For exemple the following schema ::
+
+ Class EntityA(EntityType):
+ relation_a2b = SubjectRelation('EntityB')
+
+ class EntityB(EntityType):
+ pass
+
+May generate the following message ::
+
+ add EntityA relation_a2b EntityB subject
+
+This message will be used in views of ``EntityA`` for creation of a new
+``EntityB`` with a preset relation ``relation_a2b`` between the current
+``EntityA`` and the new ``EntityB``. The opposite message ::
+
+ add EntityA relation_a2b EntityB object
+
+Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
+title of they respective creation form will be ::
+
+ creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
+
+ creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
+
+In the translated string you can use ``%(linkto)s`` for reference to the source
+``entity``.
+
+Handling the translation catalog
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once the internationalization is done in your code, you need to populate and
+update the translation catalog. Cubicweb provides the following commands for this
+purpose:
+
+
+* `i18ncubicweb` updates Cubicweb framework's translation
+ catalogs. Unless you actually work on the framework itself, you
+ don't need to use this command.
+
+* `i18ncube` updates the translation catalogs of *one particular cube*
+ (or of all cubes). After this command is executed you must update
+ the translation files *.po* in the "i18n" directory of your
+ cube. This command will of course not remove existing translations
+ still in use. It will mark unused translation but not remove them.
+
+* `i18ninstance` recompiles the translation catalogs of *one particular
+ instance* (or of all instances) after the translation catalogs of
+ its cubes have been updated. This command is automatically
+ called every time you create or update your instance. The compiled
+ catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
+ instance where `lang` is the language identifier ('en' or 'fr'
+ for exemple).
+
+
+Example
+```````
+
+You have added and/or modified some translation strings in your cube
+(after creating a new view or modifying the cube's schema for exemple).
+To update the translation catalogs you need to do:
+
+1. `cubicweb-ctl i18ncube <cube>`
+2. Edit the <cube>/i18n/xxx.po files and add missing translations (empty `msgstr`)
+3. `hg ci -m "updated i18n catalogs"`
+4. `cubicweb-ctl i18ninstance <myinstance>`
+
+Editing po files
+~~~~~~~~~~~~~~~~
+
+Using a PO aware editor
+````````````````````````
+
+Many tools exist to help maintain .po (PO) files. Common editors or
+development environment provides modes for these. One can also find
+dedicated PO files editor, such as `poedit`_.
+
+.. _`poedit`: http://www.poedit.net/
+
+While usage of such a tool is commendable, PO files are perfectly
+editable with a (unicode aware) plain text editor. It is also useful
+to know their structure for troubleshooting purposes.
+
+Structure of a PO file
+``````````````````````
+
+In this section, we selectively quote passages of the `GNU gettext`_
+manual chapter on PO files, available there::
+
+ http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
+
+One PO file entry has the following schematic structure::
+
+ white-space
+ # translator-comments
+ #. extracted-comments
+ #: reference...
+ #, flag...
+ #| msgid previous-untranslated-string
+ msgid untranslated-string
+ msgstr translated-string
+
+
+A simple entry can look like this::
+
+ #: lib/error.c:116
+ msgid "Unknown system error"
+ msgstr "Error desconegut del sistema"
+
+It is also possible to have entries with a context specifier. They
+look like this::
+
+ white-space
+ # translator-comments
+ #. extracted-comments
+ #: reference...
+ #, flag...
+ #| msgctxt previous-context
+ #| msgid previous-untranslated-string
+ msgctxt context
+ msgid untranslated-string
+ msgstr translated-string
+
+
+The context serves to disambiguate messages with the same
+untranslated-string. It is possible to have several entries with the
+same untranslated-string in a PO file, provided that they each have a
+different context. Note that an empty context string and an absent
+msgctxt line do not mean the same thing.
+
+Contexts and CubicWeb
+`````````````````````
+
+CubicWeb PO files have both non-contextual and contextual msgids.
+
+Contextual entries are automatically used in some cases. For instance,
+entity.dc_type(), eschema.display_name(req) or display_name(etype,
+req, form, context) methods/function calls will use them.
+
+It is also possible to explicitly use the with _cw.pgettext(context,
+msgid).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/js.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,355 @@
+.. -*- coding: utf-8 -*-
+
+Javascript
+----------
+
+*CubicWeb* uses quite a bit of javascript in its user interface and
+ships with jquery (1.3.x) and parts of the jquery UI library, plus a
+number of homegrown files and also other third party libraries.
+
+All javascript files are stored in cubicweb/web/data/. There are
+around thirty js files there. In a cube it goes to data/.
+
+Obviously one does not want javascript pieces to be loaded all at
+once, hence the framework provides a number of mechanisms and
+conventions to deal with javascript resources.
+
+Conventions
+~~~~~~~~~~~
+
+It is good practice to name cube specific js files after the name of
+the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
+
+.. XXX external_resources variable (which needs love)
+
+CubicWeb javascript API
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Javascript resources are typically loaded on demand, from views. The
+request object (available as self._cw from most application objects,
+for instance views and entities objects) has a few methods to do that:
+
+* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
+ javascript files and writes proper entries into the HTML header
+ section. The localfile parameter allows to declare resources which
+ are not from web/data (for instance, residing on a content delivery
+ network).
+
+* `add_onload(self, jscode)` which adds one raw javascript code
+ snippet inline in the html headers. This is quite useful for setting
+ up early jQuery(document).ready(...) initialisations.
+
+CubicWeb javascript events
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* ``server-response``: this event is triggered on HTTP responses (both
+ standard and ajax). The two following extra parameters are passed
+ to callbacks :
+
+ - ``ajax``: a boolean that says if the reponse was issued by an
+ ajax request
+
+ - ``node``: the DOM node returned by the server in case of an
+ ajax request, otherwise the document itself for standard HTTP
+ requests.
+
+Important AJAX APIS
+~~~~~~~~~~~~~~~~~~~
+
+* `asyncRemoteExec` and `remoteExec` are the base building blocks for
+ doing arbitrary async (resp. sync) communications with the server
+
+* `reloadComponent` is a convenience function to replace a DOM node
+ with server supplied content coming from a specific registry (this
+ is quite handy to refresh the content of some boxes for instances)
+
+* `jQuery.fn.loadxhtml` is an important extension to jQuery which
+ allows proper loading and in-place DOM update of xhtml views. It is
+ suitably augmented to trigger necessary events, and process CubicWeb
+ specific elements such as the facet system, fckeditor, etc.
+
+
+A simple example with asyncRemoteExec
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In the python side, we have to extend the BaseController class. The
+@jsonize decorator ensures that the `return value` of the method is
+encoded as JSON data. By construction, the JSonController inputs
+everything in JSON format.
+
+.. sourcecode: python
+
+ from cubicweb.web.views.basecontrollers import JSonController, jsonize
+
+ @monkeypatch(JSonController)
+ @jsonize
+ def js_say_hello(self, name):
+ return u'hello %s' % name
+
+In the javascript side, we do the asynchronous call. Notice how it
+creates a `deferred` object. Proper treatment of the return value or
+error handling has to be done through the addCallback and addErrback
+methods.
+
+.. sourcecode: javascript
+
+ function asyncHello(name) {
+ var deferred = asyncRemoteExec('say_hello', name);
+ deferred.addCallback(function (response) {
+ alert(response);
+ });
+ deferred.addErrback(function (error) {
+ alert('something fishy happened');
+ });
+ }
+
+ function syncHello(name) {
+ alert( remoteExec('say_hello', name) );
+ }
+
+Anatomy of a reloadComponent call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`reloadComponent` allows to dynamically replace some DOM node with new
+elements. It has the following signature:
+
+* `compid` (mandatory) is the name of the component to be reloaded
+
+* `rql` (optional) will be used to generate a result set given as
+ argument to the selected component
+
+* `registry` (optional) defaults to 'components' but can be any other
+ valid registry name
+
+* `nodeid` (optional) defaults to compid + 'Component' but can be any
+ explicitly specified DOM node id
+
+* `extraargs` (optional) should be a dictionary of values that will be
+ given to the cell_call method of the component
+
+A simple reloadComponent example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server side implementation of `reloadComponent` is the
+js_component method of the JSonController.
+
+The following function implements a two-steps method to delete a
+standard bookmark and refresh the UI, while keeping the UI responsive.
+
+.. sourcecode:: javascript
+
+ function removeBookmark(beid) {
+ d = asyncRemoteExec('delete_bookmark', beid);
+ d.addCallback(function(boxcontent) {
+ reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
+ document.location.hash = '#header';
+ updateMessage(_("bookmark has been removed"));
+ });
+ }
+
+`reloadComponent` is called with the id of the bookmark box as
+argument, no rql expression (because the bookmarks display is actually
+independant of any dataset context), a reference to the 'boxes'
+registry (which hosts all left, right and contextual boxes) and
+finally an explicit 'bookmarks_box' nodeid argument that stipulates
+the target DOM node.
+
+Anatomy of a loadxhtml call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
+proper loading and in-place DOM update of xhtml views. The existing
+`jQuery.load`_ function does not handle xhtml, hence the addition. The
+API of loadxhtml is roughly similar to that of `jQuery.load`_.
+
+.. _`jQuery.load`: http://api.jquery.com/load/
+
+
+* `url` (mandatory) should be a complete url (typically referencing
+ the JSonController, but this is not strictly mandatory)
+
+* `data` (optional) is a dictionary of values given to the
+ controller specified through an `url` argument; some keys may have a
+ special meaning depending on the choosen controller (such as `fname`
+ for the JSonController); the `callback` key, if present, must refer
+ to a function to be called at the end of loadxhtml (more on this
+ below)
+
+* `reqtype` (optional) specifies the request method to be used (get or
+ post); if the argument is 'post', then the post method is used,
+ otherwise the get method is used
+
+* `mode` (optional) is one of `replace` (the default) which means the
+ loaded node will replace the current node content, `swap` to replace
+ the current node with the loaded node, and `append` which will
+ append the loaded node to the current node content
+
+About the `callback` option:
+
+* it is called with two parameters: the current node, and a list
+ containing the loaded (and post-processed node)
+
+* whenever is returns another function, this function is called in
+ turn with the same parameters as above
+
+This mechanism allows callback chaining.
+
+
+A simple example with loadxhtml
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we are concerned with the retrieval of a specific view to be
+injected in the live DOM. The view will be of course selected
+server-side using an entity eid provided by the client side.
+
+.. sourcecode:: python
+
+ from cubicweb import typed_eid
+ from cubicweb.web.views.basecontrollers import JSonController, xhtmlize
+
+ @monkeypatch(JSonController)
+ @xhtmlize
+ def js_frob_status(self, eid, frobname):
+ entity = self._cw.entity_from_eid(typed_eid(eid))
+ return entity.view('frob', name=frobname)
+
+.. sourcecode:: javascript
+
+ function update_some_div(divid, eid, frobname) {
+ var params = {fname:'frob_status', eid: eid, frobname:frobname};
+ jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
+ }
+
+In this example, the url argument is the base json url of a cube
+instance (it should contain something like
+`http://myinstance/json?`). The actual JSonController method name is
+encoded in the `params` dictionary using the `fname` key.
+
+A more real-life example from CubicWeb
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A frequent use case of Web 2 applications is the delayed (or
+on-demand) loading of pieces of the DOM. This is typically achieved
+using some preparation of the initial DOM nodes, jQuery event handling
+and proper use of loadxhtml.
+
+We present here a skeletal version of the mecanism used in CubicWeb
+and available in web/views/tabs.py, in the `LazyViewMixin` class.
+
+.. sourcecode:: python
+
+ def lazyview(self, vid, rql=None):
+ """ a lazy version of wview """
+ w = self.w
+ self._cw.add_js('cubicweb.lazy.js')
+ urlparams = {'vid' : vid, 'fname' : 'view'}
+ if rql is not None:
+ urlparams['rql'] = rql
+ w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
+ vid, xml_escape(self._cw.build_url('json', **urlparams))))
+ w(u'</div>')
+ self._cw.add_onload(u"""
+ jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
+ load_now('#lazy-%(vid)s');});"""
+ % {'event': 'load_%s' % vid, 'vid': vid})
+
+This creates a `div` with a specific event associated to it.
+
+The full version deals with:
+
+* optional parameters such as an entity eid, an rset
+
+* the ability to further reload the fragment
+
+* the ability to display a spinning wheel while the fragment is still
+ not loaded
+
+* handling of browsers that do not support ajax (search engines,
+ text-based browsers such as lynx, etc.)
+
+The javascript side is quite simple, due to loadxhtml awesomeness.
+
+.. sourcecode:: javascript
+
+ function load_now(eltsel) {
+ var lazydiv = jQuery(eltsel);
+ lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
+ }
+
+This is all significantly different of the previous `simple example`
+(albeit this example actually comes from real-life code).
+
+Notice how the `cubicweb:loadurl` is used to convey the url
+information. The base of this url is similar to the global javascript
+JSON_BASE_URL. According to the pattern described earlier,
+the `fname` parameter refers to the standard `js_view` method of the
+JSonController. This method renders an arbitrary view provided a view
+id (or `vid`) is provided, and most likely an rql expression yielding
+a result set against which a proper view instance will be selected.
+
+The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML
+in a specific cubicweb namespace. It is a means to pass information
+without breaking HTML nor XHTML compliance and without resorting to
+ungodly hacks.
+
+Given all this, it is easy to add a small nevertheless useful feature
+to force the loading of a lazy view (for instance, a very
+computation-intensive web page could be scinded into one fast-loading
+part and a delayed part).
+
+On the server side, a simple call to a javascript function is
+sufficient.
+
+.. sourcecode:: python
+
+ def forceview(self, vid):
+ """trigger an event that will force immediate loading of the view
+ on dom readyness
+ """
+ self._cw.add_onload("trigger_load('%s');" % vid)
+
+The browser-side definition follows.
+
+.. sourcecode:: javascript
+
+ function trigger_load(divid) {
+ jQuery('#lazy-' + divd).trigger('load_' + divid);
+ }
+
+
+
+
+.. XXX reloadComponent
+.. XXX userCallback / user_callback
+
+Javascript library: overview
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* jquery.* : jquery and jquery UI library
+
+* cubicweb.ajax.js : concentrates all ajax related facilities (it
+ extends jQuery with the loahxhtml function, provides a handfull of
+ high-level ajaxy operations like asyncRemoteExec, reloadComponent,
+ replacePageChunk, getDomFromResponse)
+
+* cubicweb.python.js : adds a number of practical extension to stdanrd
+ javascript objects (on Date, Array, String, some list and dictionary
+ operations), and a pythonesque way to build classes. Defines a
+ CubicWeb namespace.
+
+* cubicweb.htmlhelpers.js : a small bag of convenience functions used
+ in various other cubicweb javascript resources (baseuri, progress
+ cursor handling, popup login box, html2dom function, etc.)
+
+* cubicweb.widgets.js : provides a widget namespace and constructors
+ and helpers for various widgets (mainly facets and timeline)
+
+* cubicweb.edition.js : used by edition forms
+
+* cubicweb.preferences.js : used by the preference form
+
+* cubicweb.facets.js : used by the facets mechanism
+
+There is also javascript support for massmailing, gmap (google maps),
+fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
+AppEngine), flot (charts drawing), tabs and bookmarks.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/property.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,13 @@
+The property mecanism
+---------------------
+
+.. XXX CWProperty and co
+
+
+Property API
+~~~~~~~~~~~~
+.. XXX feed me
+
+Registering and using your own property
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. XXX feed me
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/publisher.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,65 @@
+.. _publisher:
+
+Publisher
+---------
+
+What happens when an HTTP request is issued ?
+
+The story begins with the ``CubicWebPublisher.main_publish``
+method. We do not get upper in the bootstrap process because it is
+dependant on the used HTTP library. With `twisted`_ however,
+``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the
+real entry point.
+
+.. _`twisted`: http://twistedmatrix.com/trac/
+
+What main_publish does:
+
+* get a controller id and a result set from the path (this is actually
+ delegated to the `urlpublisher` component)
+
+* the controller is then selected (if not, this is considered an
+ authorization failure and signaled as such) and called
+
+* then either a proper result is returned, in which case the
+ request/connection object issues a ``commit`` and returns the result
+
+* or error handling must happen:
+
+ * ``ValidationErrors`` pop up there and may lead to a redirect to a
+ previously arranged url or standard error handling applies
+ * an HTTP 500 error (`Internal Server Error`) is issued
+
+
+Now, let's turn to the controller. There are many of them in
+:mod:`cubicweb.web.views.basecontrollers`. We can just follow the
+default `view` controller that is selected on a `view` path. See the
+:ref:`controllers` chapter for more information on controllers.
+
+The `View` controller's entry point is the `publish` method. It does
+the following:
+
+* compute the `main` view to be applied, using either the given result
+ set or building one from a user provided rql string (`rql` and `vid`
+ can be forced from the url GET parameters), that is:
+
+ * compute the `vid` using the result set and the schema (see
+ `cubicweb.web.views.vid_from_rset`)
+ * handle all error cases that could happen in this phase
+
+* do some cache management chores
+
+* select a main template (typically `TheMainTemplate`, see chapter
+ :ref:`templates`)
+
+* call it with the result set and the computed view.
+
+What happens next actually depends on the template and the view, but
+in general this is the rendering phase.
+
+
+CubicWebPublisher API
+`````````````````````
+
+.. autoclass:: cubicweb.web.application.CubicWebPublisher
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/request.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,79 @@
+The `Request` class (`cubicweb.web`)
+------------------------------------
+
+Overview
+````````
+
+A request instance is created when an HTTP request is sent to the web server.
+It contains informations such as form parameters, user authenticated, etc.
+
+**Globally, a request represents a user query, either through HTTP or not
+(we also talk about RQL queries on the server side for example).**
+
+An instance of `Request` has the following attributes:
+
+* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated
+ user
+* `form`, dictionary containing the values of a web form
+* `encoding`, character encoding to use in the response
+
+But also:
+
+* `Session data handling`
+
+ * `session_data()`, returns a dictionary containing all the session data
+ * `get_session_data(key, default=None)`, returns a value associated to the given
+ key or the value `default` if the key is not defined
+ * `set_session_data(key, value)`, assign a value to a key
+ * `del_session_data(key)`, suppress the value associated to a key
+
+* `Cookies handling`
+
+ * `get_cookie()`, returns a dictionary containing the value of the header
+ HTTP 'Cookie'
+ * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
+ with a minimal 5 minutes length of duration by default (`maxage` = None
+ returns a *session* cookie which will expire when the user closes the browser
+ window)
+ * `remove_cookie(cookie, key)`, forces a value to expire
+
+* `URL handling`
+
+ * `url()`, returns the full URL of the HTTP request
+ * `base_url()`, returns the root URL of the web application
+ * `relative_path()`, returns the relative path of the request
+
+* `And more...`
+
+ * `set_content_type(content_type, filename=None)`, adds the header HTTP
+ 'Content-Type'
+ * `get_header(header)`, returns the value associated to an arbitrary header
+ of the HTTP request
+ * `set_header(header, value)`, adds an arbitrary header in the response
+ * `cursor()` returns a RQL cursor on the session
+ * `execute(*args, **kwargs)`, shortcut to ``.cursor().execute()``
+ * `property_value(key)`, properties management (`CWProperty`)
+ * dictionary `data` to store data to share informations between components
+ *while a request is executed*
+
+Please note that this class is abstract and that a concrete implementation
+will be provided by the *frontend* web used (in particular *twisted* as of
+today). For the views or others that are executed on the server side,
+most of the interface of `Request` is defined in the session associated
+to the client.
+
+API
+```
+
+The elements we gave in overview for above are built in three layers,
+from ``cubicweb.req.RequestSessionBase``, ``cubicweb.dbapi.DBAPIRequest`` and
+``cubicweb.web.CubicWebRequestBase``.
+
+.. autoclass:: cubicweb.req.RequestSessionBase
+ :members:
+
+.. autoclass:: cubicweb.dbapi.DBAPIRequest
+ :members:
+
+.. autoclass:: cubicweb.web.request.CubicWebRequestBase
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/rtags.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,21 @@
+Configuring the user interface
+------------------------------
+
+.. _relation_tags:
+
+Relation tags
+~~~~~~~~~~~~~
+.. automodule:: cubicweb.rtags
+
+.. _uicfg:
+
+The ``uicfg`` module
+~~~~~~~~~~~~~~~~~~~~
+
+.. note::
+
+ The part of uicfg that deals with primary views is in the
+ :ref:`primary_view_configuration` chapter.
+
+.. automodule:: cubicweb.web.uicfg
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/basetemplates.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,115 @@
+.. -*- coding: utf-8 -*-
+
+.. |cubicweb| replace:: *CubicWeb*
+
+.. _templates:
+
+Templates
+=========
+
+Templates are the entry point for the |cubicweb| view system. As seen
+in :ref:`views_base_class`, there are two kinds of views: the
+templatable and non-templatable.
+
+Non-templatable views are standalone. They are responsible for all the
+details such as setting a proper content type (or mime type), the
+proper document headers, namespaces, etc. Examples are pure xml views
+such as RSS or Semantic Web views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked
+Data`_, etc.).
+
+.. _`SIOC`: http://sioc-project.org/
+.. _`DOAP`: http://trac.usefulinc.com/doap
+.. _`FOAF`: http://www.foaf-project.org/
+.. _`Linked Data`: http://linkeddata.org/
+
+Templatable views are not concerned with such pesky details. They
+leave it to the template. Conversely, the template's main job is to:
+
+* set up the proper document header and content type
+* define the general layout of a document
+* invoke adequate views in the various sections of the document
+
+
+Look at :mod:`cubicweb.web.views.basetemplates` and you will find the
+base templates used to generate (X)HTML for your application. The most
+important template there is `TheMainTemplate`.
+
+.. _the_main_template_layout:
+
+TheMainTemplate
+---------------
+
+.. _the_main_template_sections:
+
+Layout and sections
+```````````````````
+
+A page is composed as indicated on the schema below :
+
+.. image:: ../../images/main_template.png
+
+The sections dispatches specific views:
+
+* `header`: the rendering of the header is delegated to the
+ `htmlheader` view, whose default implementation can be found in
+ ``basetemplates.py`` and which does the following things:
+
+ * inject the favicon if there is one
+ * inject the global style sheets and javascript resources
+ * call and display a link to an rss component if there is one available
+
+ it also sets up the page title, and fills the actual
+ `header` section with top-level components, using the `header` view, which:
+
+ * tries to display a logo, the name of the application and the `breadcrumbs`
+ * provides a login status area
+ * provides a login box (hiden by default)
+
+* `left column`: this is filled with all selectable boxes matching the
+ `left` context (there is also a right column but nowadays it is
+ seldom used due to bad usability)
+
+* `contentcol`: this is the central column; it is filled with:
+
+ * the `rqlinput` view (hidden by default)
+ * the `applmessages` component
+ * the `contentheader` view which in turns dispatches all available
+ content navigation components having the `navtop` context (this
+ is used to navigate through entities implementing the IPrevNext
+ interface)
+ * the view that was given as input to the template's `call`
+ method, also dealing with pagination concerns
+ * the `contentfooter`
+
+* `footer`: adds all footer actions
+
+.. note::
+
+ How and why a view object is given to the main template is explained
+ in the :ref:`publisher` chapter.
+
+Class attributes
+````````````````
+
+We can also control certain aspects of the main template thanks to the following
+forms parameters:
+
+* `__notemplate`, if present (whatever the value assigned), only the content view
+ is returned
+* `__force_display`, if present and its value is not null, no navigation
+ whatever the number of entities to display
+* `__method`, if the result set to render contains only one entity and this
+ parameter is set, it refers to a method to call on the entity by passing it
+ the dictionary of the forms parameters, before going the classic way (through
+ step 1 and 2 described juste above)
+
+Other templates
+---------------
+
+Other standard templates include:
+
+* `login` and `logout`
+
+* `error-template` specializes TheMainTemplate to do proper end-user
+ output if an error occurs during the computation of TheMainTemplate
+ (it is a fallback view).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/baseviews.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,84 @@
+.. -*- coding: utf-8 -*-
+
+Base views
+----------
+
+*CubicWeb* provides a lot of standard views, that can be found in
+ :mod:`cubicweb.web.views` and :mod:`cubicweb.web.views.baseviews`.
+
+A certain number of views are used to build the web interface, which
+apply to one or more entities. Their identifier is what distinguish
+them from each others and the main ones are:
+
+HTML views
+~~~~~~~~~~
+
+Special views
+`````````````
+
+*noresult*
+ This view is the default view used when no result has been found
+ (e.g. empty result set).
+
+*final*
+ Display the value of a cell without trasnformation (in case of a non final
+ entity, we see the eid). Applicable on any result set.
+
+.. note::
+
+ `final` entities are merely attributes.
+
+*null*
+ This view is the default view used when nothing needs to be rendered.
+ It is always applicable.
+
+Entity views
+````````````
+
+*incontext, outofcontext*
+ Those are used to display a link to an entity, depending on the
+ entity having to be displayed in or out of context
+ (of another entity). By default it respectively produces the
+ result of `textincontext` and `textoutofcontext` wrapped in a link
+ leading to the primary view of the entity.
+
+*oneline*
+ This view is used when we can't tell if the entity should be considered as
+ displayed in or out of context. By default it produces the result of `text`
+ in a link leading to the primary view of the entity.
+
+List
+`````
+
+*list*
+ This view displays a list of entities by creating a HTML list (`<ul>`)
+ and call the view `listitem` for each entity of the result set.
+
+*listitem*
+ This view redirects by default to the `outofcontext` view.
+
+*sameetypelist*
+ This view displays a list of entities of the same type, in HTML section (`<div>`)
+ and call the view `sameetypelistitem` for each entity of the result set.
+
+*sameetypelistitem*
+ This view redirects by default to the `listitem` view.
+
+*csv*
+ This view applies to entity groups, which are individually
+ displayed using the `incontext` view. It displays each entity as a
+ coma separated list. It is NOT related to the well-known text file
+ format.
+
+Text entity views
+~~~~~~~~~~~~~~~~~
+
+*text*
+ This is the simplest text view for an entity. By default it returns the
+ result of the `.dc_title` method, which is cut to fit the
+ `navigation.short-line-size` property if necessary.
+
+*textincontext, textoutofcontext*
+ Similar to the `text` view, but called when an entity is considered out or
+ in context. By default it returns respectively the result of the
+ methods `.dc_title` and `.dc_long_title` of the entity.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/boxes.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,36 @@
+Boxes
+-----
+
+(:mod:`cubicweb.web.views.boxes`)
+
+*sidebox*
+ This view displays usually a side box of some related entities
+ in a primary view.
+
+The action box
+~~~~~~~~~~~~~~~
+
+The ``add_related`` is an automatic menu in the action box that allows to create
+an entity automatically related to the initial entity (context in
+which the box is displayed). By default, the links generated in this
+box are computed from the schema properties of the displayed entity,
+but it is possible to explicitly specify them thanks to the
+`cubicweb.web.uicfg.rmode` *relation tag*:
+
+* `link`, indicates that a relation is in general created pointing
+ to an existing entity and that we should not to display a link
+ for this relation
+
+* `create`, indicates that a relation is in general created pointing
+ to new entities and that we should display a link to create a new
+ entity and link to it automatically
+
+
+If necessary, it is possible to overwrite the method
+`relation_mode(rtype, targettype, x='subject')` to dynamically
+compute a relation creation category.
+
+Please note that if at least one action belongs to the `addrelated` category,
+the automatic behavior is desactivated in favor of an explicit behavior
+(e.g. display of `addrelated` category actions only).
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/breadcrumbs.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,58 @@
+Breadcrumbs
+-----------
+
+Breadcrumbs are a navigation component to help the user locate himself
+along a path of entities.
+
+Display
+~~~~~~~
+
+Breadcrumbs are displayed by default in the header section (see
+:ref:`the_main_template_sections`). With the default main
+template, the header section is composed by the logo, the application
+name, breadcrumbs and, at the most right, the login box. Breadcrumbs
+are displayed just next to the application name, thus breadcrumbs
+begin with a separator.
+
+Here is the header section of the CubicWeb's forge:
+
+.. image:: ../../images/breadcrumbs_header.png
+
+There are three breadcrumbs components defined in
+:mod:`cubicweb.web.views.ibreadcrumbs`:
+
+- `BreadCrumbEntityVComponent`: displayed for a result set with one line
+ if the entity implements the ``IBreadCrumbs`` interface.
+- `BreadCrumbETypeVComponent`: displayed for a result set with more than
+ one line, but with all entities of the same type which implement the
+ ``IBreadCrumbs`` interface.
+- `BreadCrumbAnyRSetVComponent`: displayed for any other result set.
+
+Building breadcrumbs
+~~~~~~~~~~~~~~~~~~~~
+
+The ``IBreadCrumbs`` interface is defined in the
+:mod:`cubicweb.interfaces` module. It specifies that an entity which
+implements this interface must have a ``breadcrumbs`` method.
+
+.. note::
+
+ Redefining the breadcrumbs is the hammer way to do it. Another way
+ is to define the `parent` method on an entity (as defined in the
+ `ITree` interface). If available, it will be used to compute
+ breadcrumbs.
+
+Here is the API of the ``breadcrumbs`` method:
+
+.. automethod:: cubicweb.interfaces.IBreadCrumbs.breadcrumbs
+
+If the breadcrumbs method return a list of entities, the
+``cubicweb.web.views.ibreadcrumbs.BreadCrumbView`` is used to display
+the elements.
+
+By default, for any entity, if recurs=True, breadcrumbs method returns
+a list of entities, else a list of a simple string.
+
+In order to see a hierarchical breadcrumbs, entities must have a
+``parent`` method which returns the parent entity. By default this
+method doesn't exist on entity, given that it can not be guessed.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/editforms.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,6 @@
+Standard forms
+--------------
+
+ (:mod:`cubicweb.web.views.editforms`)
+
+XXX feed me
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/embedding.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Embedding external pages
+------------------------
+
+(:mod:`cubicweb.web.views.embedding`)
+
+including external content
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/idownloadable.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,5 @@
+The 'download' view
+-------------------
+
+(:mod:`cubicweb.web.views.idownloadable`)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,30 @@
+The View system
+===============
+
+This chapter aims to describe the concept of a `view` used all along
+the development of a web application and how it has been implemented
+in |cubicweb|.
+
+
+.. toctree::
+ :maxdepth: 3
+
+ views
+ basetemplates
+ primary
+ baseviews
+ startup
+ boxes
+ table
+ xmlrss
+.. editforms
+
+.. toctree::
+ :maxdepth: 3
+
+ urlpublish
+ breadcrumbs
+.. wdoc
+.. embedding
+.. idownloadable
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/primary.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,314 @@
+.. _primary_view:
+
+The Primary View
+-----------------
+
+By default, *CubicWeb* provides a view that fits every available
+entity type. This is the first view you might be interested in
+modifying. It is also one of the richest and most complex.
+
+It is automatically selected on a one line result set containing an
+entity.
+
+This view is supposed to render a maximum of informations about the
+entity.
+
+It lives in the :mod:`cubicweb.web.views.primary` module.
+
+.. _primary_view_layout:
+
+Layout
+``````
+
+The primary view has the following layout.
+
+.. image:: ../../images/primaryview_template.png
+
+.. _primary_view_configuration:
+
+Primary view configuration
+``````````````````````````
+
+If you want to customize the primary view of an entity, overriding the primary
+view class may not be necessary. For simple adjustments (attributes or relations
+display locations and styles), a much simpler way is to use uicfg.
+
+Attributes/relations display location
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the primary view, there are 3 sections where attributes and
+relations can be displayed (represented in pink in the image above):
+
+* attributes
+* relations
+* sideboxes
+
+**Attributes** can only be displayed in the attributes section (default
+ behavior). They can also be hidden.
+
+For instance, to hide the ``title`` attribute of the ``Blog`` entity:
+
+.. sourcecode:: python
+
+ from cubicweb.web import uicfg
+ uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
+
+**Relations** can be either displayed in one of the three sections or hidden.
+
+For relations, there are two methods:
+
+* ``tag_object_of`` for modifying the primary view of the object
+* ``tag_subject_of`` for modifying the primary view of the subject
+
+These two methods take two arguments:
+
+* a triplet ``(subject, relation_name, object)``, where subject or object can be replaced with ``'*'``
+* the section name or ``hidden``
+
+.. sourcecode:: python
+
+ pv_section = uicfg.primaryview_section
+ # hide every relation `entry_of` in the `Blog` primary view
+ pv_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
+
+ # display `entry_of` relations in the `relations`
+ # section in the `BlogEntry` primary view
+ pv_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations')
+
+
+Display content
+^^^^^^^^^^^^^^^
+
+You can use ``primaryview_display_ctrl`` to customize the display of attributes
+or relations. Values of ``primaryview_display_ctrl`` are dictionaries.
+
+
+Common keys for attributes and relations are:
+
+* ``vid``: specifies the regid of the view for displaying the attribute or the relation.
+
+ If ``vid`` is not specified, the default value depends on the section:
+ * ``attributes`` section: 'reledit' view
+ * ``relations`` section: 'autolimited' view
+ * ``sideboxes`` section: 'sidebox' view
+
+* ``order``: int used to control order within a section. When not specified,
+ automatically set according to order in which tags are added.
+
+.. sourcecode:: python
+
+ # let us remind the schema of a blog entry
+ class BlogEntry(EntityType):
+ title = String(required=True, fulltextindexed=True, maxsize=256)
+ publish_date = Date(default='TODAY')
+ content = String(required=True, fulltextindexed=True)
+ entry_of = SubjectRelation('Blog', cardinality='?*')
+
+ # now, we want to show attributes
+ # with an order different from that in the schema definition
+ view_ctrl = uicfg.primaryview_display_ctrl
+ for index, attr in enumerate('title', 'content', 'publish_date'):
+ view_ctrl.tag_attribute(('BlogEntry', attr), {'order': index})
+
+Keys for relations only:
+
+* ``label``: label for the relations section or side box
+
+* ``showlabel``: boolean telling whether the label is displayed
+
+* ``limit``: boolean telling if the results should be limited. If so, a link to all results is displayed
+
+* ``filter``: callback taking the related result set as argument and returning it filtered
+
+.. sourcecode:: python
+
+ pv_section = uicfg.primaryview_section
+ # in `CWUser` primary view, display `created_by`
+ # relations in relations section
+ pv_section.tag_object_of(('*', 'created_by', 'CWUser'), 'relations')
+
+ # display this relation as a list, sets the label,
+ # limit the number of results and filters on comments
+ def filter_comment(rset):
+ return rset.filtered_rset(lambda x: x.e_schema == 'Comment')
+ pv_ctrl = uicfg.primaryview_display_ctrl
+ pv_ctrl.tag_object_of(('*', 'created_by', 'CWUser'),
+ {'vid': 'list', 'label': _('latest comment(s):'),
+ 'limit': True,
+ 'filter': filter_comment})
+
+.. warning:: with the ``primaryview_display_ctrl`` rtag, the subject or the
+ object of the relation is ignored for respectively ``tag_object_of`` or
+ ``tag_subject_of``. To avoid warnings during execution, they should be set to
+ ``'*'``.
+
+Rendering methods and attributes
+````````````````````````````````
+
+The basic layout of a primary view is as in the
+:ref:`primary_view_layout` section. This layout is actually drawn by
+the `render_entity` method.
+
+The methods you may want to modify while customizing a ``PrimaryView``
+are:
+
+*render_entity_title(self, entity)*
+ Renders the entity title using the ``def dc_title(self)`` method.
+
+*render_entity_metadata(self, entity)*
+ Renders the entity metadata by calling the ``metadata`` view on the
+ entity. This generic view is in cubicweb.views.baseviews.
+
+*render_entity_attributes(self, entity)*
+ Renders all the attribute of an entity with the exception of
+ attribute of type `Password` and `Bytes`. The skip_none class
+ attribute controls the display of None valued attributes.
+
+*render_entity_relations(self, entity)*
+ Renders all the relations of the entity in the main section of the page.
+
+*render_side_boxes(self, entity, boxes)*
+ Renders relations of the entity in a side box.
+
+The placement of relations in the relations section or in side boxes
+can be controlled through the :ref:`primary_view_configuration` mechanism.
+
+*content_navigation_components(self, context)*
+ This method is applicable only for entity type implementing the interface
+ `IPrevNext`. This interface is for entities which can be linked to a previous
+ and/or next entity. This method will render the navigation links between
+ entities of this type, either at the top or at the bottom of the page
+ given the context (navcontent{top|bottom}).
+
+Also, please note that by setting the following attributes in your
+subclass, you can already customize some of the rendering:
+
+*show_attr_label*
+ Renders the attribute label next to the attribute value if set to True.
+ Otherwise, does only display the attribute value.
+
+*show_rel_label*
+ Renders the relation label next to the relation value if set to True.
+ Otherwise, does only display the relation value.
+
+*skip_none*
+ Does not render an attribute value that is None if set to True.
+
+*main_related_section*
+ Renders the relations of the entity if set to True.
+
+A good practice is for you to identify the content of your entity type for which
+the default rendering does not answer your need so that you can focus on the specific
+method (from the list above) that needs to be modified. We do not advise you to
+overwrite ``render_entity`` unless you want a completely different layout.
+
+Example of customization and creation
+`````````````````````````````````````
+
+We'll show you now an example of a ``primary`` view and how to customize it.
+
+We continue along the basic tutorial :ref:`tuto_blog`.
+
+If you want to change the way a ``BlogEntry`` is displayed, just
+override the method ``cell_call()`` of the view ``primary`` in
+``BlogDemo/views.py``.
+
+.. sourcecode:: python
+
+ from cubicweb.selectors import implements
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogEntryPrimaryView(PrimaryView):
+ __select__ = PrimaryView.__select__ & implements('BlogEntry')
+
+ def render_entity_attributes(self, entity):
+ self.w(u'<p>published on %s</p>' %
+ entity.publish_date.strftime('%Y-%m-%d'))
+ super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
+
+
+The above source code defines a new primary view for
+``BlogEntry``. The `id` class attribute is not repeated there since it
+is inherited through the `primary.PrimaryView` class.
+
+The selector for this view chains the selector of the inherited class
+with its own specific criterion.
+
+The view method ``self.w()`` is used to output data. Here `lines
+08-09` output HTML for the publication date of the entry.
+
+.. image:: ../../images/lax-book_09-new-view-blogentry_en.png
+ :alt: blog entries now look much nicer
+
+Let us now improve the primary view of a blog
+
+.. sourcecode:: python
+
+ from logilab.mtconverter import xml_escape
+ from cubicweb.selectors import implements, one_line_rset
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogPrimaryView(PrimaryView):
+ __regid__ = 'primary'
+ __select__ = PrimaryView.__select__ & implements('Blog')
+ rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
+
+ def render_entity_relations(self, entity):
+ rset = self._cw.execute(self.rql, {'b' : entity.eid})
+ for entry in rset.entities():
+ self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
+
+ class BlogEntryInBlogView(EntityView):
+ __regid__ = 'inblogcontext'
+ __select__ = implements('BlogEntry')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w(u'<a href="%s" title="%s">%s</a>' %
+ entity.absolute_url(),
+ xml_escape(entity.content[:50]),
+ xml_escape(entity.description))
+
+This happens in two places. First we override the
+render_entity_relations method of a Blog's primary view. Here we want
+to display our blog entries in a custom way.
+
+At `line 10`, a simple request is made to build a result set with all
+the entities linked to the current ``Blog`` entity by the relationship
+``entry_of``. The part of the framework handling the request knows
+about the schema and infers that such entities have to be of the
+``BlogEntry`` kind and retrieves them (in the prescribed publish_date
+order).
+
+The request returns a selection of data called a result set. Result
+set objects have an .entities() method returning a generator on
+requested entities (going transparently through the `ORM` layer).
+
+At `line 13` the view 'inblogcontext' is applied to each blog entry to
+output HTML. (Note that the 'inblogcontext' view is not defined
+whatsoever in *CubicWeb*. You are absolutely free to define whole view
+families.) We juste arrange to wrap each blogentry output in a 'p'
+html element.
+
+Next, we define the 'inblogcontext' view. This is NOT a primary view,
+with its well-defined sections (title, metadata, attribtues,
+relations/boxes). All a basic view has to define is cell_call.
+
+Since views are applied to result sets which can be tables of data, we
+have to recover the entity from its (row,col)-coordinates (`line
+20`). Then we can spit some HTML.
+
+.. warning::
+
+ Be careful: all strings manipulated in *CubicWeb* are actually
+ unicode strings. While web browsers are usually tolerant to
+ incoherent encodings they are being served, we should not abuse
+ it. Hence we have to properly escape our data. The xml_escape()
+ function has to be used to safely fill (X)HTML elements from Python
+ unicode strings.
+
+Assuming we added entries to the blog titled `MyLife`, displaying it
+now allows to read its description and all its entries.
+
+.. image:: ../../images/lax-book_10-blog-with-two-entries_en.png
+ :alt: a blog and all its entries
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/startup.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,15 @@
+Startup views
+-------------
+
+(:mod:`cubicweb.web.views.startup`)
+
+The usual selectors are no_rset or yes. These views don't apply to a
+result set.
+
+*index*
+ This view defines the home page of your application. It does not require
+ a result set to apply to.
+
+*schema*
+ A view dedicated to the display of the schema of the instance
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/table.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,19 @@
+Table view
+----------
+
+(:mod:`cubicweb.web.views.tableview`)
+
+*table*
+ Creates a HTML table (`<table>`) and call the view `cell` for each cell of
+ the result set. Applicable on any result set.
+
+*cell*
+ By default redirects to the `final` view if this is a final entity or
+ `outofcontext` view otherwise
+
+
+API
+```
+
+.. autoclass:: cubicweb.web.views.tableview.TableView
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/urlpublish.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,73 @@
+.. -*- coding: utf-8 -*-
+
+URL publishing
+--------------
+
+(:mod:`cubicweb.web.views.urlpublishing`)
+
+.. automodule:: cubicweb.web.views.urlpublishing
+
+.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent
+ :members:
+
+URL rewriting
+-------------
+
+(:mod:`cubicweb.web.views.urlrewrite`)
+
+.. autoclass:: cubicweb.web.views.urlrewrite.URLRewriter
+ :members:
+
+.. autoclass:: cubicweb.web.views.urlrewrite.SimpleReqRewriter
+ :members:
+
+.. autoclass:: cubicweb.web.views.urlrewrite.SchemaBasedRewriter
+ :members:
+
+
+``SimpleReqRewriter`` is enough for a certain number of simple cases. If it is not sufficient, ``SchemaBasedRewriter`` allows to do more elaborate things.
+
+Here is an example of ``SimpleReqRewriter`` usage with plain string:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.urlrewrite import SimpleReqRewriter
+ class TrackerSimpleReqRewriter(SimpleReqRewriter):
+ rules = [
+ ('/versions', dict(vid='versionsinfo')),
+ ]
+
+When the url is `<base_url>/versions`, the view with the __regid__ `versionsinfo` is displayed.
+
+Here is an example of ``SimpleReqRewriter`` usage with regular expressions:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.urlrewrite import (
+ SimpleReqRewriter, rgx)
+
+ class BlogReqRewriter(SimpleReqRewriter):
+ rules = [
+ (rgx('/blogentry/([a-z_]+)\.rss'),
+ dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
+ 'X creation_date CD, X created_by U, '
+ 'U login "%(user)s"'
+ % {'user': r'\1'}, vid='rss'))),
+ ]
+
+When a url matches the regular expression, the view with the __regid__
+`rss` which match the result set is displayed.
+
+Here is an example of ``SchemaBasedRewriter`` usage:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.urlrewrite import (
+ SchemaBasedRewriter, rgx, build_rset)
+
+ class TrackerURLRewriter(SchemaBasedRewriter):
+ rules = [
+ (rgx('/project/([^/]+)/([^/]+)/tests'),
+ build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
+ rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
+ ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/views.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,142 @@
+
+.. _Views:
+
+Principles
+----------
+
+We'll start with a description of the interface providing a basic
+understanding of the available classes and methods, then detail the
+view selection principle.
+
+A `View` is an object responsible for the rendering of data from the
+model into an end-user consummable form. They typically churn out an
+XHTML stream, but there are views concerned with email other non-html
+outputs.
+
+.. _views_base_class:
+
+Discovering possible views
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is possible to configure the web user interface to have a left box
+showing all the views than can be applied to the current result set.
+
+To enable this, click on your login at the top right corner. Chose
+"user preferences", then "boxes", then "possible views box" and check
+"visible = yes" before validating your changes.
+
+The views listed there we either not selected because of a lower
+score, or they were deliberately excluded by the main template logic.
+
+
+Basic class for views
+~~~~~~~~~~~~~~~~~~~~~
+
+Class `View` (`cubicweb.view`)
+```````````````````````````````
+
+This class is an abstraction of a view class, used as a base class for
+every renderable object such as views, templates and other user
+interface components.
+
+A `View` is instantiated to render a result set or part of a result
+set. `View` subclasses may be parametrized using the following class
+attributes:
+
+* `templatable` indicates if the view may be embedded in a main
+ template or if it has to be rendered standalone (i.e. pure XML views
+ must not be embedded in the main template of HTML pages)
+
+* if the view is not templatable, it should set the `content_type`
+ class attribute to the correct MIME type (text/xhtml being the
+ default)
+
+* the `category` attribute may be used in the interface to regroup
+ related view kinds together
+
+A view writes to its output stream thanks to its attribute `w` (the
+append method of an `UStreamIO`, except for binary views).
+
+At instantiation time, the standard `_cw` and `cw_rset` attributes are
+added and the `w` attribute will be set at rendering time.
+
+The basic interface for views is as follows (remember that the result
+set has a tabular structure with rows and columns, hence cells):
+
+* `render(**context)`, render the view by calling `call` or
+ `cell_call` depending on the context
+
+* `call(**kwargs)`, call the view for a complete result set or null
+ (the default implementation calls `cell_call()` on each cell of the
+ result set)
+
+* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
+ result set (`row` and `col` being integers used to access the cell)
+
+* `url()`, returns the URL enabling us to get the view with the current
+ result set
+
+* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of
+ identifier `__vid` on the given result set. It is possible to give a
+ fallback view identifier that will be used if the requested view is
+ not applicable to the result set.
+
+* `html_headers()`, returns a list of HTML headers to be set by the
+ main template
+
+* `page_title()`, returns the title to use in the HTML header `title`
+
+Other basic view classes
+````````````````````````
+Here are some of the subclasses of `View` defined in `cubicweb.common.view`
+that are more concrete as they relate to data rendering within the application:
+
+* `EntityView`, view applying to lines or cell containing an entity (e.g. an eid)
+* `StartupView`, start view that does not require a result set to apply to
+* `AnyRsetView`, view applicable to any result set
+
+Examples of views class
+```````````````````````
+
+- Using `templatable`, `content_type` and HTTP cache configuration
+
+.. sourcecode:: python
+
+ class RSSView(XMLView):
+ __regid__ = 'rss'
+ title = _('rss')
+ templatable = False
+ content_type = 'text/xml'
+ http_cache_manager = MaxAgeHTTPCacheManager
+ cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
+
+- Using a custom selector
+
+.. sourcecode:: python
+
+ class SearchForAssociationView(EntityView):
+ """view called by the edition view when the user asks
+ to search for something to link to the edited eid
+ """
+ __regid__ = 'search-associate'
+ title = _('search for association')
+ __select__ = one_line_rset() & match_search_state('linksearch') & implements('Any')
+
+
+XML views, binaries views...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For views generating other formats than HTML (an image generated dynamically
+for example), and which can not simply be included in the HTML page generated
+by the main template (see above), you have to:
+
+* set the attribute `templatable` of the class to `False`
+* set, through the attribute `content_type` of the class, the MIME
+ type generated by the view to `application/octet-stream` or any
+ relevant and more specialised mime type
+
+For views dedicated to binary content creation (like dynamically generated
+images), we have to set the attribute `binary` of the class to `True` (which
+implies that `templatable == False`, so that the attribute `w` of the view could be
+replaced by a binary flow instead of unicode).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/wdoc.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Online documentation system
+---------------------------
+
+(:mod:`cubicweb.web.views.wdoc`)
+
+XXX describe the on-line documentation system
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/devweb/views/xmlrss.rst Mon Apr 26 12:52:48 2010 +0200
@@ -0,0 +1,60 @@
+.. _XmlAndRss:
+
+XML and RSS views
+-----------------
+
+(:mod:`cubicweb.web.views.xmlrss`)
+
+Overview
++++++++++
+
+*rss*
+ Creates a RSS/XML view and call the view `rssitem` for each entity of
+ the result set.
+
+*rssitem*
+ Create a RSS/XML view for each entity based on the results of the dublin core
+ methods of the entity (`dc_*`)
+
+RSS Channel Example
+++++++++++++++++++++
+
+Assuming you have several blog entries, click on the title of the
+search box in the left column. A larger search box should appear. Enter::
+
+ Any X ORDERBY D WHERE X is BlogEntry, X creation_date D
+
+and you get a list of blog entries.
+
+Click on your login at the top right corner. Chose "user preferences",
+then "boxes", then "possible views box" and check "visible = yes"
+before validating your changes.
+
+Enter the same query in the search box and you will see the same list,
+plus a box titled "possible views" in the left column. Click on
+"entityview", then "RSS".
+
+You just applied the "RSS" view to the RQL selection you requested.
+
+That's it, you have a RSS channel for your blog.
+
+Try again with::
+
+ Any X ORDERBY D WHERE X is BlogEntry, X creation_date D,
+ X entry_of B, B title "MyLife"
+
+Another RSS channel, but a bit more focused.
+
+A last one for the road::
+
+ Any C ORDERBY D WHERE C is Comment, C creation_date D LIMIT 15
+
+displayed with the RSS view, that's a channel for the last fifteen
+comments posted.
+
+[WRITE ME]
+
+* show that the RSS view can be used to display an ordered selection
+ of blog entries, thus providing a RSS channel
+
+* show that a different selection (by category) means a different channel
Binary file doc/book/en/images/03-transitions-view.en.png has changed
Binary file doc/book/en/images/03-transitions-view_en.png has changed
Binary file doc/book/en/images/archi_globale.en.png has changed
Binary file doc/book/en/images/archi_globale_en.png has changed
Binary file doc/book/en/images/cbw-add-relation-entryof.en.png has changed
Binary file doc/book/en/images/cbw-add-relation-entryof_en.png has changed
Binary file doc/book/en/images/cbw-create-blog.en.png has changed
Binary file doc/book/en/images/cbw-create-blog_en.png has changed
Binary file doc/book/en/images/cbw-detail-one-blogentry.en.png has changed
Binary file doc/book/en/images/cbw-detail-one-blogentry_en.png has changed
Binary file doc/book/en/images/cbw-list-one-blog.en.png has changed
Binary file doc/book/en/images/cbw-list-one-blog_en.png has changed
Binary file doc/book/en/images/cbw-list-two-blog.en.png has changed
Binary file doc/book/en/images/cbw-list-two-blog_en.png has changed
Binary file doc/book/en/images/cbw-schema.en.png has changed
Binary file doc/book/en/images/cbw-schema_en.png has changed
Binary file doc/book/en/images/cbw-update-primary-view.en.png has changed
Binary file doc/book/en/images/cbw-update-primary-view_en.png has changed
Binary file doc/book/en/images/lax-book.00-login.en.png has changed
Binary file doc/book/en/images/lax-book.01-start.en.png has changed
Binary file doc/book/en/images/lax-book.02-cookie-values.en.png has changed
Binary file doc/book/en/images/lax-book.02-create-blog.en.png has changed
Binary file doc/book/en/images/lax-book.03-list-one-blog.en.png has changed
Binary file doc/book/en/images/lax-book.03-site-config-panel.en.png has changed
Binary file doc/book/en/images/lax-book.03-state-submitted.en.png has changed
Binary file doc/book/en/images/lax-book.03-transitions-view.en.png has changed
Binary file doc/book/en/images/lax-book.04-detail-one-blog.en.png has changed
Binary file doc/book/en/images/lax-book.05-list-two-blog.en.png has changed
Binary file doc/book/en/images/lax-book.06-add-relation-entryof.en.png has changed
Binary file doc/book/en/images/lax-book.06-header-no-login.en.png has changed
Binary file doc/book/en/images/lax-book.06-main-template-layout.en.png has changed
Binary file doc/book/en/images/lax-book.06-main-template-logo.en.png has changed
Binary file doc/book/en/images/lax-book.06-simple-main-template.en.png has changed
Binary file doc/book/en/images/lax-book.07-detail-one-blogentry.en.png has changed
Binary file doc/book/en/images/lax-book.08-schema.en.png has changed
Binary file doc/book/en/images/lax-book.09-new-view-blogentry.en.png has changed
Binary file doc/book/en/images/lax-book.10-blog-with-two-entries.en.png has changed
Binary file doc/book/en/images/lax-book_00-login_en.png has changed
Binary file doc/book/en/images/lax-book_01-start_en.png has changed
Binary file doc/book/en/images/lax-book_02-cookie-values_en.png has changed
Binary file doc/book/en/images/lax-book_02-create-blog_en.png has changed
Binary file doc/book/en/images/lax-book_03-list-one-blog_en.png has changed
Binary file doc/book/en/images/lax-book_03-site-config-panel_en.png has changed
Binary file doc/book/en/images/lax-book_03-state-submitted_en.png has changed
Binary file doc/book/en/images/lax-book_03-transitions-view_en.png has changed
Binary file doc/book/en/images/lax-book_04-detail-one-blog_en.png has changed
Binary file doc/book/en/images/lax-book_05-list-two-blog_en.png has changed
Binary file doc/book/en/images/lax-book_06-add-relation-entryof_en.png has changed
Binary file doc/book/en/images/lax-book_06-header-no-login_en.png has changed
Binary file doc/book/en/images/lax-book_06-main-template-layout_en.png has changed
Binary file doc/book/en/images/lax-book_06-main-template-logo_en.png has changed
Binary file doc/book/en/images/lax-book_06-simple-main-template_en.png has changed
Binary file doc/book/en/images/lax-book_07-detail-one-blogentry_en.png has changed
Binary file doc/book/en/images/lax-book_08-schema_en.png has changed
Binary file doc/book/en/images/lax-book_09-new-view-blogentry_en.png has changed
Binary file doc/book/en/images/lax-book_10-blog-with-two-entries_en.png has changed
--- a/doc/book/en/index.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/index.rst Mon Apr 26 12:52:48 2010 +0200
@@ -40,9 +40,6 @@
.. _`mailing-list`: http://lists.cubicweb.org/mailman/listinfo/cubicweb
.. _blog: http://www.cubicweb.org/blog/1238
-Table of Contents
-=================
-
.. toctree::
:maxdepth: 2
@@ -52,7 +49,8 @@
.. toctree::
:maxdepth: 3
- development/index
+ devrepo/index
+ devweb/index
.. toctree::
:maxdepth: 2
--- a/doc/book/en/intro/concepts.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/intro/concepts.rst Mon Apr 26 12:52:48 2010 +0200
@@ -16,8 +16,8 @@
-----
A cube is a software component made of three parts: its data model
-(:file:`schema`), its logic (:file:`entities`) and its user interface
-(:file:`views`).
+(:mod:`schema`), its logic (:mod:`entities`) and its user interface
+(:mod:`views`).
A cube can use other cubes as building blocks and assemble them to provide a
whole with richer functionnalities than its parts. The cubes `cubicweb-blog`_ and
@@ -59,7 +59,7 @@
repository. For applications that support high traffic, several web (front-end)
and data (back-end) instances can be set-up to share the load.
-.. image:: ../images/archi_globale.en.png
+.. image:: ../images/archi_globale_en.png
The command :command:`cubicweb-ctl list` also displays the list of instances
installed on your system.
@@ -70,7 +70,7 @@
environment variable.
-.. Note::
+.. note::
The term application is used to refer to "something that should do something as
a whole", eg more like a project and so can refer to an instance or to a cube,
@@ -101,14 +101,14 @@
repository side, you can for instance by-pass security checks, which isn't
possible from client code.
-Some logic can be attached to events that happen in the repository, like
-creation of entities, deletion of relations, etc. This is used for example to
-send email notifications when the state of an object changes. See :ref:`HookIntro` below.
+Some logic can be attached to events that happen in the repository,
+like creation of entities, deletion of relations, etc. This is used
+for example to send email notifications when the state of an object
+changes. See :ref:`HookIntro` below.
.. [1] not to be confused with a Mercurial repository or a Debian repository.
.. _`Python Remote Objects`: http://pyro.sourceforge.net/
-
.. _WebEngineIntro:
Web Engine
@@ -237,11 +237,11 @@
The RQL query language
----------------------
-**No need for a complicated ORM when you have a powerful data
- manipulation language**
+No need for a complicated ORM when you have a powerful data
+manipulation language.
-All the persistent data in a |cubicweb| instance is retrieved and modified by
-using the Relation Query Language.
+All the persistent data in a |cubicweb| instance is retrieved and
+modified using RQL (see :ref:`rql_intro`).
This query language is inspired by SQL but is on a higher level in order to
emphasize browsing relations.
@@ -252,6 +252,8 @@
The repository exposes a `db-api`_ like api but using the RQL instead of SQL.
+.. _`db-api`: http://www.python.org/dev/peps/pep-0249/
+
You basically get a connection using :func:`cubicweb.dbapi.connect` , then
get a cursor to call its `execute` method which will return result set for the
given rql query.
@@ -336,8 +338,6 @@
Hooks and operation are an essential building block of any moderately complicated
cubicweb application.
-.. Note:
+.. note::
RQL queries executed in hooks and operations are *unsafe* by default, e.g. the
read and write security is deactivated unless explicitly asked.
-
-.. |cubicweb| replace:: *CubicWeb*
--- a/doc/book/en/tutorials/base/create-cube.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/tutorials/base/create-cube.rst Mon Apr 26 12:52:48 2010 +0200
@@ -174,7 +174,7 @@
``everything about technology`` as the description, then validate the form by
clicking on ``Validate``.
-.. image:: ../../images/cbw-create-blog.en.png
+.. image:: ../../images/cbw-create-blog_en.png
:alt: from to create blog
Click on the logo at top left to get back to the home page, then
@@ -182,7 +182,7 @@
You should be seeing a list with a single item ``Tech-blog`` you
just created.
-.. image:: ../../images/cbw-list-one-blog.en.png
+.. image:: ../../images/cbw-list-one-blog_en.png
:alt: displaying a list of a single blog
Clicking on this item will get you to its detailed description except
@@ -194,7 +194,7 @@
again to follow the Blog link for the second time. The list now
has two items.
-.. image:: ../../images/cbw-list-two-blog.en.png
+.. image:: ../../images/cbw-list-two-blog_en.png
:alt: displaying a list of two blogs
Add a BlogEntry
@@ -215,21 +215,21 @@
combobox titled ``add relation`` would have showed up.
-.. image:: ../../images/cbw-add-relation-entryof.en.png
+.. image:: ../../images/cbw-add-relation-entryof_en.png
:alt: editing a blog entry to add a relation to a blog
Validate the changes by clicking ``Validate``. The entity BlogEntry
that is displayed now includes a link to the entity Blog named
``MyLife``.
-.. image:: ../../images/cbw-detail-one-blogentry.en.png
+.. image:: ../../images/cbw-detail-one-blogentry_en.png
:alt: displaying the detailed view of a blogentry
Note that all of this was handled by the framework and that the only input
that was provided so far is the schema. To get a graphical view of the schema,
point your browser to the URL http://localhost:8080/schema
-.. image:: ../../images/cbw-schema.en.png
+.. image:: ../../images/cbw-schema_en.png
:alt: graphical view of the schema (aka data-model)
@@ -325,7 +325,7 @@
You can now see that the publication date has a prefix.
-.. image:: ../../images/cbw-update-primary-view.en.png
+.. image:: ../../images/cbw-update-primary-view_en.png
:alt: modified primary view
--- a/doc/book/en/tutorials/base/maintemplate.rst Fri Apr 23 13:36:43 2010 +0200
+++ b/doc/book/en/tutorials/base/maintemplate.rst Mon Apr 26 12:52:48 2010 +0200
@@ -8,7 +8,7 @@
A page is composed as indicated on the schema below:
-.. image:: ../../images/lax-book.06-main-template-layout.en.png
+.. image:: ../../images/lax-book_06-main-template-layout_en.png
In this section we will demonstrate a change in one of the main
interesting template from the three you will look for,
@@ -83,7 +83,7 @@
-.. image:: ../../images/lax-book.06-header-no-login.en.png
+.. image:: ../../images/lax-book_06-header-no-login_en.png
Customize footer
````````````````
@@ -121,7 +121,7 @@
be used based on TheMainTemplate called SimpleMainTemplate which does not have
a top section.
-.. image:: ../../images/lax-book.06-simple-main-template.en.png
+.. image:: ../../images/lax-book_06-simple-main-template_en.png
XXX
[WRITE ME]
--- a/server/migractions.py Fri Apr 23 13:36:43 2010 +0200
+++ b/server/migractions.py Mon Apr 26 12:52:48 2010 +0200
@@ -116,10 +116,10 @@
return super(ServerMigrationHelper, self).cmd_process_script(
migrscript, funcname, *args, **kwargs)
else:
- print
- print ('-> ignoring %s, only .py .sql and .txt scripts are considered' %
+ print >> sys.stderr
+ print >> sys.stderr, ('-> ignoring %s, only .py .sql and .txt scripts are considered' %
migrscript)
- print
+ print >> sys.stderr
self.commit()
except:
self.rollback()
--- a/web/views/baseviews.py Fri Apr 23 13:36:43 2010 +0200
+++ b/web/views/baseviews.py Mon Apr 26 12:52:48 2010 +0200
@@ -311,7 +311,8 @@
def call(self, **kwargs):
"""display a list of entities by calling their <item_vid> view"""
- if not 'vtitle' in self._cw.form:
+ showtitle = kwargs.pop('showtitle', not 'vtitle' in self._cw.form)
+ if showtitle:
self.w(u'<h1>%s</h1>' % self.title)
super(SameETypeListView, self).call(**kwargs)