# HG changeset patch # User Nicolas Chauvat # Date 1227208463 -3600 # Node ID 1091d8d63f51b886ded029581976e05970bd4b02 # Parent 52bf52e6fc773a7db92a2fa9c76ca6800a774626 [doc] add a level for better structure diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/01-00-introduction.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/01-00-introduction.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,335 @@ +.. -*- coding: utf-8 -*- + +.. _Overview: + +Quick overview of `CubicWeb` +============================ + +`CubicWeb` allows us to develop web applications instances based on +one or more `cubes`. + +What we call a `cube` is a model defining the data types and views. +A `cube` is a reusable component grouped with others cubes in the file +system. + +An `instance` refers to a specific installation of one or more `cubes` + where are grouped configuration files of the final web application. + +In this document, we will show you how to create a `cube` and how to use it +in an `instance` for your web application. + +Create your cube +---------------- + +After you installed your `CubicWeb` development environment, you can start +to build your first cube: :: + + cubicweb-ctl newcube blog + +This will create in ``/path/to/forest/cubes`` a directory containing: :: + + blog/ + | + |-- data/ + | |-- cubes.blog.css + | |-- cubes.blog.js + | |-- external_resources + | + |-- debian/ + | |-- changelog + | |-- compat + | |-- control + | |-- copyright + | |-- cubicweb-blog.prerm + | |-- rules + | + |-- entities.py + | + |-- i18n/ + | |-- en.po + | |-- fr.po + | + |-- __init__.py + | + |-- MANIFEST.in + | + |-- migration/ + | |-- postcreate.py + | |-- precreate.py + | + |-- __pkginfo__.py + | + |-- schema.py + | + |-- setup.py + | + |-- site_cubicweb.py + | + |-- sobjects.py + | + |-- test/ + | |-- data/ + | |-- bootstrap_cubes + | |-- pytestconf.py + | |-- realdb_test_blog.py + | |-- test_blog.py + | + |-- views.py + +Any changes applied to your data model should be done in this +directory. + + +Define your data schema +----------------------- + +The data model or schema is hte core of your `CubicWeb` application. +This is where is defined the type of content you application will handle. + +The data model is defined in the file ``schema.py`` of your cube +``blog`` such as follows. + +:: + + from cubicweb.schema import format_constraint + class Blog(EntityType): + title = String(maxsize=50, required=True) + description = String() + + class BlogEntry(EntityType): + title = String(required=True, fulltextindexed=True, maxsize=256) + publish_date = Date(default='TODAY') + content = String(required=True, fulltextindexed=True) + entry_of = SubjectRelation('Blog', cardinality='?*') + + +A Blog has a title and a description. The title is a string that is +required by the class EntityType and must be less than 50 characters. +The description is a string that is not constrained. + +A BlogEntry has a title, a publish_date and a content. The title is a +string that is required and must be less than 100 characters. The +publish_date is a Date with a default value of TODAY, meaning that +when a BlogEntry is created, its publish_date will be the current day +unless it is modified. The content is a string that will be indexed in +the full-text index and has no constraint. + +A BlogEntry also has a relationship ``entry_of`` that links it to a +Blog. The cardinality ``?*`` means that a BlogEntry can be part of +zero or one Blog (``?`` means `zero or one`) and that a Blog can +have any number of BlogEntry (``*`` means `any number including +zero`). For completeness, remember that ``+`` means `one or more`. + + +Create your instance +-------------------- + +:: + + cubicweb-ctl create blog blogdemo + + +This command will create a directory ``~/etc/cubicweb.d/blogdemo`` +which will contain all the configuration files required to start +you web application. + +The instance ``blogdemo`` is based on the cube ``blog``. + + +Welcome in your web application +------------------------------- + +Run your application with the following command: :: + + cubicweb-ctl start -D blogdemo + + +You can now access to your web application to create blogs and post messages +by visitin the URL http://localhost:8080/. +A login form will first be prompted. By default, the application will not allow +anonymous user to get in the application. You should then use the admin +account you created at the time you initialized the database with +``cubicweb-ctl create``. + +.. image:: images/login-form.png + + +Once authenticated, you can start playing with your application +and create entities. Bravo! + +.. image:: images/blog-demo-first-page.png + +Please notice that so far, `CubicWeb` franework managed all aspects of +the web application based in the schema provided at first. + + +Create entities +--------------- + +We will now create a couple of entities in our web application. + +Create a Blog +~~~~~~~~~~~~~ + +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 ``Validate``. + +.. image:: images/cbw-create-blog.en.png + :alt: from to create blog + +Click on the logo at top left to get back to the home page, then +follow the Blog link that will list for you all the existing Blog. +You should be seeing a list with a single item ``Tech-blog`` you +just created. + +.. image:: images/cbw-list-one-blog.en.png + :alt: displaying a list of a single blog + +Clicking on this item will get you to its detailed description except +that in this case, there is not much to display besides the name and +the phrase ``everything about technology``. + +Now get back to the home page by clicking on the top-left logo, then +create a new Blog called ``MyLife`` and get back to the home page +again to follow the Blog link for the second time. The list now +has two items. + +.. image:: images/cbw-list-two-blog.en.png + :alt: displaying a list of two blogs + +Create a BlogEntry +~~~~~~~~~~~~~~~~~~ + +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 ``Validate``. You added a new blog entry without +saying to what blog it belongs. There is a box on the left entitled +``actions``, click on the menu item ``modify``. You are back to the form +to edit the blog entry you just created, except that the form now has +another section with a combobox titled ``add relation``. Chose +``entry_of`` in this menu and a second combobox appears where you pick +``MyLife``. + +You could also have, at the time you started to fill the form for a +new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the +combobox titled ``add relation`` would have showed up. + + +.. image:: images/cbw-add-relation-entryof.en.png + :alt: editing a blog entry to add a relation to a blog + +Validate the changes by clicking ``Validate``. The entity BlogEntry +that is displayed now includes a link to the entity Blog named +``MyLife``. + +.. image:: images/cbw-detail-one-blogentry.en.png + :alt: displaying the detailed view of a blogentry + +Please notice that so far, `CubicWeb` franework managed all aspects of +the web application based in the schema provided at first. +Also if you wish to get a graphical view of the schema, visit +the link `Application schema`` which will direct you to : +http://localhost:8080/view?vid=schema + +.. image:: images/cbw-schema.en.png + :alt: graphical view of the schema (aka data-model) + + +Define your entities views +-------------------------- + +The views selection principle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A view is defined by a Python class which includes: + + - an identifier (all objects in `CubicWeb` 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 + + +`CubicWeb` provides a lot of standard views for the type +`EntityView`, for a complete list, you +will have to read the code in directory ``cubicweb/web/views/`` + +A view is applied on a `result set` which contains a set of +entities we are trying to display. `CubicWeb` uses a selector +mecanism which computes a score used to identify which view +is the best to apply for the `result set` we are trying to +display. The standard library of selectors is in +``cubicweb.common.selector`` and a library of methods used to +compute scores is available in ``cubicweb.vregistry.vreq``. + +It is possible to define multiple views for the same identifier +and to associate selectors and filters to allow the application +to find the best way to render the data. We will see more details +on this in :ref:`DefinitionVues`. + +For example, the view named ``primary`` is the one used to display +a single entity. We will now show you hos to customize this view. + + +View customization +~~~~~~~~~~~~~~~~~~ + +If you wish to modify the way a `BlogEntry` is rendered, you will have to +overwrite the `primary` view defined in the module ``views`` of the cube +``cubes/blog/views.py``. + +We can by example add in front of the pulication date a prefix specifying +the date we see is the publication date. + +To do so, please apply the following changes: + +:: + + from cubicweb.web.views import baseviews + + + class BlogEntryPrimaryView(baseviews.PrimaryView): + + accepts = ('BlogEntry',) + + def render_entity_title(self, entity): + self.w(u'

%s

' % html_escape(entity.dc_title())) + + def content_format(self, entity): + return entity.view('reledit', rtype='content_format') + + def cell_call(self, row, col): + entity = self.entity(row, col) + + # display entity attributes with prefixes + self.w(u'

%s

' % entity.title) + self.w(u'

published on %s

' % entity.publish_date.strftime('%Y-%m-%d')) + self.w(u'

%s

' % entity.content) + + # display relations + siderelations = [] + if self.main_related_section: + self.render_entity_relations(entity, siderelations) + +.. note:: + When a view is modified, it is not required to restart the application + server. Save the Python file and reload the page in your web browser + to view the changes. + +You can now see that the publication date has a prefix. + +.. image:: images/cbw-update-primary-view.en.png + :alt: modified primary view + + +The above source code defines a new primary view for +``BlogEntry``. + +Since views are applied to resultsets and resulsets can be tables of +data, it is needed to recover the entity from its (row,col) +coordinates. We will get to this in more detail later. + +The view has a ``self.w()`` method that is used to output data. In our +example we use it to output HTML tags and values of the entity's attributes. + diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/01-introduction.en.txt --- a/doc/book/en/01-introduction.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,335 +0,0 @@ -.. -*- coding: utf-8 -*- - -.. _Overview: - -Quick overview of `CubicWeb` -============================ - -`CubicWeb` allows us to develop web applications instances based on -one or more `cubes`. - -What we call a `cube` is a model defining the data types and views. -A `cube` is a reusable component grouped with others cubes in the file -system. - -An `instance` refers to a specific installation of one or more `cubes` - where are grouped configuration files of the final web application. - -In this document, we will show you how to create a `cube` and how to use it -in an `instance` for your web application. - -Create your cube ----------------- - -After you installed your `CubicWeb` development environment, you can start -to build your first cube: :: - - cubicweb-ctl newcube blog - -This will create in ``/path/to/forest/cubes`` a directory containing: :: - - blog/ - | - |-- data/ - | |-- cubes.blog.css - | |-- cubes.blog.js - | |-- external_resources - | - |-- debian/ - | |-- changelog - | |-- compat - | |-- control - | |-- copyright - | |-- cubicweb-blog.prerm - | |-- rules - | - |-- entities.py - | - |-- i18n/ - | |-- en.po - | |-- fr.po - | - |-- __init__.py - | - |-- MANIFEST.in - | - |-- migration/ - | |-- postcreate.py - | |-- precreate.py - | - |-- __pkginfo__.py - | - |-- schema.py - | - |-- setup.py - | - |-- site_cubicweb.py - | - |-- sobjects.py - | - |-- test/ - | |-- data/ - | |-- bootstrap_cubes - | |-- pytestconf.py - | |-- realdb_test_blog.py - | |-- test_blog.py - | - |-- views.py - -Any changes applied to your data model should be done in this -directory. - - -Define your data schema ------------------------ - -The data model or schema is hte core of your `CubicWeb` application. -This is where is defined the type of content you application will handle. - -The data model is defined in the file ``schema.py`` of your cube -``blog`` such as follows. - -:: - - from cubicweb.schema import format_constraint - class Blog(EntityType): - title = String(maxsize=50, required=True) - description = String() - - class BlogEntry(EntityType): - title = String(required=True, fulltextindexed=True, maxsize=256) - publish_date = Date(default='TODAY') - content = String(required=True, fulltextindexed=True) - entry_of = SubjectRelation('Blog', cardinality='?*') - - -A Blog has a title and a description. The title is a string that is -required by the class EntityType and must be less than 50 characters. -The description is a string that is not constrained. - -A BlogEntry has a title, a publish_date and a content. The title is a -string that is required and must be less than 100 characters. The -publish_date is a Date with a default value of TODAY, meaning that -when a BlogEntry is created, its publish_date will be the current day -unless it is modified. The content is a string that will be indexed in -the full-text index and has no constraint. - -A BlogEntry also has a relationship ``entry_of`` that links it to a -Blog. The cardinality ``?*`` means that a BlogEntry can be part of -zero or one Blog (``?`` means `zero or one`) and that a Blog can -have any number of BlogEntry (``*`` means `any number including -zero`). For completeness, remember that ``+`` means `one or more`. - - -Create your instance --------------------- - -:: - - cubicweb-ctl create blog blogdemo - - -This command will create a directory ``~/etc/cubicweb.d/blogdemo`` -which will contain all the configuration files required to start -you web application. - -The instance ``blogdemo`` is based on the cube ``blog``. - - -Welcome in your web application -------------------------------- - -Run your application with the following command: :: - - cubicweb-ctl start -D blogdemo - - -You can now access to your web application to create blogs and post messages -by visitin the URL http://localhost:8080/. -A login form will first be prompted. By default, the application will not allow -anonymous user to get in the application. You should then use the admin -account you created at the time you initialized the database with -``cubicweb-ctl create``. - -.. image:: images/login-form.png - - -Once authenticated, you can start playing with your application -and create entities. Bravo! - -.. image:: images/blog-demo-first-page.png - -Please notice that so far, `CubicWeb` franework managed all aspects of -the web application based in the schema provided at first. - - -Create entities ---------------- - -We will now create a couple of entities in our web application. - -Create a Blog -~~~~~~~~~~~~~ - -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 ``Validate``. - -.. image:: images/cbw-create-blog.en.png - :alt: from to create blog - -Click on the logo at top left to get back to the home page, then -follow the Blog link that will list for you all the existing Blog. -You should be seeing a list with a single item ``Tech-blog`` you -just created. - -.. image:: images/cbw-list-one-blog.en.png - :alt: displaying a list of a single blog - -Clicking on this item will get you to its detailed description except -that in this case, there is not much to display besides the name and -the phrase ``everything about technology``. - -Now get back to the home page by clicking on the top-left logo, then -create a new Blog called ``MyLife`` and get back to the home page -again to follow the Blog link for the second time. The list now -has two items. - -.. image:: images/cbw-list-two-blog.en.png - :alt: displaying a list of two blogs - -Create a BlogEntry -~~~~~~~~~~~~~~~~~~ - -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 ``Validate``. You added a new blog entry without -saying to what blog it belongs. There is a box on the left entitled -``actions``, click on the menu item ``modify``. You are back to the form -to edit the blog entry you just created, except that the form now has -another section with a combobox titled ``add relation``. Chose -``entry_of`` in this menu and a second combobox appears where you pick -``MyLife``. - -You could also have, at the time you started to fill the form for a -new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the -combobox titled ``add relation`` would have showed up. - - -.. image:: images/cbw-add-relation-entryof.en.png - :alt: editing a blog entry to add a relation to a blog - -Validate the changes by clicking ``Validate``. The entity BlogEntry -that is displayed now includes a link to the entity Blog named -``MyLife``. - -.. image:: images/cbw-detail-one-blogentry.en.png - :alt: displaying the detailed view of a blogentry - -Please notice that so far, `CubicWeb` franework managed all aspects of -the web application based in the schema provided at first. -Also if you wish to get a graphical view of the schema, visit -the link `Application schema`` which will direct you to : -http://localhost:8080/view?vid=schema - -.. image:: images/cbw-schema.en.png - :alt: graphical view of the schema (aka data-model) - - -Define your entities views --------------------------- - -The views selection principle -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A view is defined by a Python class which includes: - - - an identifier (all objects in `CubicWeb` 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 - - -`CubicWeb` provides a lot of standard views for the type -`EntityView`, for a complete list, you -will have to read the code in directory ``cubicweb/web/views/`` - -A view is applied on a `result set` which contains a set of -entities we are trying to display. `CubicWeb` uses a selector -mecanism which computes a score used to identify which view -is the best to apply for the `result set` we are trying to -display. The standard library of selectors is in -``cubicweb.common.selector`` and a library of methods used to -compute scores is available in ``cubicweb.vregistry.vreq``. - -It is possible to define multiple views for the same identifier -and to associate selectors and filters to allow the application -to find the best way to render the data. We will see more details -on this in :ref:`DefinitionVues`. - -For example, the view named ``primary`` is the one used to display -a single entity. We will now show you hos to customize this view. - - -View customization -~~~~~~~~~~~~~~~~~~ - -If you wish to modify the way a `BlogEntry` is rendered, you will have to -overwrite the `primary` view defined in the module ``views`` of the cube -``cubes/blog/views.py``. - -We can by example add in front of the pulication date a prefix specifying -the date we see is the publication date. - -To do so, please apply the following changes: - -:: - - from cubicweb.web.views import baseviews - - - class BlogEntryPrimaryView(baseviews.PrimaryView): - - accepts = ('BlogEntry',) - - def render_entity_title(self, entity): - self.w(u'

%s

' % html_escape(entity.dc_title())) - - def content_format(self, entity): - return entity.view('reledit', rtype='content_format') - - def cell_call(self, row, col): - entity = self.entity(row, col) - - # display entity attributes with prefixes - self.w(u'

%s

' % entity.title) - self.w(u'

published on %s

' % entity.publish_date.strftime('%Y-%m-%d')) - self.w(u'

%s

' % entity.content) - - # display relations - siderelations = [] - if self.main_related_section: - self.render_entity_relations(entity, siderelations) - -.. note:: - When a view is modified, it is not required to restart the application - server. Save the Python file and reload the page in your web browser - to view the changes. - -You can now see that the publication date has a prefix. - -.. image:: images/cbw-update-primary-view.en.png - :alt: modified primary view - - -The above source code defines a new primary view for -``BlogEntry``. - -Since views are applied to resultsets and resulsets can be tables of -data, it is needed to recover the entity from its (row,col) -coordinates. We will get to this in more detail later. - -The view has a ``self.w()`` method that is used to output data. In our -example we use it to output HTML tags and values of the entity's attributes. - diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/02-00-foundation.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/02-00-foundation.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,567 @@ +.. -*- coding: utf-8 -*- + +`CubicWeb` concepts +=================== + +A little history... +------------------- + +`CubicWeb` is a web application framework developped by Logilab_ since 2001. + +Entirely written in Python, `CubicWeb` publishes data from all sorts +of sources such as SQL database, LDAP directory and versioning system such +as subversion. + +`CubicWeb` user interface was designed to let the final user a huge flexibility +on how to select and how to display content. It allows to browse the knowledge +database and to display the results with the best rendering according to +the context. +This interface flexibility gives back the user the control of the +rendering parameters that are usually reserved for developpers. + + +We can list a couple of web applications developped with `CubicWeb`, an online +public phone directory (see http://www.118000.fr/), a system for managing +digital studies and simulations for a research lab, a tool for shared children +babysitting (see http://garde-partagee.atoukontact.fr/), a tool to manage +software developpment (see http://www.logilab.org), etc. + +In 2008, `CubicWeb` was ported for a new type of source : the datastore +from GoogleAppEngine_. + +Global architecture +------------------- +.. image:: images/archi_globale.png + +.. note:: + For real, the client and server sides are integrated in the same + process and interact directly, without the needs for distants + calls using Pyro. It is important to note down that those two + sides, client/server, are disjointed and it is possible to execute + a couple of calls in distincts processes to balance the load of + your web site on one or more machines. + +.. _TermsVocabulary: + +Terms and vocabulary +-------------------- + +*schema* + The schema defines the data model of an application based on entities + and relations, modeled with a comprehensive language made of Python + classes based on `yams`_ library. This is the core piece + of an application. It is initially defined in the file system and is + stored in the database at the time an instance is created. `CubicWeb` + provides a certain number of system entities included automatically as + it is necessarry for the core of `CubicWeb` and a library of + cubes that can be explicitely included if necessary. + + +*entity type* + An entity is a set of attributes; the essential attribute of + an entity is its key, named eid + +*relation type* + Entities are linked to each others by relations. In `CubicWeb` + relations are binary: by convention we name the first item of + a relation the `subject` and the second the `object`. + +*final entity type* + Final types corresponds to the basic types such as string of characters, + integers... Those types have a main property which is that they can + only be used as `object` of a relation. The attributes of an entity + (non final) are entities (finals). + +*final relation type* + A relation is said final if its `object` is a final type. This is equivalent + to an entity attribute. + +*relation definition* + a relation definition is a 3-uple (subject entity type, relation type, object entity type), + with an associated set of property such as cardinality, constraints... + +*repository* + This is the RQL server side of `CubicWeb`. Be carefull not to get + confused with a Mercurial repository or a debian repository. + +*source* + A data source is a container of data (SGBD, LDAP directory, `Google + App Engine`'s datastore ...) integrated in the + `CubicWeb` repository. This repository has at least one source, `system` which + contains the schema of the application, plain-text index and others + vital informations for the system. + +*configuration* + It is possible to create differents configurations for an instance: + + - ``repository`` : repository only, accessible for clients using Pyro + - ``twisted`` : web interface only, access the repository using Pyro + - ``all-in-one`` : web interface and repository in a single process. + The repository could be or not accessible using Pyro. + +*cube* + A cube is a model grouping one or multiple data types and/or views + to provide a specific functionnality or a complete `CubicWeb` application + potentially using other cubes. The available subes are located in the file + system at `/path/to/forest/cubicweb/cubes`. + Larger applications can be built faster by importing cubes, + adding entities and relationships and overriding the + views that need to display or edit informations not provided by + cubes. + +*instance* + An instance is a specific installation of a cube. All the required + configuration files necessarry for the well being of your web application + are grouped in an instance. This will refer to the cube(s) your application + is based on. + By example logilab.org and our intranet are two instances of a single + cube jpl, developped internally. + The instances are defined in the directory `~/etc/cubicweb.d`. + +*application* + The term application is sometime used to talk about an instance + and sometimes to talk of a cube depending on the context. + So we would like to avoid using this term and try to use *cube* and + *instance* instead. + +*result set* + This object contains the results of an RQL query sent to the source + and information on the query. + +*Pyro* + `Python Remote Object`_, distributed objects system similar to Java's RMI + (Remote Method Invocation), which can be used for the dialog between the web + side of the framework and the RQL repository. + +*query language* + A full-blown query language named RQL is used to formulate requests + to the database or any sources such as LDAP or `Google App Engine`'s + datastore. + +*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. + + +.. _`Python Remote Object`: http://pyro.sourceforge.net/ +.. _`yams`: http://www.logilab.org/project/yams/ + + +`CubicWeb` engine +----------------- + +The engine in `CubicWeb` is a set of classes managing a set of objects loaded +dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamics objects, based on the schema +or the library, are building the final application. The differents dymanic components are +by example: + +* client and server side + + - entities definition, containing the logic which enables application data manipulation + +* client side + + - *views*, or more specifically + + - boxes + - header and footer + - forms + - page templates + + - *actions* + - *controllers* + +* server side + + - notification hooks + - notification views + +The components of the engine are: + +* a frontal web (only twisted is available so far), transparent for dynamic objects +* an object that encapsulates the configuration +* a `registry` (`cubicweb.cwvreg`) containing the dynamic objects loaded automatically + +Every *appobject* may access to the instance configuration using its *config* attribute +and to the registry using its *vreg* attribute. + +Details of the recording process +-------------------------------- + +At startup, the `registry` or registers base, inspects a number of directories +looking for compatible classes definition. After a recording process, the objects +are assigned to registers so that they can be selected dynamically while the +application is running. + +The base class of those objects is `AppRsetObject` (module `cubicweb.common.appobject`). + +XXX registers example +XXX actual details of the recording process! + +Runtime objects selection +------------------------- +XXX tell why it's a cw foundation! + +Application objects are stored in the registry using a two level hierarchy : + + object's `__registry__` : object's `id` : [list of app objects] + +The following rules are applied to select an object given a register and an id and an input context: +* each object has a selector + - its selector may be derivated from a set of basic (or not :) + selectors using `chainall` or `chainfirst` combinators +* a selector return a score >= 0 +* a score of 0 means the objects can't be applied to the input context +* the object with the greatest score is selected. If multiple objects have an + identical score, one of them is selected randomly (this is usually a bug) + +The object's selector is the `__selector__` class method on the object's class. + +The score is used to choose the most pertinent objects where there are more than +one selectable object. For instance, if you're selecting the primary +(eg `id = 'primary'`) view (eg `__registry__ = 'view'`) for a result set containing +a `Card` entity, 2 objects will probably be selectable: + +* the default primary view (`accepts = 'Any'`) +* the specific `Card` primary view (`accepts = 'Card'`) + +This is because primary views are using the `accept_selector` which is considering the +`accepts` class attribute of the object's class. Other primary views specific to other +entity types won't be selectable in this case. And among selectable objects, the +accept selector will return a higher score the the second view since it's more +specific, so it will be selected as expected. + +Usually, you won't define it directly but by defining the `__selectors__` tuple +on the class, with :: + + __selectors__ = (sel1, sel2) + +which is equivalent to :: + + __selector__ = chainall(sel1, sel2) + +The former is prefered since it's shorter and it's ease overriding in +subclasses (you have access to sub-selectors instead of the wrapping function). + +:chainall(selectors...): if one selector return 0, return 0, else return the sum of scores + +:chainfirst(selectors...): return the score of the first selector which has a non zero score + +XXX describe standard selector (link to generated api doc!) + +Example +~~~~~~~ +Le but final : quand on est sur un Blog, on veut que le lien rss de celui-ci pointe +vers les entrées de ce blog, non vers l'entité blog elle-même. + +L'idée générale pour résoudre ça : on définit une méthode sur les classes d'entité +qui renvoie l'url du flux rss pour l'entité en question. Avec une implémentation +par défaut sur AnyEntity et une implémentation particulière sur Blog qui fera ce +qu'on veut. + +La limitation : on est embêté dans le cas ou par ex. on a un result set qui contient +plusieurs entités Blog (ou autre chose), car on ne sait pas sur quelle entité appeler +la méthode sus-citée. Dans ce cas, on va conserver le comportement actuel (eg appel +à limited_rql) + +Donc : on veut deux cas ici, l'un pour un rset qui contient une et une seule entité, +l'autre pour un rset qui contient plusieurs entité. + +Donc... On a déja dans web/views/boxes.py la classe RSSIconBox qui fonctionne. Son +sélecteur :: + + class RSSIconBox(ExtResourcesBoxTemplate): + """just display the RSS icon on uniform result set""" + __selectors__ = ExtResourcesBoxTemplate.__selectors__ + (nfentity_selector,) + + +indique qu'il prend en compte : + +* les conditions d'apparition de la boite (faut remonter dans les classes parentes + pour voir le détail) +* nfentity_selector, qui filtre sur des rset contenant une liste d'entité non finale + +ça correspond donc à notre 2eme cas. Reste à fournir un composant plus spécifique +pour le 1er cas :: + + class EntityRSSIconBox(RSSIconBox): + """just display the RSS icon on uniform result set for a single entity""" + __selectors__ = RSSIconBox.__selectors__ + (onelinerset_selector,) + + +Ici, on ajoute onelinerset_selector, qui filtre sur des rset de taille 1. Il faut +savoir que quand on chaine des selecteurs, le score final est la somme des scores +renvoyés par chaque sélecteur (sauf si l'un renvoie zéro, auquel cas l'objet est +non sélectionnable). Donc ici, sur un rset avec plusieurs entités, onelinerset_selector +rendra la classe EntityRSSIconBox non sélectionnable, et on obtiendra bien la +classe RSSIconBox. Pour un rset avec une entité, la classe EntityRSSIconBox aura un +score supérieur à RSSIconBox et c'est donc bien elle qui sera sélectionnée. + +Voili voilou, il reste donc pour finir tout ça : + +* à définir le contenu de la méthode call de EntityRSSIconBox +* fournir l'implémentation par défaut de la méthode renvoyant l'url du flux rss sur + AnyEntity +* surcharger cette methode dans blog.Blog + +When to use selectors? +~~~~~~~~~~~~~~~~~~~~~~ +Il faut utiliser les sélecteurs pour faire des choses différentes en +fonction de ce qu'on a en entrée. Dès qu'on a un "if" qui teste la +nature de `self.rset` dans un objet, il faut très sérieusement se +poser la question s'il ne vaut pas mieux avoir deux objets différent +avec des sélecteurs approprié. + +If this is so fundamental, why don't I see them more often? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Because you're usually using base classes which are hiding the plumbing +of __registry__ (almost always), id (often when using "standard" object), +register and selector. + +API Python/RQL +-------------- + +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 : + +`execute(rqlstring, args=None, eid_key=None, build_descr=True)` + +:rqlstring: the RQL query to execute (unicode) +:args: if the query contains substitutions, a dictionnary containing the values to use +:eid_key: + an implementation detail of the RQL queries cache implies that if a substitution + is used to introduce an eid *susceptible to raise the ambiguities in the query + type resolution*, then we have to specify the correponding key in the dictionnary + through this argument + + +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. + +.. note:: + While executing updates queries (SET, INSERT, DELETE), if a query generates + an error related to security, a rollback is automatically done on the current + transaction. + + +The `Request` class (`cubicweb.web`) +------------------------------------ + +A request instance is created when an HTPP request is sent to the web server. +It contains informations such as forms 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 by example)** + +An instance of `Request` has the following attributes: + +* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated + user +* `form`, dictionnary containing the values of a web form +* `encoding`, characters encoding to use in the response + +But also: + +:Session data handling: + * `session_data()`, returns a dictinnary 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 dictionnary 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 (`EProperty`) + * dictionnary `data` to store data to share informations between components + *while a request is executed* + +Please note down 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. + +The `AppObject` class +--------------------- + +In general: + +* we do not inherit directly from this class but from a more specific + class such as `AnyEntity`, `EntityView`, `AnyRsetView`, + `Action`... + +* to be recordable, a subclass has to define its own register (attribute + `__registry__`) and its identifier (attribute `id`). Usually we do not have + to take care of the register, only the identifier `id`. + +We can find a certain number of attributes and methods defined in this class +and so common to all the application objects: + +At the recording, the following attributes are dynamically added to +the *subclasses*: + +* `vreg`, the `vregistry` of the application +* `schema`, the application schema +* `config`, the application configuration + +We also find on instances, the following attributes: + +* `req`, `Request` instance +* `rset`, the *result set* associated to the object if necessarry +* `cursor`, rql cursor on the session + + +:URL handling: + * `build_url(method=None, **kwargs)`, returns an absolute URL based on + the given arguments. The *controller* supposed to handle the response + can be specified through the special parameter `method` (the connection + is theoretically done automatically :). + + * `datadir_url()`, returns the directory of the application data + (contains static files such as images, css, js...) + + * `base_url()`, shortcut to `req.base_url()` + + * `url_quote(value)`, version *unicode safe* of the function `urllib.quote` + +:Data manipulation: + + * `etype_rset(etype, size=1)`, shortcut to `vreg.etype_rset()` + + * `eid_rset(eid, rql=None, descr=True)`, returns a *result set* object for + the given eid + * `entity(row, col=0)`, returns the entity corresponding to the data position + in the *result set* associated to the object + + * `complete_entity(row, col=0, skip_bytes=True)`, is equivalent to `entity` but + also call the method `complete()` on the entity before returning it + +:Data formatting: + * `format_date(date, date_format=None, time=False)` + * `format_time(time)` + +:And more...: + + * `external_resource(rid, default=_MARKER)`, access to a value defined in the + configuration file `external_resource` + + * `tal_render(template, variables)`, + + +.. note:: + When we inherit from `AppObject` (even not directly), you *always* have to use + **super()** to get the methods and attributes of the superclasses, and not + use the class identifier. + By example, instead of writting: :: + + class Truc(PrimaryView): + def f(self, arg1): + PrimaryView.f(self, arg1) + + You'd better write: :: + + class Truc(PrimaryView): + def f(self, arg1): + super(Truc, self).f(arg1) + + +Standard structure for a cube +----------------------------- + +A complex cube is structured as follows: + +:: + + mycube/ + | + |-- schema.py + | + |-- entities/ + | + |-- sobjects/ + | + |-- views/ + | + |-- test/ + | + |-- i18n/ + | + |-- data/ + | + |-- migration/ + | |- postcreate.py + | \- depends.map + | + |-- debian/ + | + \-- __pkginfo__.py + +We can use simple Python module instead of packages, by example: + +:: + + mycube/ + | + |-- entities.py + |-- hooks.py + \-- views.py + + +where : + +* ``schema`` contains the schema definition (server side only) +* ``entities`` contains the entities definition (server side and web interface) +* ``sobjects`` contains hooks and/or views notifications (server side only) +* ``views`` contains the different components of the web interface (web interface only) +* ``test`` contains tests specifics to the application (not installed) +* ``i18n`` contains the messages catalog for supported languages (server side and + web interface) +* ``data`` contains arbitrary data files served statically + (images, css, javascripts files)... (web interface only) +* ``migration`` contains the initialization file for new instances + (``postcreate.py``) and in general a file containing the `CubicWeb` dependancies + of the cube depending on its version (``depends.map``) +* ``debian`` contains all the files that manages the debian packaging + (you would find there the classical structure with ``control``, ``rules``, + ``changelog``... (not installed) +* the file ``__pkginfo__.py`` provides meta-data on the cube, especially the + distribution name and the current version (server side and web interface) or + also the sub-cubes used by this cube + +The only required files are: + +* 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 embeding for instance) diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/02-foundation.en.txt --- a/doc/book/en/02-foundation.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,567 +0,0 @@ -.. -*- coding: utf-8 -*- - -`CubicWeb` concepts -=================== - -A little history... -------------------- - -`CubicWeb` is a web application framework developped by Logilab_ since 2001. - -Entirely written in Python, `CubicWeb` publishes data from all sorts -of sources such as SQL database, LDAP directory and versioning system such -as subversion. - -`CubicWeb` user interface was designed to let the final user a huge flexibility -on how to select and how to display content. It allows to browse the knowledge -database and to display the results with the best rendering according to -the context. -This interface flexibility gives back the user the control of the -rendering parameters that are usually reserved for developpers. - - -We can list a couple of web applications developped with `CubicWeb`, an online -public phone directory (see http://www.118000.fr/), a system for managing -digital studies and simulations for a research lab, a tool for shared children -babysitting (see http://garde-partagee.atoukontact.fr/), a tool to manage -software developpment (see http://www.logilab.org), etc. - -In 2008, `CubicWeb` was ported for a new type of source : the datastore -from GoogleAppEngine_. - -Global architecture -------------------- -.. image:: images/archi_globale.png - -.. note:: - For real, the client and server sides are integrated in the same - process and interact directly, without the needs for distants - calls using Pyro. It is important to note down that those two - sides, client/server, are disjointed and it is possible to execute - a couple of calls in distincts processes to balance the load of - your web site on one or more machines. - -.. _TermsVocabulary: - -Terms and vocabulary --------------------- - -*schema* - The schema defines the data model of an application based on entities - and relations, modeled with a comprehensive language made of Python - classes based on `yams`_ library. This is the core piece - of an application. It is initially defined in the file system and is - stored in the database at the time an instance is created. `CubicWeb` - provides a certain number of system entities included automatically as - it is necessarry for the core of `CubicWeb` and a library of - cubes that can be explicitely included if necessary. - - -*entity type* - An entity is a set of attributes; the essential attribute of - an entity is its key, named eid - -*relation type* - Entities are linked to each others by relations. In `CubicWeb` - relations are binary: by convention we name the first item of - a relation the `subject` and the second the `object`. - -*final entity type* - Final types corresponds to the basic types such as string of characters, - integers... Those types have a main property which is that they can - only be used as `object` of a relation. The attributes of an entity - (non final) are entities (finals). - -*final relation type* - A relation is said final if its `object` is a final type. This is equivalent - to an entity attribute. - -*relation definition* - a relation definition is a 3-uple (subject entity type, relation type, object entity type), - with an associated set of property such as cardinality, constraints... - -*repository* - This is the RQL server side of `CubicWeb`. Be carefull not to get - confused with a Mercurial repository or a debian repository. - -*source* - A data source is a container of data (SGBD, LDAP directory, `Google - App Engine`'s datastore ...) integrated in the - `CubicWeb` repository. This repository has at least one source, `system` which - contains the schema of the application, plain-text index and others - vital informations for the system. - -*configuration* - It is possible to create differents configurations for an instance: - - - ``repository`` : repository only, accessible for clients using Pyro - - ``twisted`` : web interface only, access the repository using Pyro - - ``all-in-one`` : web interface and repository in a single process. - The repository could be or not accessible using Pyro. - -*cube* - A cube is a model grouping one or multiple data types and/or views - to provide a specific functionnality or a complete `CubicWeb` application - potentially using other cubes. The available subes are located in the file - system at `/path/to/forest/cubicweb/cubes`. - Larger applications can be built faster by importing cubes, - adding entities and relationships and overriding the - views that need to display or edit informations not provided by - cubes. - -*instance* - An instance is a specific installation of a cube. All the required - configuration files necessarry for the well being of your web application - are grouped in an instance. This will refer to the cube(s) your application - is based on. - By example logilab.org and our intranet are two instances of a single - cube jpl, developped internally. - The instances are defined in the directory `~/etc/cubicweb.d`. - -*application* - The term application is sometime used to talk about an instance - and sometimes to talk of a cube depending on the context. - So we would like to avoid using this term and try to use *cube* and - *instance* instead. - -*result set* - This object contains the results of an RQL query sent to the source - and information on the query. - -*Pyro* - `Python Remote Object`_, distributed objects system similar to Java's RMI - (Remote Method Invocation), which can be used for the dialog between the web - side of the framework and the RQL repository. - -*query language* - A full-blown query language named RQL is used to formulate requests - to the database or any sources such as LDAP or `Google App Engine`'s - datastore. - -*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. - - -.. _`Python Remote Object`: http://pyro.sourceforge.net/ -.. _`yams`: http://www.logilab.org/project/yams/ - - -`CubicWeb` engine ------------------ - -The engine in `CubicWeb` is a set of classes managing a set of objects loaded -dynamically at the startup of `CubicWeb` (*appobjects*). Those dynamics objects, based on the schema -or the library, are building the final application. The differents dymanic components are -by example: - -* client and server side - - - entities definition, containing the logic which enables application data manipulation - -* client side - - - *views*, or more specifically - - - boxes - - header and footer - - forms - - page templates - - - *actions* - - *controllers* - -* server side - - - notification hooks - - notification views - -The components of the engine are: - -* a frontal web (only twisted is available so far), transparent for dynamic objects -* an object that encapsulates the configuration -* a `registry` (`cubicweb.cwvreg`) containing the dynamic objects loaded automatically - -Every *appobject* may access to the instance configuration using its *config* attribute -and to the registry using its *vreg* attribute. - -Details of the recording process --------------------------------- - -At startup, the `registry` or registers base, inspects a number of directories -looking for compatible classes definition. After a recording process, the objects -are assigned to registers so that they can be selected dynamically while the -application is running. - -The base class of those objects is `AppRsetObject` (module `cubicweb.common.appobject`). - -XXX registers example -XXX actual details of the recording process! - -Runtime objects selection -------------------------- -XXX tell why it's a cw foundation! - -Application objects are stored in the registry using a two level hierarchy : - - object's `__registry__` : object's `id` : [list of app objects] - -The following rules are applied to select an object given a register and an id and an input context: -* each object has a selector - - its selector may be derivated from a set of basic (or not :) - selectors using `chainall` or `chainfirst` combinators -* a selector return a score >= 0 -* a score of 0 means the objects can't be applied to the input context -* the object with the greatest score is selected. If multiple objects have an - identical score, one of them is selected randomly (this is usually a bug) - -The object's selector is the `__selector__` class method on the object's class. - -The score is used to choose the most pertinent objects where there are more than -one selectable object. For instance, if you're selecting the primary -(eg `id = 'primary'`) view (eg `__registry__ = 'view'`) for a result set containing -a `Card` entity, 2 objects will probably be selectable: - -* the default primary view (`accepts = 'Any'`) -* the specific `Card` primary view (`accepts = 'Card'`) - -This is because primary views are using the `accept_selector` which is considering the -`accepts` class attribute of the object's class. Other primary views specific to other -entity types won't be selectable in this case. And among selectable objects, the -accept selector will return a higher score the the second view since it's more -specific, so it will be selected as expected. - -Usually, you won't define it directly but by defining the `__selectors__` tuple -on the class, with :: - - __selectors__ = (sel1, sel2) - -which is equivalent to :: - - __selector__ = chainall(sel1, sel2) - -The former is prefered since it's shorter and it's ease overriding in -subclasses (you have access to sub-selectors instead of the wrapping function). - -:chainall(selectors...): if one selector return 0, return 0, else return the sum of scores - -:chainfirst(selectors...): return the score of the first selector which has a non zero score - -XXX describe standard selector (link to generated api doc!) - -Example -~~~~~~~ -Le but final : quand on est sur un Blog, on veut que le lien rss de celui-ci pointe -vers les entrées de ce blog, non vers l'entité blog elle-même. - -L'idée générale pour résoudre ça : on définit une méthode sur les classes d'entité -qui renvoie l'url du flux rss pour l'entité en question. Avec une implémentation -par défaut sur AnyEntity et une implémentation particulière sur Blog qui fera ce -qu'on veut. - -La limitation : on est embêté dans le cas ou par ex. on a un result set qui contient -plusieurs entités Blog (ou autre chose), car on ne sait pas sur quelle entité appeler -la méthode sus-citée. Dans ce cas, on va conserver le comportement actuel (eg appel -à limited_rql) - -Donc : on veut deux cas ici, l'un pour un rset qui contient une et une seule entité, -l'autre pour un rset qui contient plusieurs entité. - -Donc... On a déja dans web/views/boxes.py la classe RSSIconBox qui fonctionne. Son -sélecteur :: - - class RSSIconBox(ExtResourcesBoxTemplate): - """just display the RSS icon on uniform result set""" - __selectors__ = ExtResourcesBoxTemplate.__selectors__ + (nfentity_selector,) - - -indique qu'il prend en compte : - -* les conditions d'apparition de la boite (faut remonter dans les classes parentes - pour voir le détail) -* nfentity_selector, qui filtre sur des rset contenant une liste d'entité non finale - -ça correspond donc à notre 2eme cas. Reste à fournir un composant plus spécifique -pour le 1er cas :: - - class EntityRSSIconBox(RSSIconBox): - """just display the RSS icon on uniform result set for a single entity""" - __selectors__ = RSSIconBox.__selectors__ + (onelinerset_selector,) - - -Ici, on ajoute onelinerset_selector, qui filtre sur des rset de taille 1. Il faut -savoir que quand on chaine des selecteurs, le score final est la somme des scores -renvoyés par chaque sélecteur (sauf si l'un renvoie zéro, auquel cas l'objet est -non sélectionnable). Donc ici, sur un rset avec plusieurs entités, onelinerset_selector -rendra la classe EntityRSSIconBox non sélectionnable, et on obtiendra bien la -classe RSSIconBox. Pour un rset avec une entité, la classe EntityRSSIconBox aura un -score supérieur à RSSIconBox et c'est donc bien elle qui sera sélectionnée. - -Voili voilou, il reste donc pour finir tout ça : - -* à définir le contenu de la méthode call de EntityRSSIconBox -* fournir l'implémentation par défaut de la méthode renvoyant l'url du flux rss sur - AnyEntity -* surcharger cette methode dans blog.Blog - -When to use selectors? -~~~~~~~~~~~~~~~~~~~~~~ -Il faut utiliser les sélecteurs pour faire des choses différentes en -fonction de ce qu'on a en entrée. Dès qu'on a un "if" qui teste la -nature de `self.rset` dans un objet, il faut très sérieusement se -poser la question s'il ne vaut pas mieux avoir deux objets différent -avec des sélecteurs approprié. - -If this is so fundamental, why don't I see them more often? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Because you're usually using base classes which are hiding the plumbing -of __registry__ (almost always), id (often when using "standard" object), -register and selector. - -API Python/RQL --------------- - -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 : - -`execute(rqlstring, args=None, eid_key=None, build_descr=True)` - -:rqlstring: the RQL query to execute (unicode) -:args: if the query contains substitutions, a dictionnary containing the values to use -:eid_key: - an implementation detail of the RQL queries cache implies that if a substitution - is used to introduce an eid *susceptible to raise the ambiguities in the query - type resolution*, then we have to specify the correponding key in the dictionnary - through this argument - - -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. - -.. note:: - While executing updates queries (SET, INSERT, DELETE), if a query generates - an error related to security, a rollback is automatically done on the current - transaction. - - -The `Request` class (`cubicweb.web`) ------------------------------------- - -A request instance is created when an HTPP request is sent to the web server. -It contains informations such as forms 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 by example)** - -An instance of `Request` has the following attributes: - -* `user`, instance of `cubicweb.common.utils.User` corresponding to the authenticated - user -* `form`, dictionnary containing the values of a web form -* `encoding`, characters encoding to use in the response - -But also: - -:Session data handling: - * `session_data()`, returns a dictinnary 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 dictionnary 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 (`EProperty`) - * dictionnary `data` to store data to share informations between components - *while a request is executed* - -Please note down 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. - -The `AppObject` class ---------------------- - -In general: - -* we do not inherit directly from this class but from a more specific - class such as `AnyEntity`, `EntityView`, `AnyRsetView`, - `Action`... - -* to be recordable, a subclass has to define its own register (attribute - `__registry__`) and its identifier (attribute `id`). Usually we do not have - to take care of the register, only the identifier `id`. - -We can find a certain number of attributes and methods defined in this class -and so common to all the application objects: - -At the recording, the following attributes are dynamically added to -the *subclasses*: - -* `vreg`, the `vregistry` of the application -* `schema`, the application schema -* `config`, the application configuration - -We also find on instances, the following attributes: - -* `req`, `Request` instance -* `rset`, the *result set* associated to the object if necessarry -* `cursor`, rql cursor on the session - - -:URL handling: - * `build_url(method=None, **kwargs)`, returns an absolute URL based on - the given arguments. The *controller* supposed to handle the response - can be specified through the special parameter `method` (the connection - is theoretically done automatically :). - - * `datadir_url()`, returns the directory of the application data - (contains static files such as images, css, js...) - - * `base_url()`, shortcut to `req.base_url()` - - * `url_quote(value)`, version *unicode safe* of the function `urllib.quote` - -:Data manipulation: - - * `etype_rset(etype, size=1)`, shortcut to `vreg.etype_rset()` - - * `eid_rset(eid, rql=None, descr=True)`, returns a *result set* object for - the given eid - * `entity(row, col=0)`, returns the entity corresponding to the data position - in the *result set* associated to the object - - * `complete_entity(row, col=0, skip_bytes=True)`, is equivalent to `entity` but - also call the method `complete()` on the entity before returning it - -:Data formatting: - * `format_date(date, date_format=None, time=False)` - * `format_time(time)` - -:And more...: - - * `external_resource(rid, default=_MARKER)`, access to a value defined in the - configuration file `external_resource` - - * `tal_render(template, variables)`, - - -.. note:: - When we inherit from `AppObject` (even not directly), you *always* have to use - **super()** to get the methods and attributes of the superclasses, and not - use the class identifier. - By example, instead of writting: :: - - class Truc(PrimaryView): - def f(self, arg1): - PrimaryView.f(self, arg1) - - You'd better write: :: - - class Truc(PrimaryView): - def f(self, arg1): - super(Truc, self).f(arg1) - - -Standard structure for a cube ------------------------------ - -A complex cube is structured as follows: - -:: - - mycube/ - | - |-- schema.py - | - |-- entities/ - | - |-- sobjects/ - | - |-- views/ - | - |-- test/ - | - |-- i18n/ - | - |-- data/ - | - |-- migration/ - | |- postcreate.py - | \- depends.map - | - |-- debian/ - | - \-- __pkginfo__.py - -We can use simple Python module instead of packages, by example: - -:: - - mycube/ - | - |-- entities.py - |-- hooks.py - \-- views.py - - -where : - -* ``schema`` contains the schema definition (server side only) -* ``entities`` contains the entities definition (server side and web interface) -* ``sobjects`` contains hooks and/or views notifications (server side only) -* ``views`` contains the different components of the web interface (web interface only) -* ``test`` contains tests specifics to the application (not installed) -* ``i18n`` contains the messages catalog for supported languages (server side and - web interface) -* ``data`` contains arbitrary data files served statically - (images, css, javascripts files)... (web interface only) -* ``migration`` contains the initialization file for new instances - (``postcreate.py``) and in general a file containing the `CubicWeb` dependancies - of the cube depending on its version (``depends.map``) -* ``debian`` contains all the files that manages the debian packaging - (you would find there the classical structure with ``control``, ``rules``, - ``changelog``... (not installed) -* the file ``__pkginfo__.py`` provides meta-data on the cube, especially the - distribution name and the current version (server side and web interface) or - also the sub-cubes used by this cube - -The only required files are: - -* 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 embeding for instance) diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-00-definition-schema.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/03-00-definition-schema.en.txt Thu Nov 20 20:14:23 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 " ". 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 diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-00-sect-definition-schema.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/03-00-sect-definition-schema.en.txt Thu Nov 20 20:14:23 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__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 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__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] diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-00-sect-stdlib-schemas.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/03-00-sect-stdlib-schemas.en.txt Thu Nov 20 20:14:23 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. + diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-00-setup.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/03-00-setup.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,13 @@ +.. -*- coding: utf-8 -*- + +.. _MiseEnPlaceEnv: + +=================================================== +Installation and set-up of a `CubicWeb` environment +=================================================== +.. contents:: + +.. include:: 03-01-installation.en.txt +.. include:: 03-02-create-instance.en.txt +.. include:: 03-03-cubicweb-ctl.en.txt + diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-definition-schema.en.txt --- a/doc/book/en/03-definition-schema.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,20 +0,0 @@ -.. -*- 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 " ". 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 diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-sect-definition-schema.en.txt --- a/doc/book/en/03-sect-definition-schema.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,344 +0,0 @@ -.. -*- 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__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 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__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] diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-sect-stdlib-schemas.en.txt --- a/doc/book/en/03-sect-stdlib-schemas.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -.. -*- 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. - diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/03-setup.en.txt --- a/doc/book/en/03-setup.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -.. -*- coding: utf-8 -*- - -.. _MiseEnPlaceEnv: - -=================================================== -Installation and set-up of a `CubicWeb` environment -=================================================== -.. contents:: - -.. include:: 03-01-installation.en.txt -.. include:: 03-02-create-instance.en.txt -.. include:: 03-03-cubicweb-ctl.en.txt - diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/04-00-define-schema.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/04-00-define-schema.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,22 @@ +.. -*- coding: utf-8 -*- + +Data model definition (*schema*) +================================ + +The schema is the core piece of a `CubicWeb` application as it defines +the data model handled. It is based on entities types already defined +in the `CubicWeb` standard library and others, more specific, we would +expect to find in one or more Python files under the `schema` directory. + +At this point, 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 +" ". +A relation type could have been implied if none is related to a +relation definition of the schema. + + +.. include:: 04-01-schema-stdlib.en.txt +.. include:: 04-02-schema-definition.en.txt + diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/04-define-schema.en.txt --- a/doc/book/en/04-define-schema.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -.. -*- coding: utf-8 -*- - -Data model definition (*schema*) -================================ - -The schema is the core piece of a `CubicWeb` application as it defines -the data model handled. It is based on entities types already defined -in the `CubicWeb` standard library and others, more specific, we would -expect to find in one or more Python files under the `schema` directory. - -At this point, 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 -" ". -A relation type could have been implied if none is related to a -relation definition of the schema. - - -.. include:: 04-01-schema-stdlib.en.txt -.. include:: 04-02-schema-definition.en.txt - diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/05-00-define-views.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/05-00-define-views.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,238 @@ +.. -*- coding: utf-8 -*- + +.. _DefinitionVues: + +Views definition +================ + +Basic class for views +--------------------- + +Class `View` (`cubicweb.common.view`) +````````````````````````````````````` + +A view writes in its output exit thanks to its attribute `w` (`UStreamIO`). + +The basic interface for views is as follows: + +* `dispatch(**context)`, render the view by calling `call` or + `cell_call` depending on the given parameters +* `call(**kwargs)`, call the view for a complete result set or null +* `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set +* `url()`, returns the URL enabling us to get the view with the current + result set +* `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier + `__vid` on the given result set. It is possible to give a view identifier + of fallback that will be used if the view requested is not applicable to the + result set + +* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except + the flow is automatically passed in the parameters + +* `html_headers()`, returns a list of HTML headers to set by the main template + +* `page_title()`, returns the title to use in the HTML header `title` + +* `creator(eid)`, returns the eid and the login of the entity creator of the entity + having the eid given in the parameter + +Other basic classes: + +* `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 applied to any result set + + +The selection view principle +---------------------------- + +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 + + +For a given identifier, multiple views can be defined. `CubicWeb` uses +a selector which computes scores so that it can identify and select the +best view to apply in context. The selector library is in +``cubicweb.common.selector`` and a library of the methods used to +compute scores is in ``cubicweb.vregistry.vreq``. + + +`CubicWeb` provides a lot of standard views, for a complete list, you +will have to read the code in directory ``cubicweb/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'

%s

' % entity.title) + 10. self.w(u'

published on %s in category %s

' % \ + 11. (entity.publish_date.strftime('%Y-%m-%d'), entity.category)) + 12. self.w(u'

%s

' % 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'

%s

' % entity.title) + 08. self.w(u'

%s

' % 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 `CubicWeb`. 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 cubicwweb.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. +[FILLME] + + +Templates +--------- + +*Templates* are specific view that does not depend on a result set. The basic +class `Template` (`cubicweb.common.view`) is derived from the class `View`. + +To build a HTML page, a *main template* is used. In general, the template of +identifier `main` is the one (it is not used in case an error is raised or for +the login form by example). This template uses other templates in addition +to the views which depends on the content to generate the HTML page to return. + +A *template* is responsible for: + +1. executing RQL query of data to render if necessarry +2. identifying the view to use to render data if it is not specified +3. composing the HTML page to return + + +The default main template (`cubicweb.web.views.basetemplates.TheMainTemplate`) +------------------------------------------------------------------------------ + +The default main template build the page based on the following pattern: + +.. image:: images/main_template_layout.png + +The rectangle containing `view.dispathc()` represents the area where the content +view has to be displayed. The others represents sub-templates called to complete +the page. A default implementation of those is provided in +`cubicweb.views.basetemplates`. You can, of course, overload those sub-templates +to implement your own customization of the HTML page. + +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 dictionnary of the forms parameters, before going the classic way (through + step 1 and 2 described juste above) + +.. include:: 05-01-views-stdlib.en.txt + + +XML views, binaries... +---------------------- +For the views generating other formats that HTML (an image generated dynamically +by example), and which can not usually be included in the HTML page generated +by the main template (see above), you have to: + +* set the atribute `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` + +For the views dedicated to binary content creation (an image dynamically generated +by example), we have to set the attribute `binary` of the class to `True` (which +implies that `templateable == False`, so that the attribute `w` of the view could be +replaced by a binary flow instead of unicode). + +(X)HTML tricks to apply +----------------------- + +Some web browser (Firefox by example) are not happy with empty `
` +(by empty we mean that there is no content in the tag, but there +could be attributes), so we should always use `
` even if +it is empty and not use `
`. + diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/05-define-views.en.txt --- a/doc/book/en/05-define-views.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -.. -*- coding: utf-8 -*- - -.. _DefinitionVues: - -Views definition -================ - -Basic class for views ---------------------- - -Class `View` (`cubicweb.common.view`) -````````````````````````````````````` - -A view writes in its output exit thanks to its attribute `w` (`UStreamIO`). - -The basic interface for views is as follows: - -* `dispatch(**context)`, render the view by calling `call` or - `cell_call` depending on the given parameters -* `call(**kwargs)`, call the view for a complete result set or null -* `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set -* `url()`, returns the URL enabling us to get the view with the current - result set -* `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier - `__vid` on the given result set. It is possible to give a view identifier - of fallback that will be used if the view requested is not applicable to the - result set - -* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except - the flow is automatically passed in the parameters - -* `html_headers()`, returns a list of HTML headers to set by the main template - -* `page_title()`, returns the title to use in the HTML header `title` - -* `creator(eid)`, returns the eid and the login of the entity creator of the entity - having the eid given in the parameter - -Other basic classes: - -* `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 applied to any result set - - -The selection view principle ----------------------------- - -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 - - -For a given identifier, multiple views can be defined. `CubicWeb` uses -a selector which computes scores so that it can identify and select the -best view to apply in context. The selector library is in -``cubicweb.common.selector`` and a library of the methods used to -compute scores is in ``cubicweb.vregistry.vreq``. - - -`CubicWeb` provides a lot of standard views, for a complete list, you -will have to read the code in directory ``cubicweb/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'

%s

' % entity.title) - 10. self.w(u'

published on %s in category %s

' % \ - 11. (entity.publish_date.strftime('%Y-%m-%d'), entity.category)) - 12. self.w(u'

%s

' % 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'

%s

' % entity.title) - 08. self.w(u'

%s

' % 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 `CubicWeb`. 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 cubicwweb.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. -[FILLME] - - -Templates ---------- - -*Templates* are specific view that does not depend on a result set. The basic -class `Template` (`cubicweb.common.view`) is derived from the class `View`. - -To build a HTML page, a *main template* is used. In general, the template of -identifier `main` is the one (it is not used in case an error is raised or for -the login form by example). This template uses other templates in addition -to the views which depends on the content to generate the HTML page to return. - -A *template* is responsible for: - -1. executing RQL query of data to render if necessarry -2. identifying the view to use to render data if it is not specified -3. composing the HTML page to return - - -The default main template (`cubicweb.web.views.basetemplates.TheMainTemplate`) ------------------------------------------------------------------------------- - -The default main template build the page based on the following pattern: - -.. image:: images/main_template_layout.png - -The rectangle containing `view.dispathc()` represents the area where the content -view has to be displayed. The others represents sub-templates called to complete -the page. A default implementation of those is provided in -`cubicweb.views.basetemplates`. You can, of course, overload those sub-templates -to implement your own customization of the HTML page. - -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 dictionnary of the forms parameters, before going the classic way (through - step 1 and 2 described juste above) - -.. include:: 05-01-views-stdlib.en.txt - - -XML views, binaries... ----------------------- -For the views generating other formats that HTML (an image generated dynamically -by example), and which can not usually be included in the HTML page generated -by the main template (see above), you have to: - -* set the atribute `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` - -For the views dedicated to binary content creation (an image dynamically generated -by example), we have to set the attribute `binary` of the class to `True` (which -implies that `templateable == False`, so that the attribute `w` of the view could be -replaced by a binary flow instead of unicode). - -(X)HTML tricks to apply ------------------------ - -Some web browser (Firefox by example) are not happy with empty `
` -(by empty we mean that there is no content in the tag, but there -could be attributes), so we should always use `
` even if -it is empty and not use `
`. - diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/06-00-define-workflows.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/06-00-define-workflows.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,154 @@ +.. -*- coding: utf-8 -*- + +Définition de workflow +====================== +On peut mettre une condition rql ou/et un groupe auquel doit appartenir l'utilisateur. + +Si on met à la fois un(ou plusieurs) groupe et une condition RQL, il faut que les deux soient respectés. + +Si on met plusieurs groupes, il faut que l'utilisateur soit dans un des groupes. + +Pour la condition RQL sur une transition, on peut y mettre les substitutions suivantes : + +* `%(eid)s`, eid de l'objet +* `%(ueid)s`, eid de l'utilisateur qui fait la requête +* `%(seid)s`, eid de l'état courant de l'objet + +Dans le script de création d'un workflow, penser à mettre `_()` autour des noms d'états et de transitions +pour que ceux si soient pris en compte par les scripts de gestion des catalogues i18n. + +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] + +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. + +There are two ways to create a workflow, form the user interface, +and also by defining it in ``migration/postcreate.py``. This script +is executed each time a new ``./bin/laxctl db-init`` is done. +If you create the states and transitions through the user interface +this means that next time you will need to initialize the database +you will have to re-create all the entities. +We strongly recommand you create the workflow in ``migration\postcreate.py`` +and we will now show you how. +The user interface would only be a reference for you to view the states +and transitions but is not the appropriate interface to define your +application workflow. + +Update the schema +~~~~~~~~~~~~~~~~~ +To enable a BlogEntry to have a State, we have to define a relation +``in_state`` in the schema of BlogEntry. Please do as follows, add +the line ``in_state (...)``:: + + class BlogEntry(EntityType): + title = String(maxsize=100, required=True) + publish_date = Date(default='TODAY') + text_format = String(meta=True, internationalizable=True, maxsize=50, + default='text/rest', constraints=[format_constraint]) + text = String(fulltextindexed=True) + category = String(vocabulary=('important','business')) + entry_of = SubjectRelation('Blog', cardinality='?*') + in_state = SubjectRelation('State', cardinality='1*') + +As you updated the schema, you will have re-execute ``./bin/laxctl db-init`` +to initialize the database and migrate your existing entities. +[WRITE ABOUT MIGRATION] + +Create states, transitions and group permissions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +At the time the ``postcreate.py`` script is executed, several methods +can be used. They are all defined in the ``class ServerMigrationHelper``. +We will only discuss the method we use to create a wrokflow here. + +To define our workflow for BlogDemo, please add the following lines +to ``migration/postcreate.py``:: + + _ = unicode + + moderators = add_entity('EGroup', name=u"moderators") + + submitted = add_state(_('submitted'), 'BlogEntry', initial=True) + published = add_state(_('published'), 'BlogEntry') + + add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) + + checkpoint() + +``add_entity`` is used here to define the new group of users that we +need to define the transitions, `moderators`. +If this group required by the transition is not defined before the +transition is created, it will not create the relation `transition +require the group moderator`. + +``add_state`` expects as the first argument the name of the state you are +willing to create, then the entity type on which the state can be applied, +and an optionnal argument to set if the state is the initial state +of the entity type or not. + +``add_transition`` expects as the first argument the name of the +transition, then the entity type on which we can apply the transition, +then the list of possible initial states from which the transition +can be applied, the target state of the transition, and the permissions +(e.g. list of the groups of users who can apply the transition). + +.. image:: images/lax-book.03-transitions-view.en.png + +You can now notice that in the actions box of a BlogEntry, the state +is now listed as well as the possible transitions from this state +defined by the workflow. This transition, as defined in the workflow, +will only being displayed for the users belonging to the group +moderators of managers. + + diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/06-define-workflows.en.txt --- a/doc/book/en/06-define-workflows.en.txt Thu Nov 20 10:25:44 2008 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -.. -*- coding: utf-8 -*- - -Définition de workflow -====================== -On peut mettre une condition rql ou/et un groupe auquel doit appartenir l'utilisateur. - -Si on met à la fois un(ou plusieurs) groupe et une condition RQL, il faut que les deux soient respectés. - -Si on met plusieurs groupes, il faut que l'utilisateur soit dans un des groupes. - -Pour la condition RQL sur une transition, on peut y mettre les substitutions suivantes : - -* `%(eid)s`, eid de l'objet -* `%(ueid)s`, eid de l'utilisateur qui fait la requête -* `%(seid)s`, eid de l'état courant de l'objet - -Dans le script de création d'un workflow, penser à mettre `_()` autour des noms d'états et de transitions -pour que ceux si soient pris en compte par les scripts de gestion des catalogues i18n. - -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] - -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. - -There are two ways to create a workflow, form the user interface, -and also by defining it in ``migration/postcreate.py``. This script -is executed each time a new ``./bin/laxctl db-init`` is done. -If you create the states and transitions through the user interface -this means that next time you will need to initialize the database -you will have to re-create all the entities. -We strongly recommand you create the workflow in ``migration\postcreate.py`` -and we will now show you how. -The user interface would only be a reference for you to view the states -and transitions but is not the appropriate interface to define your -application workflow. - -Update the schema -~~~~~~~~~~~~~~~~~ -To enable a BlogEntry to have a State, we have to define a relation -``in_state`` in the schema of BlogEntry. Please do as follows, add -the line ``in_state (...)``:: - - class BlogEntry(EntityType): - title = String(maxsize=100, required=True) - publish_date = Date(default='TODAY') - text_format = String(meta=True, internationalizable=True, maxsize=50, - default='text/rest', constraints=[format_constraint]) - text = String(fulltextindexed=True) - category = String(vocabulary=('important','business')) - entry_of = SubjectRelation('Blog', cardinality='?*') - in_state = SubjectRelation('State', cardinality='1*') - -As you updated the schema, you will have re-execute ``./bin/laxctl db-init`` -to initialize the database and migrate your existing entities. -[WRITE ABOUT MIGRATION] - -Create states, transitions and group permissions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -At the time the ``postcreate.py`` script is executed, several methods -can be used. They are all defined in the ``class ServerMigrationHelper``. -We will only discuss the method we use to create a wrokflow here. - -To define our workflow for BlogDemo, please add the following lines -to ``migration/postcreate.py``:: - - _ = unicode - - moderators = add_entity('EGroup', name=u"moderators") - - submitted = add_state(_('submitted'), 'BlogEntry', initial=True) - published = add_state(_('published'), 'BlogEntry') - - add_transition(_('approve_blogentry'), 'BlogEntry', (submitted,), published, ('moderators', 'managers'),) - - checkpoint() - -``add_entity`` is used here to define the new group of users that we -need to define the transitions, `moderators`. -If this group required by the transition is not defined before the -transition is created, it will not create the relation `transition -require the group moderator`. - -``add_state`` expects as the first argument the name of the state you are -willing to create, then the entity type on which the state can be applied, -and an optionnal argument to set if the state is the initial state -of the entity type or not. - -``add_transition`` expects as the first argument the name of the -transition, then the entity type on which we can apply the transition, -then the list of possible initial states from which the transition -can be applied, the target state of the transition, and the permissions -(e.g. list of the groups of users who can apply the transition). - -.. image:: images/lax-book.03-transitions-view.en.png - -You can now notice that in the actions box of a BlogEntry, the state -is now listed as well as the possible transitions from this state -defined by the workflow. This transition, as defined in the workflow, -will only being displayed for the users belonging to the group -moderators of managers. - - diff -r 52bf52e6fc77 -r 1091d8d63f51 doc/book/en/07-00-data-as-objects.en.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/book/en/07-00-data-as-objects.en.txt Thu Nov 20 20:14:23 2008 +0100 @@ -0,0 +1,142 @@ +.. -*- coding: utf-8 -*- + + +Manipulation des données stockées +================================= + +Les classes `Entity` et `AnyEntity` +----------------------------------- +Pour fournir un comportement spécifique à un type d'entité, il suffit de définir +une classe héritant de la class `ginco.entities.AnyEntity`. En général il faut +définir ces classes dans un module du package `entities` d'une application pour +qu'elle soit disponible à la fois coté serveur et coté client. + +La classe `AnyEntity` est une classe chargée dynamiquement héritant de la classe +de base `Entity` (`ginco.common.entity`). On définit une sous-classe pour +ajouter des méthodes ou spécialiser les comportements d'un type d'entité donné. + +Des descripteurs sont ajoutés à l'enregistrement pour initialiser la classe en +fonction du schéma : + +* on peut accéder aux attributs définis dans le schéma via les attributs de même + nom sur les instances (valeur typée) + +* on peut accéder aux relations définies dans le schéma via les attributs de même + nom sur les instances (liste d'instances d'entité) + +Les méthodes définies sur la classe `AnyEntity` ou `Entity` sont les suivantes : + +* `has_eid()`, retourne vrai si l'entité à un eid affecté (i.e. pas en cours de + création) + +* `check_perm(action)`, vérifie que l'utilisateur à le droit d'effectuer + l'action demandée sur l'entité + +:Formattage et génération de la sortie: + + * `view(vid, **kwargs)`, applique la vue donnée à l'entité + + * `absolute_url(**kwargs)`, retourne une URL absolue permettant d'accéder à la + vue primaire d'une entité + + * `rest_path()`, renvoie une l'URL REST relative permettant d'obtenir l'entité + + * `format(attr)`, retourne le format (type MIME) du champ passé en argument + + * `printable_value(attr, value=_marker, attrtype=None, format='text/html')`, + retourne une chaine permettant l'affichage dans un format donné de la valeur + d'un attribut (la valeur est automatiquement récupérée au besoin) + + * `display_name(form='')`, retourne une chaîne pour afficher le type de + l'entité, en spécifiant éventuellement la forme désirée ('plural' pour la + forme plurielle) + +:Gestion de données: + + * `as_rset()`, transforme l'entité en un resultset équivalent simulant + le résultat de la requête `Any X WHERE X eid _eid_` + + * `complete(skip_bytes=True)`, effectue une requête permettant de récupérer d'un + coup toutes les valeurs d'attributs manquant sur l'entité + + * `get_value(name)`, récupere la valeur associée à l'attribut passé en argument + + * `related(rtype, x='subject', limit=None, entities=False)`, retourne une liste + des entités liées à l'entité courant par la relation donnée en argument + + * `unrelated(rtype, targettype, x='subject', limit=None)`, retourne un result set + des entités not liées à l'entité courante par la relation donnée en argument + et satisfaisants les contraintes de celle-ci + + * `set_attributes(**kwargs)`, met à jour la liste des attributs avec + les valeurs correspondantes passées sous forme d'arguments nommés + + * `copy_relations(ceid)`, copie les relations de l'entité ayant l'eid passé en + argument sur l'entité courante + + * `last_modified(view)`, retourne la date à laquelle on doit considérer + l'objet comme modifié (utiliser par la gestion de cache HTTP) + + * `delete()` permet de supprimer l'entité représentée + +:Meta-données standard (Dublin Core): + + * `dc_title()`, retourne une chaine unicode correspondant à la méta-donnée + 'Title' (utilise par défaut le premier attribut non 'meta' du schéma de + l'entité) + + * `dc_long_title()`, comme dc_title mais peut retourner un titre plus détaillé + + * `dc_description(format='text/plain')`, retourne une chaine unicode + correspondant à la méta-donnée 'Description' (cherche un attribut + 'description' par défaut) + + * `dc_authors()`, retourne une chaine unicode correspondant à la méta-donnée + 'Authors' (propriétaires par défaut) + + * `dc_date(date_format=None)`, retourne une chaine unicode + correspondant à la méta-donnée 'Date' (date de modification par défaut) + +:Contrôle du vocabulaire pour les relations: + + * `vocabulary(rtype, x='subject', limit=None)`, appelée notamment + par les vues d'édition d'erudi, elle renvoie une liste de couple + (label, eid) des entités qui pourraient être liées à l'entité + via la relation `rtype` + * `subject_relation_vocabulary(rtype, limit=None)`, appelée + en interne par `vocabulary` dans le cas d'une relation sujet + * `object_relation_vocabulary(rtype, limit=None)`, appelée + en interne par `vocabulary` dans le cas d'une relation objet + * `relation_vocabulary(rtype, targettype, x, limit=None)`, appelé + en interne par `subject_relation_vocabulary` et `object_relation_vocabulary` + + +Les *rtags* +----------- +Les *rtags* permettent de spécifier certains comportements propres aux relations +d'un type d'entité donné (voir plus loin). Ils sont définis sur la classe +d'entité via l'attribut `rtags` qui est un dictionnaire dont les clés sont un +triplet :: + + , , , ,