--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/01-intro.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,85 @@
+.. -*- coding: utf-8 -*-
+
+Introduction
+============
+
+This book uses version 0.4.0 of `LAX`.
+
+What is `LAX` ?
+----------------
+
+`LAX` stands for `Logilab Appengine eXtension`. It is a web application framework
+based on `Google AppEngine`.
+
+`LAX` is a port of the web framework Logilab_ has been developping since 2001.
+This framework originally published data queried from different sources including
+SQL databases, LDAP directories and concurrent versionning systems
+(like subversion). In April/May 2008, it was adapted to run also on
+top of `Google AppEngine`'s datastore.
+
+`Google AppEngine` is provided with a partial port of the `Django`
+framework, but Google stated at Google IO 2008 that it would not
+support a specific Python web framework and that all
+community-supported frameworks would be more than welcome[1]_.
+
+`LAX` competes with other Python web application frameworks to get
+developers' attention and support. It originates from Logilab and is
+the result of about ten years of experience in developing large-scale
+web applications.
+
+Distinctive features include a data-model driven engine, a full-blown
+query language, a selection/view mechanism for HTML/XML/text
+generation, reuseable components, etc. It all sums up to very fast and
+efficient development.
+
+If you like Python and its standard library, chances are you will like
+`LAX` for it comes with batteries included thanks to its standard
+component library.
+
+Compare `LAX` with other frameworks and see for yourself what is your
+best option.
+
+.. _Logilab: http://www.logilab.fr/
+.. [1] for more on this matter, read our blog at http://www.logilab.org/blog/5216
+
+Essentials
+----------
+
+Schema
+
+ The schema defines the data model of an application as entities and
+ relationships. It is the core of an application. Entities and
+ relationships are modeled with a comprehensive language made of
+ Python classes.
+
+Query language
+
+ A full-blown query language named RQL is used to formulate
+ requests to the datastore.
+
+Result set
+
+ A resultset encapsulates the results of a request sent to
+ the datastore and informations about this request.
+
+Views
+
+ A view is applied to a `result set` to present it as HTML, XML,
+ JSON, CSV, etc. Views are implemented as Python classes. There is no
+ templating language.
+
+Generated user interface
+
+ A user interface is generated on-the-fly from the schema definition:
+ entities can be created, displayed, updated and deleted. As display
+ views are not very fancy, it is usually necessary to develop your
+ own. Any generated view can be overridden by defining a new one with
+ the same identifier.
+
+Components
+
+ Pieces of schema and sets of views can be combined into
+ components. Larger applications can be built faster by importing
+ components, adding entities and relationships and overriding the
+ views that need to display or edit informations not provided by
+ components.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/02-install.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,220 @@
+.. -*- coding: utf-8 -*-
+
+.. _installation:
+
+Installation
+============
+
+Download the source
+-------------------
+
+- The `Google AppEngine SDK` can be downloaded from:
+ http://code.google.com/appengine/downloads.html
+
+- `LAX` is available as an extension of `CubicWeb` under the GPLv2
+ license which can be downloaded from : http://cubicweb.org/
+
+Please follow instructions on how to install `CubicWeb` framework.
+
+Once ``cubicweb-ctl`` is installed, then you can create a Google
+App Engine extension of our framework by running the command ::
+
+ cubicweb-ctl newgapp <myapp>
+
+This will create a directory containing ::
+
+ `-- myapp/
+ |-- app.conf
+ |-- app.yaml
+ |-- bin/
+ | `-- laxctl
+ |-- boostrap_cubes
+ |-- cubes/
+ | |-- addressbook/
+ | ..
+ | |-- comment
+ | ..
+ | `-- zone/
+ |-- cubicweb/
+ |-- custom.py
+ |-- cw-cubes/
+ |-- dateutil/
+ |-- docutils/
+ |-- fckeditor/
+ |-- i18n/
+ |-- index.yaml
+ |-- loader.py
+ |-- logilab/
+ |-- main.py
+ |-- migration.py
+ |-- mx/
+ |-- roman.py
+ |-- rql/
+ |-- schema.py
+ |-- simplejson/
+ |-- tools/
+ |-- views.py
+ |-- vobject/
+ |-- yams/
+ `-- yapps/
+
+
+This skeleton directory is a working `AppEngine` application. You will
+recognize the files ``app.yaml`` and ``main.py``. All the rest is the
+`LAX` framework and its third-party libraries. You will notice that
+the directory ``cubes`` is a library of reusable components.
+
+The main directories that you should know about are:
+
+ - ``cubes`` : this is a library of reusable yams components. To use
+ those components you will list them in the variable
+ `included-yams-cubes` of ``app.conf``. See also :ref:`components`.
+ - [WHICH OTHER ONES SHOULD BE LISTED HERE?]
+
+Dependencies
+------------
+
+Before starting anything, please make sure the following packages are installed:
+ - yaml : by default google appengine is providing yaml; make sure you can
+ import it. We recommend you create a symbolic link yaml instead of installing
+ and using python-yaml:
+ yaml -> full/path/to/google_appengine/lib/yaml/lib/yaml/
+ - gettext
+
+Setup
+-----
+
+Once you executed ``cubicweb-ctl newgapp <myapp>``, you can use that ``myapp/``
+as an application directory and do as follows.
+
+This installation directory provides a configuration for an instance of `CubicWeb`
+ported for Google App Engine. It is installed with its own command ``laxctl``
+which is a port of the command tool ``cubicweb-ctl`` originally developped for
+`CubicWeb`.
+
+You can have the details of available commands by running ::
+
+ $ python myapp/bin/laxctl --help
+
+
+Generating translation files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`LAX` is fully internationalized. Translation catalogs are found in
+``myapp/i18n``. To compile the translation files, use the `gettext` tools
+or the ``laxctl`` command ::
+
+ $ python myapp/bin/laxctl i18nupdate
+ $ python myapp/bin/laxctl i18ncompile
+
+Ignore the errors that print "No translation file found for domain
+'erudi'". They disappear after the first run of i18ncompile.
+
+.. note:: The command myapp/bin/laxctl i18nupdate needs to be executed
+ only if your application is using components from ginco-apps.
+ Otherwise, please skip it.
+
+You will never need to add new entries in the translation catalog. Instead we would
+recommand you to use ``self.req._("msgId")`` in your application code
+to flag new message id to add to the catalog, where ``_`` refers to
+xgettext that is used to collect new strings to translate.
+While running ``laxctl i18nupdate``, new string will be added to the catalogs.
+
+Generating the data directory
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to generate the ``myapp/data`` directory that holds the static
+files like stylesheets and icons, you need to run the command::
+
+ $ python myapp/bin/laxctl populatedata
+
+Generating the schema diagram
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There is a view named ``schema`` that displays a diagram of the
+entity-relationship graph defined by the schema. This diagram has to
+be generated from the command line::
+
+ $ python myapp/bin/laxctl genschema
+
+Application configuration
+-------------------------
+
+Authentication
+~~~~~~~~~~~~~~
+
+You have the option of using or not google authentication for your application.
+This has to be define in ``app.conf`` and ``app.yaml``.
+
+In ``app.conf`` modify the following variable::
+
+ # does this application rely on google authentication service or not.
+ use-google-auth=no
+
+In ``app.yaml`` comment the `login: required` set by default in the handler::
+
+ - url: .*
+ script: main.py
+ # comment the line below to allow anonymous access or if you don't want to use
+ # google authentication service
+ #login: required
+
+
+
+
+Quickstart : launch the application
+-----------------------------------
+
+On Mac OS X platforms, drag that directory on the
+`GoogleAppEngineLauncher`.
+
+On Unix and Windows platforms, run it with the dev_appserver::
+
+ $ python /path/to/google_appengine/dev_appserver.py /path/to/myapp/
+
+Once the local server is started, visit `http://MYAPP_URL/_load <http://localhost:8080/_load>`_ and sign in as administrator.
+This will initialize the repository and enable you to log in into
+the application and continue the installation.
+
+You should be redirected to a page displaying a message `content initialized`.
+
+Initialize the datastore
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+You, then, want to visit `http://MYAPP_URL/?vid=authinfo <http://localhost:8080/?vid=authinfo>`_ .
+If you selected not to use google authentication, you will be prompted to a
+login form where you should initialize the administrator login (recommended
+to use admin/admin at first). You will then be redirected to a page providing
+you the value to provide to ``./bin/laxctl --cookie``.
+
+If you choosed to use google authentication, then you will not need to set up
+and administrator login but you will get the cookie value as well.
+
+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
+ :alt: displaying the detailed view of the cookie values returned
+
+
+.. note:: In case you are not redirected to a page providing the
+ option --cookie value, please visit one more time
+ `http://MYAPP_URL/?vid=authinfo <http://localhost:8080/?vid=authinfo>`_ .
+
+Once, you have this value, then return to the shell and execute ::
+
+ $ python myapp/bin/laxctl db-init --cookie='dev_appserver_login=test@example.com:True; __session=7bbe973a6705bc5773a640f8cf4326cc' localhost:8080
+
+.. note:: In the case you are not using google authentication, the value returned
+ by `http://MYAPP_URL/?vid=authinfo <http://localhost:8080/?vid=authinfo>`_
+ will look like :
+ --cookie='__session=2b45d1a9c36c03d2a30cedb04bc37b6d'
+
+Log out by clicking in the menu at the top right corner
+and restart browsing from `http://MYAPP_URL/ <http://localhost:8080>`_
+as a normal user.
+
+Unless you did something to change it, http://MYAPP_URL should be
+http://localhost:8080/
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/03-create-app.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,201 @@
+.. -*- coding: utf-8 -*-
+
+
+Creating your first application
+===============================
+
+This tutorial will guide you step by step to build a blog application
+and discover the unique features of `LAX`. It assumes that you followed
+the installation guidelines and that both the `AppEngine SDK` and the
+`LAX` framework are setup on your computer.
+
+Creating a new application
+--------------------------
+
+When you installed `LAX`, you saw a directory named ``skel``. Make a copy of
+this directory and call it ``BlogDemo``.
+
+Defining a schema
+-----------------
+
+With `LAX`, the schema/datamodel is the core of the application.
+
+Let us start with something simple and improve on it iteratively.
+
+In schema.py, we define two entities : ``Blog`` and ``BlogEntry``.
+
+::
+
+ class Blog(EntityType):
+ title = String(maxsize=50, required=True)
+ description = String()
+
+ class BlogEntry(EntityType):
+ title = String(maxsize=100, required=True)
+ publish_date = Date(default='TODAY')
+ text = String(fulltextindexed=True)
+ category = String(vocabulary=('important','business'))
+ entry_of = SubjectRelation('Blog', cardinality='?*')
+
+A Blog has a title and a description. The title is a string that is
+required and must be less than 50 characters. The description is a
+string that is not constrained.
+
+A BlogEntry has a title, a publish_date and a text. The title is a
+string that is required and must be less than 100 characters. The
+publish_date is a Date with a default value of TODAY, meaning that
+when a BlogEntry is created, its publish_date will be the current day
+unless it is modified. The text is a string that will be indexed in
+the full-text index and has no constraint.
+
+A BlogEntry also has a relationship ``entry_of`` that link it to a
+Blog. The cardinality ``?*`` means that a BlogEntry can be part of
+zero or one Blog (``?`` means `zero or one`) and that a Blog can
+have any number of BlogEntry (``*`` means `any number including
+zero`). For completeness, remember that ``+`` means `one or more`.
+
+Using the application
+---------------------
+
+Defining this simple schema is enough to get us started. Make sure you
+followed the setup steps described in detail in the installation
+chapter (especially visiting http://localhost:8080/_load as an
+administrator), then launch the application with the command::
+
+ python dev_appserver.py BlogDemo
+
+and point your browser at http://localhost:8080/ (if it is easier for
+you, use the on-line demo at http://lax.appspot.com/).
+
+.. image:: images/lax-book.00-login.en.png
+ :alt: login screen
+
+After you log in, you will see the home page of your application. It
+lists the entity types: Blog and BlogEntry. If these links read
+``blog_plural`` and ``blogentry_plural`` it is because
+internationalization (i18n) is not working for you yet. Please ignore
+this for now.
+
+.. image:: images/lax-book.01-start.en.png
+ :alt: home page
+
+Let us create a few of these entities. Click on the [+] at the right
+of the link Blog. Call this new Blog ``Tech-blog`` and type in
+``everything about technology`` as the description, then validate the
+form by clicking on ``button_ok``.
+
+.. image:: images/lax-book.02-create-blog.en.png
+ :alt: from to create blog
+
+Click on the logo at top left to get back to the home page, then
+follow the Blog link. You should be seeing a list with a single item
+``Tech-blog``.
+
+.. image:: images/lax-book.03-list-one-blog.en.png
+ :alt: displaying a list of a single blog
+
+Clicking on this item will get you to its detailed description except
+that in this case, there is not much to display besides the name and
+the phrase ``everything about technology``.
+
+.. image:: images/lax-book.04-detail-one-blog.en.png
+ :alt: displaying the detailed view of a blog
+
+Now get back to the home page by clicking on the top-left logo, then
+create a new Blog called ``MyLife`` and get back to the home page
+again to follow the Blog link for the second time. The list now
+has two items.
+
+.. image:: images/lax-book.05-list-two-blog.en.png
+ :alt: displaying a list of two blogs
+
+Get back to the home page and click on [+] at the right of the link
+BlogEntry. Call this new entry ``Hello World`` and type in some text
+before clicking on ``button_ok``. You added a new blog entry without
+saying to what blog it belongs. There is a box on the left entitled
+``actions``, click on the menu item ``modify``. You are back to the form
+to edit the blog entry you just created, except that the form now has
+another section with a combobox titled ``add relation``. Chose
+``entry_of`` in this menu and a second combobox appears where you pick
+``MyLife``.
+
+.. image:: images/lax-book.06-add-relation-entryof.en.png
+ :alt: editing a blog entry to add a relation to a blog
+
+Validate the changes by clicking ``button_ok``. The entity BlogEntry
+that is displayed now includes a link to the entity Blog named
+``MyLife``.
+
+.. image:: images/lax-book.07-detail-one-blogentry.en.png
+ :alt: displaying the detailed view of a blogentry
+
+Remember 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, run the ``laxctl genschema BlogDemo`` command as
+explained in the installation section and point your browser to the
+URL http://localhost:8080/schema
+
+.. image:: images/lax-book.08-schema.en.png
+ :alt: graphical view of the schema (aka data-model)
+
+Set-up a workflow
+-----------------
+
+Before starting, make sure you refresh your mind by reading [link to
+definition_workflow chapter].
+
+We want to create a workflow to control the quality of the BlogEntry
+submitted on your application. When a BlogEntry is created by a user
+its state should be `submitted`. To be visible to all, it needs to
+be in the state `published`. To move from `submitted` to `published`
+we need a transition that we can name `approve_blogentry`.
+
+We do not want every user to be allowed to change the state of a
+BlogEntry. We need to define a group of user, `moderators`, and
+this group will have appropriate permissions to approve BlogEntry
+to be published and visible to all.
+
+Create states and transitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Let us create a state `submitted`. Click on the [+] at the right
+of the link States. Call this new Blog ``submitted`` and type in
+``Initial State of a BlogEntry`` as the description, then validate the
+form by clicking on ``Apply``. This will leave us in the editing form
+with an additional section to create the relations related to the
+entity State we juste created. Select the relation ``initial_state_of``
+and select the entity type ``BlogEntry``.
+
+.. image:: images/lax-book.03-state-submitted.en.png
+
+
+
+
+Create group and set permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+
+Change view permission
+~~~~~~~~~~~~~~~~~~~~~~
+
+
+Conclusion
+----------
+
+Exercise
+~~~~~~~~
+
+Create new blog entries in ``Tech-blog``.
+
+What we learned
+~~~~~~~~~~~~~~~
+
+Creating a simple schema was enough to set up a new application that
+can store blogs and blog entries.
+
+What is next ?
+~~~~~~~~~~~~~~
+
+Although the application is fully functionnal, its look is very
+basic. In the following section we will learn to create views to
+customize how data is displayed.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/03-definition-schema.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,20 @@
+.. -*- coding: utf-8 -*-
+
+Data Model definition (*schema*)
+================================
+
+The schema is the main concept of `LAX` applications as it defines the
+data model we will handle. It is based on entities types already defined
+in the library and others, more specific, we would expect to find in one or
+more Python files under the `schema` directory.
+
+It is important to make clear the difference between relation type and relation
+definition: a relation type is only a relation name with potentially other
+additionnal properties (see XXXX), whereas a relation definition is a complete
+triplet "<subject entity type> <relation type> <object entity type>". A relation
+type could have been implied if none is related to a relation definition of the
+schema.
+
+
+.. include:: 03-sect-stdlib-schemas.en.txt
+.. include:: 03-sect-definition-schema.en.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/03-sect-definition-schema.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,344 @@
+.. -*- coding: utf-8 -*-
+
+Entity type definition
+----------------------
+
+An entity type is defined by a Python class which inherits `EntityType`. The
+class name correponds to the type name. Then the content of the class contains
+the description of attributes and relations for the defined entity type,
+by example ::
+
+ class Personne(EntityType):
+ """A person with the properties and the relations necessarry for my
+ application"""
+
+ last_name = String(required=True, fulltextindexed=True)
+ first_name = String(required=True, fulltextindexed=True)
+ title = String(vocabulary=('M', 'Mme', 'Mlle'))
+ date_of_birth = Date()
+ works_for = SubjectRelation('Company', cardinality='?*')
+
+* the name of the Python attribute corresponds to the name of the attribute
+ or the relation in `LAX` application.
+
+* all built-in types are available : `String`, `Int`, `Float`,
+ `Boolean`, `Date`, `Datetime`, `Time`, `Byte`.
+
+* each entity has at least the following meta-relations :
+
+ - `eid` (`Int`)
+
+ - `creation_date` (`Datetime`)
+
+ - `modification_date` (`Datetime`)
+
+ - `created_by` (`EUser`) (which user created the entity)
+
+ - `owned_by` (`EUser`) (who does the entity belongs to, by default the
+ creator but not necessarry and it could have multiple owners)
+
+ - `is` (`EEType`)
+
+
+* it is also possible to define relations of type object by using `ObjectRelation`
+ instead of `SubjectRelation`
+
+* the first argument of `SubjectRelation` and `ObjectRelation` gives respectively
+ the object/subject entity type of the relation. This could be :
+
+ * a string corresponding to an entity type
+
+ * a tuple of string correponding to multiple entities types
+
+ * special string such as follows :
+
+ - "**" : all types of entities
+ - "*" : all types of entities non meta
+ - "@" : all types of meta entities but not system entities (e.g. used for
+ the basis schema description)
+
+* it is possible to use the attribute `meta` to flag an entity type as a `meta`
+ (e.g. used to describe/categorize other entities)
+
+* optional properties for attributes and relations :
+
+ - `description` : 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` : list of conditions/constraints that the relation needs to
+ satisfy (c.f. `Contraints`_)
+
+ - `cardinality` : two characters string which specify the cardinality of the
+ relation. The first character defines the cardinality of the relation on
+ the subject, the second on the object of the relation. When a relation
+ has multiple possible subjects or objects, the cardinality applies to all
+ and not on a one to one basis (so it must be consistent...). The possible
+ values are inspired from regular expressions syntax :
+
+ * `1`: 1..1
+ * `?`: 0..1
+ * `+`: 1..n
+ * `*`: 0..n
+
+ - `meta` : boolean indicating that the relation is a meta-relation (false by
+ default)
+
+* optionnal properties for attributes :
+
+ - `required` : boolean indicating if the attribute is required (false by default)
+
+ - `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 usefull 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 correpond to the RQL keywords `TODAY` and `NOW`.
+
+ - `vocabulary` : specify static possible values of an attribute
+
+* optionnal properties of type `String` :
+
+ - `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)
+
+ - `maxsize` : integer providing the maximum size of the string (no limit by default)
+
+* optionnal properties for relations :
+
+ - `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 need
+ to set 'object' as the value. The composition implies that when the relation
+ is deleted (so when the composite is deleted), the composed are also deleted.
+ [PAS CLAIR]
+
+Contraints
+``````````
+By default, the available constraints types are :
+
+* `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
+
+* `UniqueConstraint` : identical to "unique=True"
+
+* `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
+
+* `RQLConstraint` : allows to specify a RQL query that needs to be satisfied
+ by the subject and/or the object of the relation. In this query the variables
+ `S` and `O` are reserved for the entities subject and object of the
+ relation.
+
+* `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
+ [PAS CLAIR]
+
+
+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, as well as 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)[PAS CLAIR] by example ::
+
+ class locked_by(RelationType):
+ """relation on all entities indicating that they are locked"""
+ inlined = True
+ cardinality = '?*'
+ subject = '*'
+ object = 'EUser'
+
+In addition to the permissions, the own properties of the relation types
+(shared also by all definition of relation of this type) are :
+
+
+* `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 the relation when the cardinality
+ of subject->relation->object is 0..1 ('?') or 1..1 ('1')
+
+* `symetric` : boolean indication that the relation is symetrical, which
+ means `X relation Y` implies `Y relation X`
+
+In the case of simultaneous relations definitions, `subject` and `object`
+can both be equal to the value of the first argument of `SubjectRelation`
+and `ObjectRelation`.
+
+When a relation is not inlined and not symetrical, and it does not require
+specific permissions, its definition (by using `SubjectRelation` and
+`ObjectRelation`) is all we need.
+
+Permissions definition
+----------------------
+
+Define permissions is set through to the attribute `permissions` of entities and
+relations types. It defines a dictionnary 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 once the user is in the listed groups or one of the RQL condition is
+satisfied.
+
+The standard groups are :
+
+* `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 define in the precreate
+of the application (``migration/precreate.py``).
+
+Use of RQL expression for writing rights
+````````````````````````````````````````
+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 a 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 `RQLExpression` in the case of a non-final relation
+ [WHAT IS A NON FINALE 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 defined rights on attributes of an entity (non-final relation),
+ knowing that :
+
+ - to defines 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.
+
+
+
+In addition to thatm the entity type `EPermission` from the standard library
+allow to build very complex and dynamic security architecture. The schema of
+this entity type is as follow : ::
+
+ class EPermission(MetaEntityType):
+ """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('EGroup', cardinality='+*',
+ description=_('groups to which the permission is granted'))
+ require_state = SubjectRelation('State',
+ description=_("entity'state in which the permission is applyable"))
+ # 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 ::
+
+ ...
+
+ 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 assumes/indicates [???] that an entity `EPermission` 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 genricity of the entity type `EPermission`, 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)
+
+
+Use of RQL expression for reading rights
+````````````````````````````````````````
+
+The principles are the same but with the following restrictions :
+
+* we can not [??] `RRQLExpression` on relation types for reading
+
+* special relations "has_<ACTION>_permission" can not be used
+
+
+Note on the use of RQL expression for `add` permission
+``````````````````````````````````````````````````````
+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 checks methods
+(check_perm, 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.
+[PAS CLAIR]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/03-sect-stdlib-schemas.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,86 @@
+.. -*- coding: utf-8 -*-
+
+Pre-defined schemas in the library
+----------------------------------
+
+The library defines a set of entities schemas that are required by the system
+or commonly used in `LAX` applications.
+Of course, you can extend those schemas if necessarry.
+
+System schemas
+``````````````
+Those are defined in::
+
+ ./myapp/ginco/schemas/
+ ./myapp/ginco/entities/
+
+``schemas/`` defines the data model you will use in your application.
+It allows you to describre the entities and the relations you will need.
+
+``entities/`` deifnes the methods you might need on the entities you
+defined in your schema.
+
+The system entities available are :
+
+* `EUser`, system users
+* `EGroup`, users groups
+* `EEType`, entity type
+* `ERType`, relation type
+
+* `State`, workflow state
+* `Transition`, workflow transition
+* `TrInfo`, record of a transition trafic for an entity
+
+* `EmailAddress`, email address, used by the system to send notifications
+ to the users and also used by others optionnals schemas
+
+* `EProperty`, used to configure the application
+* `EPermission`, used to configure the security of the application
+
+* `Card`, generic documenting card
+* `Bookmark`, an entity type used to allow a user to customize his links within
+ the application
+
+
+Components in the library
+`````````````````````````
+
+Those are defined in::
+
+ ./myapp/ginco-apps/
+
+An application is based on several basic components. In the set of available
+basic components we can find by example :
+
+* `ecomment`, provides an entity type for `Comment` allowing us to comment others
+ site's entities
+
+* `emailinglist`, provides an entity type for `Mailinglist` which groups informations
+ in a discussion list
+
+* `efile`, provides entity types for `File` et `Image` used to represent
+ files (text or binary) with additionnal informations such as MIME type or
+ encoding.
+
+* `elink`, provides an entity type for hypertext link (`Link`)
+
+* `eblog`, provides an entity type weblog (`Blog`)
+
+* `eperson`, provides an entity type for a person (`Person`)
+
+* `eaddressbook`, provides an entity type used to represent phone
+ numbers (`PhoneNumber`) and mailing address (`PostalAddress`)
+
+* `eclasstags`, categorization system based on tags (`Tag`)
+
+* `eclassfolders`, categorization system based on folders hierarchy in order
+ to create navigation sections (`Folder`)
+
+* `eemail`, archiving management for emails (`Email`, `Emailpart`,
+ `Emailthread`)
+
+* `ebasket`, basket management (`Basket`) allowing to group entities
+
+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.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/04-develop-views.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,126 @@
+.. -*- coding: utf-8 -*-
+
+
+Developing the user interface with Views
+========================================
+
+Before moving to this section, make sure you read the `Essentials`
+section in the Introduction.
+
+Tip: when modifying views, you do not need to restart the local
+server. Just save the file in your editor and reload the page in your
+browser to see the changes.
+
+The selection/view principle
+----------------------------
+
+With `LAX`, views are defined by Python classes. A view includes :
+
+- an identifier (all objects in `LAX` are entered in a registry
+ and this identifier will be used as a key)
+
+- a filter to select the resulsets it can be applied to
+
+`LAX` provides a lot of standard views, for a complete list, you
+will have to read the code in directory ``ginco/web/views/`` (XXX
+improve doc).
+
+For example, the view named ``primary`` is the one used to display
+a single entity.
+
+If you want to change the way a ``BlogEntry`` is displayed, just
+override the view ``primary`` in ``BlogDemo/views.py`` ::
+
+ 01. from ginco.web.views import baseviews
+ 02.
+ 03. class BlogEntryPrimaryView(baseviews.PrimaryView):
+ 04.
+ 05. accepts = ('BlogEntry',)
+ 06.
+ 07. def cell_call(self, row, col):
+ 08. entity = self.entity(row, col)
+ 09. self.w(u'<h1>%s</h1>' % entity.title)
+ 10. self.w(u'<p>published on %s in category %s</p>' % \
+ 11. (entity.publish_date.strftime('%Y-%m-%d'), entity.category))
+ 12. self.w(u'<p>%s</p>' % entity.text)
+
+The above source code defines a new primary view (`line 03`) for
+``BlogEntry`` (`line 05`).
+
+Since views are applied to resultsets and resulsets can be tables of
+data, it is needed to recover the entity from its (row,col)
+coordinates (`line 08`). We will get to this in more detail later.
+
+The view has a ``self.w()`` method that is used to output data. Here `lines
+09-12` output HTML tags and values of the entity's attributes.
+
+When displaying same blog entry as before, you will notice that the
+page is now looking much nicer.
+
+.. 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 ::
+
+ 01. class BlogPrimaryView(baseviews.PrimaryView):
+ 02.
+ 03. accepts = ('Blog',)
+ 04.
+ 05. def cell_call(self, row, col):
+ 06. entity = self.entity(row, col)
+ 07. self.w(u'<h1>%s</h1>' % entity.title)
+ 08. self.w(u'<p>%s</p>' % entity.description)
+ 09. rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid)
+ 10. self.wview('primary', rset)
+
+In the above source code, `lines 01-08` are similar to the previous
+view we defined.
+
+At `line 09`, a simple request in made to build a resultset 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 infer that such entities have to be of the
+``BlogEntry`` kind and retrieves them.
+
+The request returns a selection of data called a resultset. At
+`line 10` the view 'primary' is applied to this resultset to output
+HTML.
+
+**This is to be compared to interfaces and protocols in object-oriented
+languages. Applying a given view to all the entities of a resultset only
+requires the availability, for each entity of this resultset, of a
+view with that name that can accepts the entity.**
+
+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
+
+**Before we move forward, remember that the selection/view principle is
+at the core of `LAX`. Everywhere in the engine, data is requested
+using the RQL language, then HTML/XML/text/PNG is output by applying a
+view to the resultset returned by the query. That is where most of the
+flexibility comes from.**
+
+[WRITE ME]
+
+* implementing interfaces, calendar for blog entries
+* show that a calendar view can export data to ical
+
+We will implement the ginco.interfaces.ICalendarable interfaces on
+entities.BloEntry and apply the OneMonthCalendar and iCalendar views
+to resultsets like "Any E WHERE E is BlogEntry"
+
+* create view "blogentry table" with title, publish_date, category
+
+We will show that by default the view that displays
+"Any E,D,C WHERE E publish_date D, E category C" is the table view.
+Of course, the same can be obtained by calling
+self.wview('table',rset)
+
+* in view blog, select blogentries and apply view "blogentry table"
+* demo ajax by filtering blogentry table on category
+
+we did the same with 'primary', but with tables we can turn on filters
+and show that ajax comes for free.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/05-components.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,150 @@
+.. -*- coding: utf-8 -*-
+
+.. _components:
+
+Components
+===========
+
+What is a component
+-------------------
+
+A component is a model grouping one or more entity types and/or views associated
+in order to provide a specific feature or even a complete application using
+others components.
+You can decide to write your own set of components if you wish to re-use the
+entity types you develop. By default, LAX comes with its owns set of components
+that you can start using right away.
+
+
+Standard library
+----------------
+
+A library of standard components is part of the `LAX` release (look at
+``lax/skel/ginco-apps``). Components provide entities and views. With
+``lax-0.4``, you should get a set of application entities and system
+entities you can re-use.
+
+The available application entities are :
+
+* addressbook: PhoneNumber and PostalAddress
+
+* ebasket: Basket (like a shopping cart)
+
+* eblog: Blog (a *very* basic blog)
+
+* eclassfolder: Folder (to organize things but grouping them in folders)
+
+* eclasstags: Tag (to tag anything)
+
+
+* efile: File (to allow users to upload and store binary or text files)
+
+* elink: Link (to collect links to web resources)
+
+* emailinglist: MailingList (to reference a mailing-list and the URLs
+ for its archives and its admin interface)
+
+* eperson: Person (easily mixed with addressbook)
+
+* etask: Task (something to be done between start and stop date)
+
+* ezone: Zone (to define places within larger places, for example a
+ city in a state in a country)
+
+The available system entities are :
+
+* ecomment: Comment (to attach comment threads to entities)
+
+
+
+Adding comments to BlogDemo
+---------------------------
+
+To import a component in your application just change the line in the
+``app.conf`` file. For example::
+
+ included-yams-components=ecomment
+
+Will make the ``Comment`` entity available in your ``BlogDemo``
+application.
+
+Change the schema to add a relationship between ``BlogEntry`` and
+``Comment`` and you are done. Since the ecomment component defines the
+``comments`` relationship, adding the line::
+
+ comments = ObjectRelation('Comment', cardinality='1*', composite='object')
+
+to the definition of a ``BlogEntry`` will be enough.
+
+Clear the datastore and restart.
+
+Component structure
+-------------------
+
+A complex component is structured as follows :
+::
+
+ mycomponent/
+ |
+ |-- schema.py
+ |
+ |-- entities/
+ |
+ |-- sobjects/
+ |
+ |-- views/
+ |
+ |-- test/
+ |
+ |-- i18n/
+ |
+ |-- data/
+ |
+ |-- migration/
+ | |- postcreate.py
+ | \- depends.map
+ |
+ |-- debian/
+ |
+ \-- __pkginfo__.py
+
+We can also define simple Python module instead of directories (packages), for example :
+::
+
+ mycomponent/
+ |
+ |-- entities.py
+ |-- hooks.py
+ \-- views.py
+
+
+where :
+
+* ``schema`` contains the definition of the schema (server side only)
+* ``entities`` contains entities definition (server side and web interface)
+* ``sobjects`` contains hooks and/or notification views (server side only)
+* ``views`` contains the web interface components (web interface only)
+* ``test`` contains tests related to the application (not installed)
+* ``i18n`` contains messages 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 file 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-components used by
+ the component.
+
+At least you should have :
+
+* the file ``__pkginfo__.py``
+* schema definition
+
+[WRITE ME]
+
+* explain the component architecture
+
+* add comments to the blog by importing the comments component
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/06-maintemplate.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,210 @@
+.. -*- coding: utf-8 -*-
+
+Views & Templates
+=================
+
+
+Look at ``lax/skel/ginco/web/views/basetemplates.py`` and you will
+find the base templates used to generate HTML for your application.
+
+A page is composed as indicated on the schema below :
+
+.. image:: images/lax-book.06-main-template-layout.en.png
+
+In this section we will go through a couple of the primary templates
+you must be interested in, that is to say, the HTMLPageHeader,
+the HTMLPageFooter and the TheMainTemplate.
+
+
+HTMLPageHeader
+--------------
+
+Let's use a different logo than the default one provided with LAX
+and customize our header.
+
+Change logo
+~~~~~~~~~~~
+
+The easiest way to use a different logo is to replace the existing
+``logo.png`` in ``myapp/data`` by your prefered icon and refresh.
+By default all application will look for a ``logo.png`` to be
+rendered in the logo section.
+
+.. image:: images/lax-book.06-main-template-logo.en.png
+
+[ADD]
+customized external_resources in myapp/data cd crih for reference
+
+[WRITE ME]
+ADD how to use external_resources variables used in ginco/web/webconfig.py
+
+Customize header
+~~~~~~~~~~~~~~~~
+
+Let's now move the search box in the header and remove the login form
+from the header. We'll show how to move it to the left column of the application.
+
+Let's sat we do not want anymore the login menu to be in the header, but we
+prefer it to be in the left column just below the logo. As the left column is
+rendered by ``TheMainTemplate``, we will show how to do it in TheMainTemplate_.
+
+First, to remove the login menu, we just need to comment out the display of the
+login component such as follows : ::
+
+ class MyHTMLPageHeader(HTMLPageHeader):
+
+ def main_header(self, view):
+ """build the top menu with authentification info and the rql box"""
+ self.w(u'<table id="header"><tr>\n')
+ self.w(u'<td id="firstcolumn">')
+ self.vreg.select_component('logo', self.req, self.rset).dispatch(w=self.w)
+ self.w(u'</td>\n')
+ # appliname and breadcrumbs
+ self.w(u'<td id="headtext">')
+ comp = self.vreg.select_component('appliname', self.req, self.rset)
+ if comp and comp.propval('visible'):
+ comp.dispatch(w=self.w)
+ comp = self.vreg.select_component('breadcrumbs', self.req, self.rset, view=view)
+ if comp and comp.propval('visible'):
+ comp.dispatch(w=self.w, view=view)
+ self.w(u'</td>')
+ # logged user and help
+ #self.w(u'<td>\n')
+ #comp = self.vreg.select_component('loggeduserlink', self.req, self.rset)
+ #comp.dispatch(w=self.w)
+ #self.w(u'</td><td>')
+
+ self.w(u'<td>')
+ helpcomp = self.vreg.select_component('help', self.req, self.rset)
+ if helpcomp: # may not be available if Card is not defined in the schema
+ helpcomp.dispatch(w=self.w)
+ self.w(u'</td>')
+ # lastcolumn
+ self.w(u'<td id="lastcolumn">')
+ self.w(u'</td>\n')
+ self.w(u'</tr></table>\n')
+ self.template('logform', rset=self.rset, id='popupLoginBox', klass='hidden',
+ title=False, message=False)
+
+
+
+.. image:: images/lax-book.06-header-no-login.en.png
+
+Let's now move the search box in the top-right header area. To do so, we will
+first create a method to get the search box display and insert it in the header
+table.
+
+::
+
+ from ginco.web.views.basetemplates import HTMLPageHeader
+ class MyHTMLPageHeader(HTMLPageHeader):
+ def main_header(self, view):
+ """build the top menu with authentification info and the rql box"""
+ self.w(u'<table id="header"><tr>\n')
+ self.w(u'<td id="firstcolumn">')
+ self.vreg.select_component('logo', self.req, self.rset).dispatch(w=self.w)
+ self.w(u'</td>\n')
+ # appliname and breadcrumbs
+ self.w(u'<td id="headtext">')
+ comp = self.vreg.select_component('appliname', self.req, self.rset)
+ if comp and comp.propval('visible'):
+ comp.dispatch(w=self.w)
+ comp = self.vreg.select_component('breadcrumbs', self.req, self.rset, view=view)
+ if comp and comp.propval('visible'):
+ comp.dispatch(w=self.w, view=view)
+ self.w(u'</td>')
+
+ # logged user and help
+ #self.w(u'<td>\n')
+ #comp = self.vreg.select_component('loggeduserlink', self.req, self.rset)
+ #comp.dispatch(w=self.w)
+ #self.w(u'</td><td>')
+
+ # search box
+ self.w(u'<td>')
+ self.get_searchbox(view, 'left')
+ self.w(u'</td>')
+
+ self.w(u'<td>')
+ helpcomp = self.vreg.select_component('help', self.req, self.rset)
+ if helpcomp: # may not be available if Card is not defined in the schema
+ helpcomp.dispatch(w=self.w)
+ self.w(u'</td>')
+ # lastcolumn
+ self.w(u'<td id="lastcolumn">')
+ self.w(u'</td>\n')
+ self.w(u'</tr></table>\n')
+ self.template('logform', rset=self.rset, id='popupLoginBox', klass='hidden',
+ title=False, message=False)
+
+ def get_searchbox(self, view, context):
+ boxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+ view=view, context=context))
+ if boxes:
+ for box in boxes:
+ if box.id == 'search_box':
+ box.dispatch(w=self.w, view=view)
+
+
+
+
+HTMLPageFooter
+--------------
+
+If you want to change the footer for example, look
+for HTMLPageFooter and override it in your views file as in :
+::
+
+ form ginco.web.views.basetemplates import HTMLPageFooter
+ class MyHTMLPageFooter(HTMLPageFooter):
+ def call(self, **kwargs):
+ self.w(u'<div class="footer">')
+ self.w(u'This website has been created with <a href="http://lax.logilab.org">LAX</a>.')
+ self.w(u'</div>')
+
+Updating a view does not require any restart of the server. By reloading
+the page you can see your new page footer.
+
+
+TheMainTemplate
+---------------
+.. _TheMainTemplate:
+
+The MainTemplate is a bit complex as it tries to accomodate many
+different cases. We are now about to go through it and cutomize entirely
+our application.
+
+TheMainTemplate is responsible for the general layout of the entire application.
+It defines the template of ``id = main`` that is used by the application. Is
+also defined in ``ginco/web/views/basetemplates.py`` another template that can
+be used based on TheMainTemplate called SimpleMainTemplate which does not have
+a top section.
+
+.. image:: images/lax-book.06-simple-main-template.en.png
+
+CSS changes
+-----------
+
+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/``.
+
+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.
+
+1
+[TODO]
+Add login menu in left column
+
+
+[WRITE ME]
+
+* customize MainTemplate and show that everything in the user
+ interface can be changed
+
+[TODO]
+Rajouter une section pour definir la terminologie utilisee.
+Dans ginco-doc rajouter une section pour erudi-ctl shell ou
+on liste les commandes dispos.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/07-rss-xml.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,45 @@
+.. -*- coding: utf-8 -*-
+
+RSS Channel
+===========
+
+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
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/08-rql.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,211 @@
+.. -*- coding: utf-8 -*-
+
+RQL language (Relation Query Language)
+========================================
+
+Introduction
+------------
+* RQL language focuses on browsing relations.
+* Attributes are considered as particular relations.
+* RQL is inspired from SQL but is a high level language.
+* A good knowledge of Erudi's schemas defining the application is required.
+
+
+Types of requests
+-----------------
+
+Search (`Any`)
+ query the repository to extract entities and/or attributes.
+
+Insertion (`INSERT`)
+ insert new entities in the database.
+
+Updates of entities, creation of relations (`SET`)
+ update existing entities in the database, or create relations between existing
+ entities
+
+Deletion of entities or relations (`DELETE`)
+ delete existing entities and relations from the database.
+
+
+Variables and typing
+--------------------
+
+Entities and values to browse and/or select are set in the query through *variables*
+which should be written in capital letters.
+
+The possible types for each variable can be deducted from the schema depending on
+the conditions expressed in the query.
+
+You can force the possible types for a variable thanks to the special relation `is`.
+
+
+
+Built-in types
+--------------
+* `String` (literal: between double or single quotes).
+* `Int`, `Float` (separator is '.').
+* `Date`, `Datetime`, `Time` (literal: pattern YYYY/MM/DD[ hh:mm] or keywords
+ `TODAY` and `NOW`).
+* `Boolean` (keywords `TRUE` et `FALSE`).
+* keyword `NULL`.
+
+Operators
+----------
+* Logical operators: `AND`, `OR`, `,`.
+* Mathematical operators: `+`, `-`, `*`, `/`.
+* Comparison operators: `=`, `<`, `<=`, `>=`, `>`, `~=`, `LIKE`, `IN`.
+
+ * The operator `=` is the default operator.
+
+ * The operator `LIKE` / `~=` allows the use of the character `%` in a string
+ to indicate that the string should start/end with a prefix/suffix::
+
+ Any X WHERE X nom ~= 'Th%'
+ Any X WHERE X nom LIKE '%lt'
+
+ * The operator `IN` allows to provide a list of possible values::
+
+ Any X WHERE X nom IN ('chauvat', 'fayolle', 'di mascio', 'thenault')
+
+Search query
+------------
+
+ [`DISTINCT`] <entity type> V1(, V2)\*
+ [`GROUPBY` V1(, V2)\*] [`ORDERBY` <orderterms>]
+ [`WHERE` <condition>]
+ [`LIMIT` <value>] [`OFFSET` <value>]
+
+:entity type:
+ Type of the selected variable
+ Special type `Any` is equivalent to not specify a type
+:condition:
+ list of relations to browse following the pattern
+ `V1 relation V2|<static value>`
+:orderterms:
+ Setting of the selection order : variable or column number followed by the
+ sorting method (`ASC`, `DESC`), ASC being the default value.
+:note for grouped queries:
+ For grouped queries (e.g. using function `GROUPBY`), all the selected
+ variables must be grouped or aggregated.
+
+Examples - search
+`````````````````
+::
+
+ Any X WHERE X eid 53
+ Personne X
+ Personne X WHERE X travaille_pour S, S nom "logilab"
+ Any E,COUNT(X) GROUPBY E ORDERBY EN WHERE X is E, E name EN
+ Any E,COUNT(X) GROUPBY E ORDERBY 2 WHERE X is E
+
+
+Advanced features
+`````````````````
+* Aggregate functions : `COUNT`, `MIN`, `MAX`, `SUM`.
+* String functions :`UPPER`, `LOWER`.
+* Optional relations :
+
+ * They allow to select entities related to others or not.
+
+ * You should use `?` behind the variable to specify the relation to itself is
+ optional.
+
+ - Project anomalies related to a version or not ::
+
+ Any X,V WHERE X concerns P, P eid 42, X corrected_in V?
+
+ - All the cards and the project they document otherwise ::
+
+ Any C,P WHERE C is Card, P? documented_by C
+
+Negation
+````````
+* A query such as `Document X WHERE NOT X owned_by U` is equivalent to
+ "the documents which do not have relation `owned_by`".
+* Whereas the query `Document X WHERE NOT X owned_by U, U login "syt"`
+ is equivalent to "the documents which do not have relation `owned_by`
+ with the user syt". They could have a relation with other users.
+
+
+Identity
+````````
+
+We could use the special relation `identity` in a query in order to add a
+condition of identity between two variables. This is equivalent to ``is``
+in Python.
+
+ Any A WHERE A comments B, A identity B
+
+returns the set of objects which comment themselves. The relation `identity`
+is very usefull while defining security rules with `RQLExpressions`.
+
+Insertion queries
+-----------------
+ `INSERT` <entity type> V1(, <entity type> V2)\* `:` <assignments>
+ [`WHERE` <condition>]
+
+:assignments:
+ list of relations to assign such as `V1 relation V2|<static value>`
+
+The condition allow to define the variables we would use in assignments.
+
+Be careful, if a condition is specified, the insertion is done *for each result
+returned by the condition*.
+
+Examples - insertion
+`````````````````````
+* Insertion of a new person named 'bidule'::
+
+ INSERT Person X: X name 'bidule'
+
+* Insertion of a new person named 'bidule', another named
+ 'chouette' and a relation 'friend' between them::
+
+ INSERT Person X, Person Y: X name 'bidule', Y name 'chouette', X friend Y
+
+* Insertion of a new person named 'bidule' and a relation 'friend'with an
+ existing person 'chouette'::
+
+ INSERT Person X: X name 'bidule', X friend Y WHERE Y name 'chouette'
+
+
+Update queries
+--------------
+ `SET` <assignments>
+ [`WHERE` <condition>]
+
+Be careful, if a condition is specified, the update is done *for each result
+returned by the condition*.
+
+Examples - update
+`````````````````
+* Renaming of the person named 'bidule' to 'toto', with change on the first name::
+
+ SET X name 'toto', X firstname 'original' WHERE X is 'Person', X name 'bidule'
+
+* Insertion of a relation of type 'know' between two objects linked with the relation
+ of type 'friend' ::
+
+ SET X know Y WHERE X friend Y
+
+Deletion queries
+----------------
+ `DELETE` (<entity type> V) | (V1 relation v2),...
+ [`WHERE` <condition>]
+
+
+Be careful, if a condition is specified, the deletion is done *for each result
+returned by the condition*.
+
+
+Examples
+````````
+* Deletion of the person named 'toto'::
+
+ DELETE Person X WHERE X name 'toto'
+
+* Deletion of all the relations of type 'friend' linked to the person named
+ 'toto'::
+
+ DELETE X friend Y WHERE X is 'Person', X name 'toto'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/09-urlrewrite.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+URL Rewriting
+=============
+
+[WRITE ME]
+
+* show how urls are mapped to selections and views and explain URLRewriting
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/10-security.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,10 @@
+.. -*- coding: utf-8 -*-
+
+Security
+=========
+
+[WRITE ME]
+
+* talk about security access rights and show that security is defined
+ using RQL
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/11-definition-workflow.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,43 @@
+.. -*- coding: utf-8 -*-
+
+Defining a Workflow
+===================
+
+General
+-------
+
+A workflow can be defined in a `LAX` application thanks to the system
+entities ``State`` and ``Transition``. Those are defined within all
+LAX application and can be set-up through the main administrator interface.
+
+Once your schema is defined, you can start creating the set of states and
+the required transitions for your applications entities.
+
+You first need to define the states and then the transitions between those
+to complete your workflow.
+
+A ``State`` defines the status of an entity. While creating a new state,
+you will be first given the option to select the entity type the state
+can be applied to. By choosing ``Apply``, a new section will be displayed
+in the editing screen to enable you to add relation to the state you are
+creating.
+
+A ``Transition`` is also based on an entity type it can be applied to.
+By choosing ``Apply``, a new section will be displayed in the editing
+screen to enable you to add relation to the transition you are
+creating.
+
+At the transition level you will also define the group of user which can
+aplly this transition to an object.
+
+
+Example of a simple workflow
+----------------------------
+
+Please see the tutorial to view and example of a simple workflow.
+
+
+[Create a simple workflow for BlogDemo, to have a moderator approve new blog
+entry to be published. This implies, specify a dedicated group of blog
+moderator as well as hide the view of a blog entry to the user until
+it reaches the state published]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/11-faq.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,54 @@
+.. -*- coding: utf-8 -*-
+
+Frequently Asked Questions
+==========================
+
+* Why does not LAX have a template language ?
+
+ It does. Actually, you can use your preferred template language if you
+ want. [explain how to use a template language]
+
+ The reason template languages are not used in this book is that
+ experience has proved us that using pure python was more efficient.
+
+* Why do you think using pure python is better than using a template language ?
+
+ [copy answer from forum]
+
+ code is easier to maintain, does not have to learn a new dialect
+ each time, real function/classes etc -> real development
+
+* Why do you use the GPL license to prevent me from doing X ?
+
+ [copy answer from forum]
+
+* LAX looks pretty recent. Is it stable ?
+
+ [answer that framework has evolved over the past seven years and that
+ data migrated from one schema to the other ever since]
+
+* Why is the RQL query language looking similar to X ?
+
+ [copy answer from forum, explain why similar to sparql and why better
+ than django and SQL]
+
+* which ajax library
+
+ [we use mochikit and things on top of that]
+
+* `Error while publishing rest text ...`
+
+ While modifying the description of an entity, you get an error message in
+ the application `Error while publishing ...` for Rest text and plain text.
+ The server returns a traceback like as follows :
+ 2008-10-06 15:05:08 - (erudi.rest) ERROR: error while publishing ReST text
+ Traceback (most recent call last):
+ File "/home/sandrine/src/blogdemo/ginco/common/rest.py", line 217, in rest_publish
+ File "/usr/lib/python2.5/codecs.py", line 817, in open
+ file = __builtin__.open(filename, mode, buffering)
+ TypeError: __init__() takes at most 3 arguments (4 given)
+
+
+ This can be fixed by applying the patch described in :
+ http://code.google.com/p/googleappengine/issues/detail?id=48
+[ADD MORE FAQ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/12-internationalization.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,73 @@
+.. -*- coding: utf-8 -*-
+
+.. _internationalization:
+
+
+Internationalization
+====================
+
+The internationalization
+
+Le système d'internationalisation de l'interface web d'erudi est basé sur le
+système `GNU gettext`_.
+
+.. _`GNU gettext`: http://www.gnu.org/software/gettext/
+
+Messages à internationaliser
+----------------------------
+
+Marquage des messages à internaliser
+````````````````````````````````````
+Les chaines de caractères à internationaliser sont marqués par l'appel à la
+fonction `_` *OU* par la méthode équivalent de la requête dans le code python ou
+dans les expressions python de template TAL.
+
+Dans les templates erudi-tal, il est également possible d'insérer une chaine à
+traduire via les balises `i18n:content` et `i18n:replace`.
+
+De plus des messages correspondant aux entités/relations utilisés par le schéma
+de l'application seront automatiquement ajoutés.
+
+Renvoi d'un message internationalisé lors de la construction d'une page
+```````````````````````````````````````````````````````````````````````
+La fonction *built-in* `_` ne doit servir qu'**à marquer les messages à
+traduire**, non pas à récupérer une traduction. Il faut pour cela utiliser la
+méthode `_` de l'objet requête, sans quoi vous récupérerez l'identifiant de
+message au lieu de sa traduction dans la langue propre à la requête.1
+
+
+Gestion des catalogues de traduction
+------------------------------------
+Une fois l'application rendu internationalisable coté code, reste à gérer les
+catalogues de traductions. erudi-ctl intègre pour cela les commandes suivantes :
+
+* `i18nlibupdate`, met à jour les catalogues de messages *de la librairie
+ erudi*. Sauf si vous développez sur le framework (et non votre propre
+ application), vous ne devriez pas avoir à utiliser cette commande
+
+* `i18nupdate`, met à jour les catalogues de messages *du composant* (ou de tous
+ les composants). A la suite de cette commande, vous devez mettre à jour les
+ fichiers de traduction *.po* dans le sous-répertoire "i18n" de votre
+ template. Évidemment les traductions précédentes toujours utilisées ont été
+ conservées.
+
+* `i18ncompile`, recompile les catalogues de messages *d'une instance* (ou de
+ toutes les instances) après mise à jour des catalogues de son composant. Cela
+ est effectué automatiquement lors d'une création ou d'une mise à jour. Les
+ catalogues de messages compilés se trouvent dans le répertoire
+ "i18n/<lang>/LC_MESSAGES/erudi.mo" de l'application où `lang` est
+ l'identifiant de la langue sur 2 lettres ('en' ou 'fr' par exemple)
+
+
+Le cas classique
+````````````````
+Vous avez ajouté et/ou modifié des messages d'un composant utilisé par votre
+application (en ajoutant une nouvelle vue ou en ayant modifié le schéma par
+exemple) :
+
+1. `cubicweb-ctl i18nupdate <composant>`
+2. éditer les fichiers <composant>/xxx.po dans pour y rajouter les traductions
+ manquantes (`msgstr` vide)
+3. `hg ci -m "updated i18n catalogs"`
+4. `cubicweb-ctl i18n compile <monapplication>`
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/12-reference.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,33 @@
+.. -*- coding: utf-8 -*-
+
+API Reference
+=============
+
+Schema API
+----------
+
+Base Types
+~~~~~~~~~~
+
+Base types are defined as a set in yams.BASE_TYPES that includes:
+`String`, `Int`, `Float`, `Boolean`, `Date`, `Time`, `Datetime`,
+`Interval`, `Password`, `Bytes`.
+
+See `yams' API <http://lax.logilab.org/apidoc>`_
+
+Constraints
+~~~~~~~~~~~
+
+Constraints are defined in yams.constraints and include:
+`UniqueConstraint`, `SizeConstraint`, `RegexpConstraint`,
+`BoundConstraint`, `IntervalBoundConstraint`,
+`StaticVocabularyConstraint`, `MultipleStaticVocabularyConstraint`.
+
+See `yams' API <http://lax.logilab.org/apidoc>`_
+
+Views API
+---------
+
+See `yams' API <http://lax.logilab.org/apidoc>`_
+[WRITE ME]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/faq.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,56 @@
+.. -*- coding: utf-8 -*-
+
+Frequently Asked Questions
+==========================
+
+* Why does not LAX have a template language ?
+
+ It does. Actually, you can use your preferred template language if you
+ want. [explain how to use a template language]
+
+ The reason template languages are not used in this book is that
+ experience has proved us that using pure python was more efficient.
+
+* Why do you think using pure python is better than using a template language ?
+
+ [copy answer from forum]
+
+ code is easier to maintain, does not have to learn a new dialect
+ each time, real function/classes etc -> real development
+
+* Why do you use the GPL license to prevent me from doing X ?
+
+ [copy answer from forum]
+
+* LAX looks pretty recent. Is it stable ?
+
+ [answer that framework has evolved over the past seven years and that
+ data migrated from one schema to the other ever since]
+
+* Why is the RQL query language looking similar to X ?
+
+ [copy answer from forum, explain why similar to sparql and why better
+ than django and SQL]
+
+* which ajax library
+
+ [we use mochikit and things on top of that]
+
+* `Error while publishing rest text ...`
+
+ While modifying the description of an entity, you get an error message in
+ the application `Error while publishing ...` for Rest text and plain text.
+ The server returns a traceback like as follows ::
+
+ 2008-10-06 15:05:08 - (erudi.rest) ERROR: error while publishing ReST text
+ Traceback (most recent call last):
+ File "/home/sandrine/src/blogdemo/ginco/common/rest.py", line 217, in rest_publish
+ (...)
+ File "/usr/lib/python2.5/codecs.py", line 817, in open
+ file = __builtin__.open(filename, mode, buffering)
+ TypeError: __init__() takes at most 3 arguments (4 given)
+
+ This can be fixed by applying the patch described in :
+ `Google group appengine <http://code.google.com/p/googleappengine/issues/detail?id=48>`_
+
+[ADD MORE FAQ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/lax-book.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,27 @@
+.. LAX documentation master file, created by sphinx-quickstart on Wed Sep 10 08:23:04 2008.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. _contents:
+
+LAX book
+========
+
+
+.. toctree::
+ :maxdepth: 2
+
+
+ 01-intro.en.txt
+ 02-install.en.txt
+ 03-definition-schema.en.txt
+ 04-develop-views.en.txt
+ 05-components.en.txt
+ 06-maintemplate.en.txt
+ 07-rss-xml.en.txt
+ 08-rql.en.txt
+ 09-urlrewrite.en.txt
+ 10-security.en.txt
+ 11-definition-workflow.en.txt
+ 12-internationalization.en.txt
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/reference.en.txt Fri Nov 14 11:05:32 2008 +0100
@@ -0,0 +1,33 @@
+.. -*- coding: utf-8 -*-
+
+API Reference
+=============
+
+Schema API
+----------
+
+Base Types
+~~~~~~~~~~
+
+Base types are defined as a set in yams.BASE_TYPES that includes:
+`String`, `Int`, `Float`, `Boolean`, `Date`, `Time`, `Datetime`,
+`Interval`, `Password`, `Bytes`.
+
+See `yams' API <http://lax.logilab.org/apidoc>`_
+
+Constraints
+~~~~~~~~~~~
+
+Constraints are defined in yams.constraints and include:
+`UniqueConstraint`, `SizeConstraint`, `RegexpConstraint`,
+`BoundConstraint`, `IntervalBoundConstraint`,
+`StaticVocabularyConstraint`, `MultipleStaticVocabularyConstraint`.
+
+See `yams' API <http://lax.logilab.org/apidoc>`_
+
+Views API
+---------
+
+See `yams' API <http://lax.logilab.org/apidoc>`_
+[WRITE ME]
+