[doc] Restructure the documentation
* Create a new index file
* Move the sphinx configuration files do the documentation root
* Move book/README to dev/documenting.rst
* Move book/mode_plan.py to tools/
* Move book/en/images to images
* Move book/en/* to book/
* Move changelogs to changes/*
* Adapt the Makefile
* Add a title to the javascript api index
Related to #4832808
--- a/.hgignore Mon Jul 06 17:39:35 2015 +0200
+++ b/.hgignore Thu Jan 08 22:11:06 2015 +0100
@@ -18,4 +18,7 @@
^doc/html/
^doc/doctrees/
^doc/book/en/devweb/js_api/
+^doc/_build
+^doc/js_api/
+data/pgdb/
data.*/pgdb.*
--- a/doc/3.14.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,164 +0,0 @@
-Whats new in CubicWeb 3.14
-==========================
-
-First notice CW 3.14 depends on yams 0.34 (which is incompatible with prior
-cubicweb releases regarding instance re-creation).
-
-API changes
------------
-
-* `Entity.fetch_rql` `restriction` argument has been deprecated and should be
- replaced with a call to the new `Entity.fetch_rqlst` method, get the returned
- value (a rql `Select` node) and use the RQL syntax tree API to include the
- above-mentionned restrictions.
-
- Backward compat is kept with proper warning.
-
-* `Entity.fetch_order` and `Entity.fetch_unrelated_order` class methods have been
- replaced by `Entity.cw_fetch_order` and `Entity.cw_fetch_unrelated_order` with
- a different prototype:
-
- - instead of taking (attr, var) as two string argument, they now take (select,
- attr, var) where select is the rql syntax tree beinx constructed and var the
- variable *node*.
-
- - instead of returning some string to be inserted in the ORDERBY clause, it has
- to modify the syntax tree
-
- Backward compat is kept with proper warning, BESIDE cases below:
-
- - custom order method return **something else the a variable name with or
- without the sorting order** (e.g. cases where you sort on the value of a
- registered procedure as it was done in the tracker for instance). In such
- case, an error is logged telling that this sorting is ignored until API
- upgrade.
-
- - client code use direct access to one of those methods on an entity (no code
- known to do that).
-
-* `Entity._rest_attr_info` class method has been renamed to
- `Entity.cw_rest_attr_info`
-
- No backward compat yet since this is a protected method an no code is known to
- use it outside cubicweb itself.
-
-* `AnyEntity.linked_to` has been removed as part of a refactoring of this
- functionality (link a entity to another one at creation step). It was replaced
- by a `EntityFieldsForm.linked_to` property.
-
- In the same refactoring, `cubicweb.web.formfield.relvoc_linkedto`,
- `cubicweb.web.formfield.relvoc_init` and
- `cubicweb.web.formfield.relvoc_unrelated` were removed and replaced by
- RelationField methods with the same names, that take a form as a parameter.
-
- **No backward compatibility yet**. It's still time to cry for it.
- Cubes known to be affected: tracker, vcsfile, vcreview.
-
-* `CWPermission` entity type and its associated require_permission relation type
- (abstract) and require_group relation definitions have been moved to a new
- `localperms` cube. With this have gone some functions from the
- `cubicweb.schemas` package as well as some views. This makes cubicweb itself
- smaller while you get all the local permissions stuff into a single,
- documented, place.
-
- Backward compat is kept for existing instances, **though you should have
- installed the localperms cubes**. A proper error should be displayed when
- trying to migrate to 3.14 an instance the use `CWPermission` without the new
- cube installed. For new instances / test, you should add a dependancy on the
- new cube in cubes using this feature, along with a dependancy on cubicweb >=
- 3.14.
-
-* jQuery has been updated to 1.6.4 and jquery-tablesorter to 2.0.5. No backward
- compat issue known.
-
-* Table views refactoring : new `RsetTableView` and `EntityTableView`, as well as
- rewritten an enhanced version of `PyValTableView` on the same bases, with logic
- moved to some column renderers and a layout. Those should be well documented
- and deprecates former `TableView`, `EntityAttributesTableView` and `CellView`,
- which are however kept for backward compat, with some warnings that may not be
- very clear unfortunatly (you may see your own table view subclass name here,
- which doesn't make the problem that clear). Notice that `_cw.view('table',
- rset, *kwargs)` will be routed to the new `RsetTableView` or to the old
- `TableView` depending on given extra arguments. See #1986413.
-
-* `display_name` don't call .lower() anymore. This may leads to changes in your
- user interface. Different msgid for upper/lower cases version of entity type
- names, as this is the only proper way to handle this with some languages.
-
-* `IEditControlAdapter` has been deprecated in favor of `EditController`
- overloading, which was made easier by adding dedicated selectors called
- `match_edited_type` and `match_form_id`.
-
-* Pre 3.6 API backward compat has been dropped, though *data* migration
- compatibility has been kept. You may have to fix errors due to old API usage
- for your instance before to be able to run migration, but then you should be
- able to upgrade even a pre 3.6 database.
-
-* Deprecated `cubicweb.web.views.iprogress` in favor of new `iprogress` cube.
-
-* Deprecated `cubicweb.web.views.flot` in favor of new `jqplot` cube.
-
-
-Unintrusive API changes
------------------------
-
-* Refactored properties forms (eg user preferences and site wide properties) as
- well as pagination components to ease overridding.
-
-* New `cubicweb.web.uihelper` module with high-level helpers for uicfg.
-
-* New `anonymized_request` decorator to temporary run stuff as an anonymous
- user, whatever the currently logged in user.
-
-* New 'verbatimattr' attribute view.
-
-* New facet and form widget for Integer used to store binary mask.
-
-* New `js_href` function to generated proper javascript href.
-
-* `match_kwargs` and `match_form_params` selectors both accept a new
- `once_is_enough` argument.
-
-* `printable_value` is now a method of request, and may be given dict of
- formatters to use.
-
-* `[Rset]TableView` allows to set None in 'headers', meaning the label should be
- fetched from the result set as done by default.
-
-* Field vocabulary computation on entity creation now takes `__linkto`
- information into accounet.
-
-* Started a `cubicweb.pylintext` pylint plugin to help pylint analyzing cubes.
-
-
-RQL
----
-
-* Support for HAVING in 'SET' and 'DELETE' queries.
-
-* new `AT_TZ` function to get back a timestamp at a given time-zone.
-
-* new `WEEKDAY` date extraction function
-
-
-User interface changes
-----------------------
-
-* Datafeed source now present an history of the latest import's log, including
- global status and debug/info/warning/error messages issued during
- imports. Import logs older than a configurable amount of time are automatically
- deleted.
-
-* Breadcrumbs component is properly kept when creating an entity with '__linkto'.
-
-* users and groups management now really lead to that (i.e. includes *groups*
- management).
-
-* New 'jsonp' controller with 'jsonexport' and 'ejsonexport' views.
-
-
-Configuration
-------------
-
-* Added option 'resources-concat' to make javascript/css files concatenation
- optional.
--- a/doc/3.15.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-What's new in CubicWeb 3.15?
-============================
-
-New functionnalities
---------------------
-
-* Add Zmq server, based on the cutting edge ZMQ (http://www.zeromq.org/) socket
- library. This allows to access distant instance, in a similar way as Pyro.
-
-* Publish/subscribe mechanism using ZMQ for communication among cubicweb
- instances. The new zmq-address-sub and zmq-address-pub configuration variables
- define where this communication occurs. As of this release this mechanism is
- used for entity cache invalidation.
-
-* Improved WSGI support. While there is still some caveats, most of the code
- which was twisted only is now generic and allows related functionalities to work
- with a WSGI front-end.
-
-* Full undo/transaction support : undo of modification has eventually been
- implemented, and the configuration simplified (basically you activate it or not
- on an instance basis).
-
-* Controlling HTTP status code used is not much more easier :
-
- - `WebRequest` now has a `status_out` attribut to control the response status ;
-
- - most web-side exceptions take an optional ``status`` argument.
-
-API changes
------------
-
-* The base registry implementation has been moved to a new
- `logilab.common.registry` module (see #1916014). This includes code from :
-
- * `cubicweb.vreg` (the whole things that was in there)
- * `cw.appobject` (base selectors and all).
-
- In the process, some renaming was done:
-
- * the top level registry is now `RegistryStore` (was `VRegistry`), but that
- should not impact cubicweb client code ;
-
- * former selectors functions are now known as "predicate", though you still use
- predicates to build an object'selector ;
-
- * for consistency, the `objectify_selector` decoraror has hence be renamed to
- `objectify_predicate` ;
-
- * on the CubicWeb side, the `selectors` module has been renamed to
- `predicates`.
-
- Debugging refactoring dropped the more need for the `lltrace` decorator. There
- should be full backward compat with proper deprecation warnings. Notice the
- `yes` predicate and `objectify_predicate` decorator, as well as the
- `traced_selection` function should now be imported from the
- `logilab.common.registry` module.
-
-* All login forms are now submitted to <app_root>/login. Redirection to requested
- page is now handled by the login controller (it was previously handle by the
- session manager).
-
-* `Publisher.publish` has been renamed to `Publisher.handle_request`. This
- method now contains generic version of logic previously handled by
- Twisted. `Controller.publish` is **not** affected.
-
-Unintrusive API changes
------------------------
-
-* New 'ldapfeed' source type, designed to replace 'ldapuser' source with
- data-feed (i.e. copy based) source ideas.
-
-* New 'zmqrql' source type, similar to 'pyrorql' but using ømq instead of Pyro.
-
-* A new registry called `services` has appeared, where you can register
- server-side `cubicweb.server.Service` child classes. Their `call` method can be
- invoked from a web-side AppObject instance using new `self._cw.call_service`
- method or a server-side one using `self.session.call_service`. This is a new
- way to call server-side methods, much cleaner than monkey patching the
- Repository class, which becomes a deprecated way to perform similar tasks.
-
-* a new `ajax-func` registry now hosts all remote functions (i.e. functions
- callable through the `asyncRemoteExec` JS api). A convenience `ajaxfunc`
- decorator will let you expose your python function easily without all the
- appobject standard boilerplate. Backward compatibility is preserved.
-
-* the 'json' controller is now deprecated in favor of the 'ajax' one.
-
-* `WebRequest.build_url` can now take a __secure__ argument. When True cubicweb
- try to generate an https url.
-
-
-User interface changes
-----------------------
-
-A new 'undohistory' view expose the undoable transactions and give access to undo
-some of them.
--- a/doc/3.16.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-What's new in CubicWeb 3.16?
-============================
-
-New functionalities
---------------------
-
-* Add a new dataimport store (`SQLGenObjectStore`). This store enables a fast
- import of data (entity creation, link creation) in CubicWeb, by directly
- flushing information in SQL. This may only be used with PostgreSQL, as it
- requires the 'COPY FROM' command.
-
-
-API changes
------------
-
-* Orm: `set_attributes` and `set_relations` are unified (and
- deprecated) in favor of `cw_set` that works in all cases.
-
-* db-api/configuration: all the external repository connection information is
- now in an URL (see `#2521848 <http://www.cubicweb.org/2521848>`_),
- allowing to drop specific options of pyro nameserver host, group, etc and fix
- broken `ZMQ <http://www.zeromq.org/>`_ source. Configuration related changes:
-
- * Dropped 'pyro-ns-host', 'pyro-instance-id', 'pyro-ns-group' from the client side
- configuration, in favor of 'repository-uri'. **NO MIGRATION IS DONE**,
- supposing there is no web-only configuration in the wild.
-
- * Stop discovering the connection method through `repo_method` class attribute
- of the configuration, varying according to the configuration class. This is
- a first step on the way to a simpler configuration handling.
-
- DB-API related changes:
-
- * Stop indicating the connection method using `ConnectionProperties`.
-
- * Drop `_cnxtype` attribute from `Connection` and `cnxtype` from
- `Session`. The former is replaced by a `is_repo_in_memory` property
- and the later is totaly useless.
-
- * Turn `repo_connect` into `_repo_connect` to mark it as a private function.
-
- * Deprecate `in_memory_cnx` which becomes useless, use `_repo_connect` instead
- if necessary.
-
-* the "tcp://" uri scheme used for `ZMQ <http://www.zeromq.org/>`_
- communications (in a way reminiscent of Pyro) is now named
- "zmqpickle-tcp://", so as to make room for future zmq-based lightweight
- communications (without python objects pickling).
-
-* Request.base_url gets a `secure=True` optional parameter that yields
- an https url if possible, allowing hook-generated content to send
- secure urls (e.g. when sending mail notifications)
-
-* Dataimport ucsvreader gets a new boolean `ignore_errors`
- parameter.
-
-
-Unintrusive API changes
------------------------
-
-* Drop of `cubicweb.web.uicfg.AutoformSectionRelationTags.bw_tag_map`,
- deprecated since 3.6.
-
-
-User interface changes
-----------------------
-
-* The RQL search bar has now some auto-completion support. It means
- relation types or entity types can be suggested while typing. It is
- an awesome improvement over the current behaviour !
-
-* The `action box` associated with `table` views (from `tableview.py`)
- has been transformed into a nice-looking series of small tabs; it
- means that the possible actions are immediately visible and need not
- be discovered by clicking on an almost invisible icon on the upper
- right.
-
-* The `uicfg` module has moved to web/views/ and ui configuration
- objects are now selectable. This will reduce the amount of
- subclassing and whole methods replacement usually needed to
- customize the ui behaviour in many cases.
-
-* Remove changelog view, as neither cubicweb nor known
- cubes/applications were properly feeding related files.
-
-
-Other changes
--------------
-
-* 'pyrorql' sources will be automatically updated to use an URL to locate the source
- rather than configuration option. 'zmqrql' sources were broken before this change,
- so no upgrade is needed...
-
-* Debugging filters for Hooks and Operations have been added.
-
-* Some cubicweb-ctl commands used to show the output of `msgcat` and
- `msgfmt`; they don't anymore.
--- a/doc/3.17.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-What's new in CubicWeb 3.17?
-============================
-
-New functionalities
---------------------
-
-* add a command to compare db schema and file system schema
- (see `#464991 <http://www.cubicweb.org/464991>`_)
-
-* Add CubicWebRequestBase.content with the content of the HTTP request (see #2742453)
- (see `#2742453 <http://www.cubicweb.org/2742453>`_)
-
-* Add directive bookmark to ReST rendering
- (see `#2545595 <http://www.cubicweb.org/ticket/2545595>`_)
-
-* Allow user defined final type
- (see `#124342 <https://www.logilab.org/ticket/124342>`_)
-
-
-API changes
------------
-
-* drop typed_eid() in favour of int() (see `#2742462 <http://www.cubicweb.org/2742462>`_)
-
-* The SIOC views and adapters have been removed from CubicWeb and moved to the
- `sioc` cube.
-
-* The web page embedding views and adapters have been removed from CubicWeb and
- moved to the `embed` cube.
-
-* The email sending views and controllers have been removed from CubicWeb and
- moved to the `massmailing` cube.
-
-* ``RenderAndSendNotificationView`` is deprecated in favor of
- ``ActualNotificationOp`` the new operation use the more efficient *data*
- idiom.
-
-* Looping task can now have a interval <= ``0``. Negative interval disable the
- looping task entirely.
-
-* We now serve html instead of xhtml.
- (see `#2065651 <http://www.cubicweb.org/ticket/2065651>`_)
-
-
-Deprecation
----------------------
-
-* ``ldapuser`` have been deprecated. It'll be fully dropped in the next
- version. If you are still using ldapuser switch to ``ldapfeed`` **NOW**!
-
-* ``hijack_user`` have been deprecated. It will be dropped soon.
-
-Deprecated Code Drops
-----------------------
-
-* The progress views and adapters have been removed from CubicWeb. These
- classes were deprecated since 3.14.0. They are still available in the
- `iprogress` cube.
-
-* API deprecated since 3.7 have been dropped.
--- a/doc/3.18.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-What's new in CubicWeb 3.18?
-============================
-
-The migration script does not handle sqlite nor mysql instances.
-
-
-New functionalities
---------------------
-
-* add a security debugging tool
- (see `#2920304 <http://www.cubicweb.org/2920304>`_)
-
-* introduce an `add` permission on attributes, to be interpreted at
- entity creation time only and allow the implementation of complex
- `update` rules that don't block entity creation (before that the
- `update` attribute permission was interpreted at entity creation and
- update time)
-
-* the primary view display controller (uicfg) now has a
- `set_fields_order` method similar to the one available for forms
-
-* new method `ResultSet.one(col=0)` to retrive a single entity and enforce the
- result has only one row (see `#3352314 https://www.cubicweb.org/ticket/3352314`_)
-
-* new method `RequestSessionBase.find` to look for entities
- (see `#3361290 https://www.cubicweb.org/ticket/3361290`_)
-
-* the embedded jQuery copy has been updated to version 1.10.2, and jQuery UI to
- version 1.10.3.
-
-* initial support for wsgi for the debug mode, available through the new
- ``wsgi`` cubicweb-ctl command, which can use either python's builtin
- wsgi server or the werkzeug module if present.
-
-* a ``rql-table`` directive is now available in ReST fields
-
-* cubicweb-ctl upgrade can now generate the static data resource directory
- directly, without a manual call to gen-static-datadir.
-
-API changes
------------
-
-* not really an API change, but the entity permission checks are now
- systematically deferred to an operation, instead of a) trying in a
- hook and b) if it failed, retrying later in an operation
-
-* The default value storage for attributes is no longer String, but
- Bytes. This opens the road to storing arbitrary python objects, e.g.
- numpy arrays, and fixes a bug where default values whose truth value
- was False were not properly migrated.
-
-* `symmetric` relations are no more handled by an rql rewrite but are
- now handled with hooks (from the `activeintegrity` category); this
- may have some consequences for applications that do low-level database
- manipulations or at times disable (some) hooks.
-
-* `unique together` constraints (multi-columns unicity constraints)
- get a `name` attribute that maps the CubicWeb contraint entities to
- corresponding backend index.
-
-* BreadCrumbEntityVComponent's open_breadcrumbs method now includes
- the first breadcrumbs separator
-
-* entities can be compared for equality and hashed
-
-* the ``on_fire_transition`` predicate accepts a sequence of possible
- transition names
-
-* the GROUP_CONCAT rql aggregate function no longer repeats duplicate
- values, on the sqlite and postgresql backends
-
-Deprecation
----------------------
-
-* ``pyrorql`` sources have been deprecated. Multisource will be fully dropped
- in the next version. If you are still using pyrorql, switch to ``datafeed``
- **NOW**!
-
-* the old multi-source system
-
-* `find_one_entity` and `find_entities` in favor of `find`
- (see `#3361290 https://www.cubicweb.org/ticket/3361290`_)
-
-* the `TmpFileViewMixin` and `TmpPngView` classes (see `#3400448
- https://www.cubicweb.org/ticket/3400448`_)
-
-Deprecated Code Drops
-----------------------
-
-* ``ldapuser`` have been dropped; use ``ldapfeed`` now
- (see `#2936496 <http://www.cubicweb.org/2936496>`_)
-
-* action ``GotRhythm`` was removed, make sure you do not
- import it in your cubes (even to unregister it)
- (see `#3093362 <http://www.cubicweb.org/3093362>`_)
-
-* all 3.8 backward compat is gone
-
-* all 3.9 backward compat (including the javascript side) is gone
-
-* the ``twisted`` (web-only) instance type has been removed
--- a/doc/3.19.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,180 +0,0 @@
-What's new in CubicWeb 3.19?
-============================
-
-New functionalities
---------------------
-
-* implement Cross Origin Resource Sharing (CORS)
- (see `#2491768 <http://www.cubicweb.org/2491768>`_)
-
-* system_source.create_eid can get a range of IDs, to reduce overhead of batch
- entity creation
-
-Behaviour Changes
------------------
-
-* The anonymous property of Session and Connection are now computed from the
- related user login. If it matches the ``anonymous-user`` in the config the
- connection is anonymous. Beware that the ``anonymous-user`` config is web
- specific. Therefore, no session may be anonymous in a repository only setup.
-
-
-New Repository Access API
--------------------------
-
-Connection replaces Session
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A new explicit Connection object replaces Session as the main repository entry
-point. Connection holds all the necessary methods to be used server-side
-(``execute``, ``commit``, ``rollback``, ``call_service``, ``entity_from_eid``,
-etc...). One obtains a new Connection object using ``session.new_cnx()``.
-Connection objects need to have an explicit begin and end. Use them as a context
-manager to never miss an end::
-
- with session.new_cnx() as cnx:
- cnx.execute('INSERT Elephant E, E name "Babar"')
- cnx.commit()
- cnx.execute('INSERT Elephant E, E name "Celeste"')
- cnx.commit()
- # Once you get out of the "with" clause, the connection is closed.
-
-Using the same Connection object in multiple threads will give you access to the
-same Transaction. However, Connection objects are not thread safe (hence at your
-own risks).
-
-``repository.internal_session`` is deprecated in favor of
-``repository.internal_cnx``. Note that internal connections are now `safe` by default,
-i.e. the integrity hooks are enabled.
-
-Backward compatibility is preserved on Session.
-
-
-dbapi vs repoapi
-~~~~~~~~~~~~~~~~
-
-A new API has been introduced to replace the dbapi. It is called `repoapi`.
-
-There are three relevant functions for now:
-
-* ``repoapi.get_repository`` returns a Repository object either from an
- URI when used as ``repoapi.get_repository(uri)`` or from a config
- when used as ``repoapi.get_repository(config=config)``.
-
-* ``repoapi.connect(repo, login, **credentials)`` returns a ClientConnection
- associated with the user identified by the credentials. The
- ClientConnection is associated with its own Session that is closed
- when the ClientConnection is closed. A ClientConnection is a
- Connection-like object to be used client side.
-
-* ``repoapi.anonymous_cnx(repo)`` returns a ClientConnection associated
- with the anonymous user if described in the config.
-
-
-repoapi.ClientConnection replace dbapi.Connection and company
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-On the client/web side, the Request is now using a ``repoapi.ClientConnection``
-instead of a ``dbapi.connection``. The ``ClientConnection`` has multiple backward
-compatible methods to make it look like a ``dbapi.Cursor`` and ``dbapi.Connection``.
-
-Session used on the Web side are now the same than the one used Server side.
-Some backward compatibility methods have been installed on the server side Session
-to ease the transition.
-
-The authentication stack has been altered to use the ``repoapi`` instead of
-the ``dbapi``. Cubes adding new element to this stack are likely to break.
-
-Session data can be accessed using the cnx.data dictionary, while
-transaction data is available through cnx.transaction_data. These
-replace the [gs]et_shared_data methods with optional txid kwarg.
-
-New API in tests
-~~~~~~~~~~~~~~~~
-
-All current methods and attributes used to access the repo on ``CubicWebTC`` are
-deprecated. You may now use a ``RepoAccess`` object. A ``RepoAccess`` object is
-linked to a new ``Session`` for a specified user. It is able to create
-``Connection``, ``ClientConnection`` and web side requests linked to this
-session::
-
- access = self.new_access('babar') # create a new RepoAccess for user babar
- with access.repo_cnx() as cnx:
- # some work with server side cnx
- cnx.execute(...)
- cnx.commit()
- cnx.execute(...)
- cnx.commit()
-
- with access.client_cnx() as cnx:
- # some work with client side cnx
- cnx.execute(...)
- cnx.commit()
-
- with access.web_request(elephant='babar') as req:
- # some work with client side cnx
- elephant_name = req.form['elephant']
- req.execute(...)
- req.cnx.commit()
-
-By default ``testcase.admin_access`` contains a ``RepoAccess`` object for the
-default admin session.
-
-
-API changes
------------
-
-* ``RepositorySessionManager.postlogin`` is now called with two arguments,
- request and session. And this now happens before the session is linked to the
- request.
-
-* ``SessionManager`` and ``AuthenticationManager`` now take a repo object at
- initialization time instead of a vreg.
-
-* The ``async`` argument of ``_cw.call_service`` has been dropped. All calls are
- now synchronous. The zmq notification bus looks like a good replacement for
- most async use cases.
-
-* ``repo.stats()`` is now deprecated. The same information is available through
- a service (``_cw.call_service('repo_stats')``).
-
-* ``repo.gc_stats()`` is now deprecated. The same information is available through
- a service (``_cw.call_service('repo_gc_stats')``).
-
-* ``repo.register_user()`` is now deprecated. The functionality is now
- available through a service (``_cw.call_service('register_user')``).
-
-* ``request.set_session`` no longer takes an optional ``user`` argument.
-
-* CubicwebTC does not have repo and cnx as class attributes anymore. They are
- standard instance attributes. ``set_cnx`` and ``_init_repo`` class methods
- become instance methods.
-
-* ``set_cnxset`` and ``free_cnxset`` are deprecated. cnxset are now
- automatically managed.
-
-* The implementation of cascading deletion when deleting `composite`
- entities has changed. There comes a semantic change: merely deleting
- a composite relation does not entail any more the deletion of the
- component side of the relation.
-
-* ``_cw.user_callback`` and ``_cw.user_rql_callback`` are deprecated. Users
- are encouraged to write an actual controller (e.g. using ``ajaxfunc``)
- instead of storing a closure in the session data.
-
-* A new ``entity.cw_linkable_rql`` method provides the rql to fetch all entities
- that are already or may be related to the current entity using the given
- relation.
-
-
-Deprecated Code Drops
-----------------------
-
-* session.hijack_user mechanism has been dropped.
-
-* EtypeRestrictionComponent has been removed, its functionality has been
- replaced by facets a while ago.
-
-* the old multi-source support has been removed. Only copy-based sources
- remain, such as datafeed or ldapfeed.
-
--- a/doc/3.20.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-What's new in CubicWeb 3.20
-===========================
-
-New features
-------------
-
-* virtual relations: a new ComputedRelation class can be used in
- schema.py; its `rule` attribute is an RQL snippet that defines the new
- relation.
-
-* computed attributes: an attribute can now be defined with a `formula`
- argument (also an RQL snippet); it will be read-only, and updated
- automatically.
-
- Both of these features are described in `CWEP-002`_, and the updated
- "Data model" chapter of the CubicWeb book.
-
-* cubicweb-ctl plugins can use the ``cubicweb.utils.admincnx`` function
- to get a Connection object from an instance name.
-
-* new 'tornado' wsgi backend
-
-* session cookies have the HttpOnly flag, so they're no longer exposed to
- javascript
-
-* rich text fields can be formatted as markdown
-
-* the edit controller detects concurrent editions, and raises a ValidationError
- if an entity was modified between form generation and submission
-
-* cubicweb can use a postgresql "schema" (namespace) for its tables
-
-* "cubicweb-ctl configure" can be used to set values of the admin user
- credentials in the sources configuration file
-
-* in debug mode, setting the _cwtracehtml parameter on a request allows tracing
- where each bit of output is produced
-
-.. _CWEP-002: http://hg.logilab.org/review/cwep/file/tip/CWEP-002.rst
-
-
-API Changes
------------
-
-* ``ucsvreader()`` and ``ucsvreader_pb()`` from the ``dataimport`` module have
- 2 new keyword arguments ``delimiter`` and ``quotechar`` to replace the
- ``separator`` and ``quote`` arguments respectively. This makes the API match
- that of Python's ``csv.reader()``. The old arguments are still supported
- though deprecated.
-
-* the migration environment's ``remove_cube`` function is now called ``drop_cube``.
-
-* cubicweb.old.css is now cubicweb.css. The previous "new"
- cubicweb.css, along with its cubicweb.reset.css companion, have been
- removed.
-
-* the jquery-treeview plugin was updated to its latest version
-
-
-Deprecated Code Drops
-----------------------
-
-* most of 3.10 and 3.11 backward compat is gone; this includes:
- - CtxComponent.box_action() and CtxComponent.build_link()
- - cubicweb.devtools.htmlparser.XMLDemotingValidator
- - various methods and properties on Entities, replaced by cw_edited and cw_attr_cache
- - 'commit_event' method on hooks, replaced by 'postcommit_event'
- - server.hook.set_operation(), replaced by Operation.get_instance(...).add_data()
- - View.div_id(), View.div_class() and View.create_url()
- - `*VComponent` classes
- - in forms, Field.value() and Field.help() must take the form and the field itself as arguments
- - form.render() must get `w` as a named argument, and renderer.render() must take `w` as first argument
- - in breadcrumbs, the optional `recurs` argument must be a set, not False
- - cubicweb.web.views.idownloadable.{download_box,IDownloadableLineView}
- - primary views no longer have `render_entity_summary` and `summary` methods
- - WFHistoryVComponent's `cell_call` method is replaced by `render_body`
- - cubicweb.dataimport.ObjectStore.add(), replaced by create_entity
- - ManageView.{folders,display_folders}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/Makefile Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,88 @@
+SRC=.
+
+# You can set these sphinx variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+#BUILDDIR = build
+BUILDDIR = _build
+CWDIR = ..
+JSDIR = ${CWDIR}/web/data
+JSTORST = tools/pyjsrest.py
+BUILDJS = js_api
+
+# Internal variables for sphinx
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d ${BUILDDIR}/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+
+
+.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " all to make standalone HTML files, developer manual and API doc"
+ @echo " html to make standalone HTML files"
+ @echo "--- "
+ @echo " pickle to make pickle files (usable by e.g. sphinx-web)"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " changes to make an overview over all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+
+clean:
+ rm -f *.html
+ -rm -rf ${BUILDDIR}/html ${BUILDDIR}/doctrees
+ -rm -rf ${BUILDJS}
+
+all: html
+
+# run sphinx ###
+html: js
+ mkdir -p ${BUILDDIR}/html ${BUILDDIR}/doctrees
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) ${BUILDDIR}/html
+ @echo
+ @echo "Build finished. The HTML pages are in ${BUILDDIR}/html."
+
+js:
+ mkdir -p ${BUILDJS}
+ $(JSTORST) -p ${JSDIR} -o ${BUILDJS}
+
+pickle:
+ mkdir -p ${BUILDDIR}/pickle ${BUILDDIR}/doctrees
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) ${BUILDDIR}/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files or run"
+ @echo " sphinx-web ${BUILDDIR}/pickle"
+ @echo "to start the sphinx-web server."
+
+web: pickle
+
+htmlhelp:
+ mkdir -p ${BUILDDIR}/htmlhelp ${BUILDDIR}/doctrees
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) ${BUILDDIR}/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in ${BUILDDIR}/htmlhelp."
+
+latex:
+ mkdir -p ${BUILDDIR}/latex ${BUILDDIR}/doctrees
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) ${BUILDDIR}/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in ${BUILDDIR}/latex."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+
+changes:
+ mkdir -p ${BUILDDIR}/changes ${BUILDDIR}/doctrees
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) ${BUILDDIR}/changes
+ @echo
+ @echo "The overview file is in ${BUILDDIR}/changes."
+
+linkcheck:
+ mkdir -p ${BUILDDIR}/linkcheck ${BUILDDIR}/doctrees
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) ${BUILDDIR}/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in ${BUILDDIR}/linkcheck/output.txt."
Binary file doc/_static/cubicweb.png has changed
Binary file doc/_static/logilab.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_static/sphinx-default.css Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,861 @@
+/**
+ * Sphinx Doc Design
+ */
+
+html, body {
+ background: white;
+}
+
+body {
+ font-family: Verdana, sans-serif;
+ font-size: 100%;
+ background-color: white;
+ color: black;
+ margin: 0;
+ padding: 0;
+}
+
+/* :::: LAYOUT :::: */
+
+div.logilablogo {
+ padding: 10px 10px 10px 10px;
+ height:75;
+}
+
+
+div.document {
+ background-color: white;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.body {
+ background-color: white;
+ padding: 0 20px 30px 20px;
+ border-left:solid;
+ border-left-color:#e2e2e2;
+ border-left-width:thin;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.clearer {
+ clear: both;
+}
+
+div.footer {
+ color: #ff4500;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #ff4500;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #ff7700;
+ color: white;
+ width: 100%;
+ height: 30px;
+ line-height: 30px;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related a {
+ color: white;
+ font-weight:bold;
+}
+
+/* ::: TOC :::: */
+
+div.sphinxsidebar {
+ border-style:solid;
+ border-color: white;
+/* background-color:#e2e2e2;*/
+ padding-bottom:5px;
+}
+
+div.sphinxsidebar h3 {
+ font-family: Verdana, sans-serif;
+ color: black;
+ font-size: 1.2em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+ font-weight:bold;
+ font-style:italic;
+}
+
+div.sphinxsidebar h4 {
+ font-family: Verdana, sans-serif;
+ color: black;
+ font-size: 1.1em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+ font-weight:bold;
+ font-style:italic;
+}
+
+div.sphinxsidebar p {
+ color: black;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ list-style: none;
+ color: black;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar a {
+ color: black;
+ text-decoration: none;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #e2e2e2;
+ font-family: sans-serif;
+ font-size: 1em;
+ padding-bottom: 5px;
+}
+
+/* :::: MODULE CLOUD :::: */
+div.modulecloud {
+ margin: -5px 10px 5px 10px;
+ padding: 10px;
+ line-height: 160%;
+ border: 1px solid #cbe7e5;
+ background-color: #f2fbfd;
+}
+
+div.modulecloud a {
+ padding: 0 5px 0 5px;
+}
+
+/* :::: SEARCH :::: */
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* :::: COMMON FORM STYLES :::: */
+
+div.actions {
+ padding: 5px 10px 5px 10px;
+ border-top: 1px solid #cbe7e5;
+ border-bottom: 1px solid #cbe7e5;
+ background-color: #e0f6f4;
+}
+
+form dl {
+ color: #333;
+}
+
+form dt {
+ clear: both;
+ float: left;
+ min-width: 110px;
+ margin-right: 10px;
+ padding-top: 2px;
+}
+
+input#homepage {
+ display: none;
+}
+
+div.error {
+ margin: 5px 20px 0 0;
+ padding: 5px;
+ border: 1px solid #d00;
+ font-weight: bold;
+}
+
+/* :::: INLINE COMMENTS :::: */
+
+div.inlinecomments {
+ position: absolute;
+ right: 20px;
+}
+
+div.inlinecomments a.bubble {
+ display: block;
+ float: right;
+ background-image: url(style/comment.png);
+ background-repeat: no-repeat;
+ width: 25px;
+ height: 25px;
+ text-align: center;
+ padding-top: 3px;
+ font-size: 0.9em;
+ line-height: 14px;
+ font-weight: bold;
+ color: black;
+}
+
+div.inlinecomments a.bubble span {
+ display: none;
+}
+
+div.inlinecomments a.emptybubble {
+ background-image: url(style/nocomment.png);
+}
+
+div.inlinecomments a.bubble:hover {
+ background-image: url(style/hovercomment.png);
+ text-decoration: none;
+ color: #3ca0a4;
+}
+
+div.inlinecomments div.comments {
+ float: right;
+ margin: 25px 5px 0 0;
+ max-width: 50em;
+ min-width: 30em;
+ border: 1px solid #2eabb0;
+ background-color: #f2fbfd;
+ z-index: 150;
+}
+
+div#comments {
+ border: 1px solid #2eabb0;
+ margin-top: 20px;
+}
+
+div#comments div.nocomments {
+ padding: 10px;
+ font-weight: bold;
+}
+
+div.inlinecomments div.comments h3,
+div#comments h3 {
+ margin: 0;
+ padding: 0;
+ background-color: #2eabb0;
+ color: white;
+ border: none;
+ padding: 3px;
+}
+
+div.inlinecomments div.comments div.actions {
+ padding: 4px;
+ margin: 0;
+ border-top: none;
+}
+
+div#comments div.comment {
+ margin: 10px;
+ border: 1px solid #2eabb0;
+}
+
+div.inlinecomments div.comment h4,
+div.commentwindow div.comment h4,
+div#comments div.comment h4 {
+ margin: 10px 0 0 0;
+ background-color: #2eabb0;
+ color: white;
+ border: none;
+ padding: 1px 4px 1px 4px;
+}
+
+div#comments div.comment h4 {
+ margin: 0;
+}
+
+div#comments div.comment h4 a {
+ color: #d5f4f4;
+}
+
+div.inlinecomments div.comment div.text,
+div.commentwindow div.comment div.text,
+div#comments div.comment div.text {
+ margin: -5px 0 -5px 0;
+ padding: 0 10px 0 10px;
+}
+
+div.inlinecomments div.comment div.meta,
+div.commentwindow div.comment div.meta,
+div#comments div.comment div.meta {
+ text-align: right;
+ padding: 2px 10px 2px 0;
+ font-size: 95%;
+ color: #538893;
+ border-top: 1px solid #cbe7e5;
+ background-color: #e0f6f4;
+}
+
+div.commentwindow {
+ position: absolute;
+ width: 500px;
+ border: 1px solid #cbe7e5;
+ background-color: #f2fbfd;
+ display: none;
+ z-index: 130;
+}
+
+div.commentwindow h3 {
+ margin: 0;
+ background-color: #2eabb0;
+ color: white;
+ border: none;
+ padding: 5px;
+ font-size: 1.5em;
+ cursor: pointer;
+}
+
+div.commentwindow div.actions {
+ margin: 10px -10px 0 -10px;
+ padding: 4px 10px 4px 10px;
+ color: #538893;
+}
+
+div.commentwindow div.actions input {
+ border: 1px solid #2eabb0;
+ background-color: white;
+ color: #135355;
+ cursor: pointer;
+}
+
+div.commentwindow div.form {
+ padding: 0 10px 0 10px;
+}
+
+div.commentwindow div.form input,
+div.commentwindow div.form textarea {
+ border: 1px solid #3c9ea2;
+ background-color: white;
+ color: black;
+}
+
+div.commentwindow div.error {
+ margin: 10px 5px 10px 5px;
+ background-color: #fbe5dc;
+ display: none;
+}
+
+div.commentwindow div.form textarea {
+ width: 99%;
+}
+
+div.commentwindow div.preview {
+ margin: 10px 0 10px 0;
+ background-color: #70d0d4;
+ padding: 0 1px 1px 25px;
+}
+
+div.commentwindow div.preview h4 {
+ margin: 0 0 -5px -20px;
+ padding: 4px 0 0 4px;
+ color: white;
+ font-size: 1.3em;
+}
+
+div.commentwindow div.preview div.comment {
+ background-color: #f2fbfd;
+}
+
+div.commentwindow div.preview div.comment h4 {
+ margin: 10px 0 0 0!important;
+ padding: 1px 4px 1px 4px!important;
+ font-size: 1.2em;
+}
+
+/* :::: SUGGEST CHANGES :::: */
+div#suggest-changes-box input, div#suggest-changes-box textarea {
+ border: 1px solid #ccc;
+ background-color: white;
+ color: black;
+}
+
+div#suggest-changes-box textarea {
+ width: 99%;
+ height: 400px;
+}
+
+
+/* :::: PREVIEW :::: */
+div.preview {
+ background-image: url(style/preview.png);
+ padding: 0 20px 20px 20px;
+ margin-bottom: 30px;
+}
+
+
+/* :::: INDEX PAGE :::: */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* :::: INDEX STYLES :::: */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+form.pfform {
+ margin: 10px 0 20px 0;
+}
+
+/* :::: GLOBAL STYLES :::: */
+
+.docwarning {
+ background-color: #ffe4e4;
+ padding: 10px;
+ margin: 0 -20px 0 -20px;
+ border-bottom: 1px solid #f66;
+}
+
+p.subhead {
+ font-weight: bold;
+ margin-top: 20px;
+}
+
+a {
+ color: orangered;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: 'Verdana', sans-serif;
+ background-color: white;
+ font-weight: bold;
+ color: black;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 10pt; font-size: 150%; }
+div.body h2 { font-size: 120%; }
+div.body h3 { font-size: 100%; }
+div.body h4 { font-size: 80%; }
+div.body h5 { font-size: 600%; }
+div.body h6 { font-size: 40%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+ul.fakelist {
+ list-style: none;
+ margin: 10px 0 10px 20px;
+ padding: 0;
+}
+
+.field-list ul {
+ padding-left: 1em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+/* "Footnotes" heading */
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+/* "Topics" */
+
+div.topic {
+ background-color: #eee;
+ border: 1px solid #ccc;
+ padding: 0 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* Admonitions */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+div.admonition p {
+ display: inline;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+table.docutils {
+ border: 0;
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 0;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+dl {
+ margin-bottom: 15px;
+ clear: both;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+.refcount {
+ color: #060;
+}
+
+dt:target,
+.highlight {
+ background-color: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+pre {
+ padding: 5px;
+ background-color: #efc;
+ color: #333;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+ overflow: auto;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+.footnote:target { background-color: #ffa }
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+form.comment {
+ margin: 0;
+ padding: 10px 30px 10px 30px;
+ background-color: #eee;
+}
+
+form.comment h3 {
+ background-color: #326591;
+ color: white;
+ margin: -10px -30px 10px -30px;
+ padding: 5px;
+ font-size: 1.4em;
+}
+
+form.comment input,
+form.comment textarea {
+ border: 1px solid #ccc;
+ padding: 2px;
+ font-family: sans-serif;
+ font-size: 100%;
+}
+
+form.comment input[type="text"] {
+ width: 240px;
+}
+
+form.comment textarea {
+ width: 100%;
+ height: 200px;
+ margin-bottom: 10px;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+/* :::: PRINT :::: */
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0;
+ width : 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ div#comments div.new-comment-box,
+ #top-link {
+ display: none;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_templates/layout.html Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,196 @@
+{%- block doctype -%}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+{%- endblock %}
+{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
+{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
+{%- macro relbar() %}
+ <div class="related">
+ <h3>Navigation</h3>
+ <ul>
+ {%- for rellink in rellinks %}
+ <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
+ <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags }}"
+ accesskey="{{ rellink[2] }}">{{ rellink[3] }}</a>
+ {%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
+ {%- endfor %}
+ {%- block rootrellink %}
+ <li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li>
+ {%- endblock %}
+ {%- for parent in parents %}
+ <li><a href="{{ parent.link|e }}" accesskey="U">{{ parent.title }}</a>{{ reldelim1 }}</li>
+ {%- endfor %}
+ {%- block relbaritems %}{% endblock %}
+ </ul>
+ </div>
+{%- endmacro %}
+{%- macro sidebar() %}
+ {%- if builder != 'htmlhelp' %}
+ <div class="sphinxsidebar">
+ <div class="sphinxsidebarwrapper">
+ {%- block sidebarlogo %}
+ {%- if logo %}
+ <p class="logo"><img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/></p>
+ {%- endif %}
+ {%- endblock %}
+ {%- block sidebartoc %}
+ {%- if display_toc %}
+ <h3>Table Of Contents</h3>
+ {{ toc }}
+ {%- endif %}
+ {%- endblock %}
+ {%- block sidebarrel %}
+ {%- if prev %}
+ <h4>Previous topic</h4>
+ <p class="topless"><a href="{{ prev.link|e }}" title="previous chapter">{{ prev.title }}</a></p>
+ {%- endif %}
+ {%- if next %}
+ <h4>Next topic</h4>
+ <p class="topless"><a href="{{ next.link|e }}" title="next chapter">{{ next.title }}</a></p>
+ {%- endif %}
+ {%- endblock %}
+ {%- if sourcename %}
+ <!--<h3>This Page</h3>
+ <ul class="this-page-menu">
+ {%- if builder == 'web' %}
+ <li><a href="#comments">Comments ({{ comments|length }} so far)</a></li>
+ <li><a href="{{ pathto('@edit/' + sourcename)|e }}">Suggest Change</a></li>
+ <li><a href="{{ pathto('@source/' + sourcename)|e }}">Show Source</a></li>
+ {%- elif builder == 'html' %}
+ <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}">Show Source</a></li>
+ {%- endif %}
+ </ul>-->
+ {%- endif %}
+ {%- if customsidebar %}
+ {{ rendertemplate(customsidebar) }}
+ {%- endif %}
+ {%- block sidebarsearch %}
+ {%- if pagename != "search" %}
+ <h3>{{ builder == 'web' and 'Keyword' or 'Quick' }} search</h3>
+ <form class="search" action="{{ pathto('search') }}" method="get">
+ <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+ {%- if builder == 'web' %}
+ <p style="font-size: 90%">Enter a module, class or function name.</p>
+ {%- endif %}
+ {%- endif %}
+ {%- endblock %}
+ </div>
+ </div>
+ {%- endif %}
+{%- endmacro -%}
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ {%- if builder != 'htmlhelp' %}
+ {%- set titlesuffix = " — " + docstitle %}
+ {%- endif %}
+ <title>{{ title|striptags }}{{ titlesuffix }}</title>
+ {%- if builder == 'web' %}
+ <link rel="stylesheet" href="{{ pathto('index') }}?do=stylesheet{%
+ if in_admin_panel %}&admin=yes{% endif %}" type="text/css" />
+ {%- for link, type, title in page_links %}
+ <link rel="alternate" type="{{ type|e(true) }}" title="{{ title|e(true) }}" href="{{ link|e(true) }}" />
+ {%- endfor %}
+ {%- else %}
+ <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
+ <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
+ {%- endif %}
+ {%- if builder != 'htmlhelp' %}
+ <script type="text/javascript">
+ var DOCUMENTATION_OPTIONS = {
+ URL_ROOT: '{{ pathto("", 1) }}',
+ VERSION: '{{ release }}',
+ COLLAPSE_MODINDEX: false,
+ FILE_SUFFIX: '{{ file_suffix }}'
+ };
+ </script>
+ <script type="text/javascript" src="{{ pathto('_static/jquery.js', 1) }}"></script>
+ <script type="text/javascript" src="{{ pathto('_static/interface.js', 1) }}"></script>
+ <script type="text/javascript" src="{{ pathto('_static/doctools.js', 1) }}"></script>
+ <script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script>
+ {%- if use_opensearch %}
+ <link rel="search" type="application/opensearchdescription+xml"
+ title="Search within {{ docstitle }}"
+ href="{{ pathto('_static/opensearch.xml', 1) }}"/>
+ {%- endif %}
+ {%- if favicon %}
+ <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
+ {%- endif %}
+ {%- endif %}
+{%- block rellinks %}
+ {%- if hasdoc('about') %}
+ <link rel="author" title="About these documents" href="{{ pathto('about') }}" />
+ {%- endif %}
+ <link rel="contents" title="Global table of contents" href="{{ pathto('contents') }}" />
+ <link rel="index" title="Global index" href="{{ pathto('genindex') }}" />
+ <link rel="search" title="Search" href="{{ pathto('search') }}" />
+ {%- if hasdoc('copyright') %}
+ <link rel="copyright" title="Copyright" href="{{ pathto('copyright') }}" />
+ {%- endif %}
+ <link rel="top" title="{{ docstitle }}" href="{{ pathto('index') }}" />
+ {%- if parents %}
+ <link rel="up" title="{{ parents[-1].title|striptags }}" href="{{ parents[-1].link|e }}" />
+ {%- endif %}
+ {%- if next %}
+ <link rel="next" title="{{ next.title|striptags }}" href="{{ next.link|e }}" />
+ {%- endif %}
+ {%- if prev %}
+ <link rel="prev" title="{{ prev.title|striptags }}" href="{{ prev.link|e }}" />
+ {%- endif %}
+{%- endblock %}
+{%- block extrahead %}{% endblock %}
+ </head>
+ <body>
+
+{% block logilablogo %}
+<div class="logilablogo">
+ <a class="logogo" href="http://www.cubicweb.org"><img border="0" src="{{ pathto('_static/cubicweb.png', 1) }}"/></a>
+ </div>
+{% endblock %}
+
+{%- block relbar1 %}{{ relbar() }}{% endblock %}
+
+{%- block sidebar1 %}{# possible location for sidebar #}{% endblock %}
+
+{%- block document %}
+ <div class="document">
+ <div class="documentwrapper">
+ {%- if builder != 'htmlhelp' %}
+ <div class="bodywrapper">
+ {%- endif %}
+ <div class="body">
+ {% block body %}{% endblock %}
+ </div>
+ {%- if builder != 'htmlhelp' %}
+ </div>
+ {%- endif %}
+ </div>
+{%- endblock %}
+
+{%- block sidebar2 %}{{ sidebar() }}{% endblock %}
+ <div class="clearer"></div>
+ </div>
+
+{%- block relbar2 %}{{ relbar() }}{% endblock %}
+
+{%- block footer %}
+ <div class="footer">
+ {%- if hasdoc('copyright') %}
+ © <a href="{{ pathto('copyright') }}">Copyright</a> {{ copyright }}.
+ {%- else %}
+ © Copyright {{ copyright }}.
+ {%- endif %}
+ {%- if last_updated %}
+ Last updated on {{ last_updated }}.
+ {%- endif %}
+ {%- if show_sphinx %}
+ Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
+ {%- endif %}
+ </div>
+{%- endblock %}
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_themes/cubicweb/layout.html Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,61 @@
+{% extends "basic/layout.html" %}
+
+{%- block extrahead %}
+<!--[if lte IE 6]>
+<link rel="stylesheet" href="{{ pathto('_static/ie6.css', 1) }}" type="text/css" media="screen" charset="utf-8" />
+<![endif]-->
+{%- if theme_favicon %}
+<link rel="shortcut icon" href="{{ pathto('_static/'+theme_favicon, 1) }}"/>
+{%- endif %}
+
+{%- if theme_canonical_url %}
+<link rel="canonical" href="{{ theme_canonical_url }}{{ pagename }}.html"/>
+{%- endif %}
+{% endblock %}
+
+{% block header %}
+
+{% if theme_in_progress|tobool %}
+ <img style="position: fixed; display: block; width: 165px; height: 165px; bottom: 60px; right: 0; border: 0;" src="{{ pathto('_static/in_progress.png', 1) }}" alt="Documentation in progress" />
+{% endif %}
+
+{% if theme_outdated|tobool %}
+ <div style="bottom: 60px; right: 20px;position: fixed;"><a href="{{ latest_url }}" class="btn btn-large btn-danger"><strong>></strong> Read the latest version of this page</a></div>
+{% endif %}
+
+<div class="header-small">
+ {%- if theme_logo %}
+ {% set img, ext = theme_logo.split('.', -1) %}
+ <div class="logo-small">
+ <a href="{{ pathto(master_doc) }}">
+ <img class="logo" src="{{ pathto('_static/%s-small.%s' % (img, ext), 1)}}" alt="Logo"/>
+ </a>
+ </div>
+ {%- endif %}
+</div>
+{% endblock %}
+
+{%- macro relbar() %}
+<div class="related">
+ <h3>{{ _('Navigation') }}</h3>
+ <ul>
+ {%- for rellink in rellinks %}
+ <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
+ <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
+ {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
+ {%- if not loop.first %}{{ reldelim2 }}{% endif %}
+ </li>
+ {%- endfor %}
+ {%- block rootrellink %}
+ <li><a href="{{ pathto(master_doc) }}">{{ docstitle|e }}</a>{{ reldelim1 }}</li>
+ {%- endblock %}
+ {%- for parent in parents %}
+ <li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
+ {%- endfor %}
+ {%- block relbaritems %} {% endblock %}
+ </ul>
+</div>
+{%- endmacro %}
+
+{%- block sidebarlogo %}{%- endblock %}
+{%- block sidebarsourcelink %}{%- endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_themes/cubicweb/static/cubicweb.css_t Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,33 @@
+/*
+ * cubicweb.css_t
+ * ~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- cubicweb theme.
+ *
+ * :copyright: Copyright 2014 by the Cubicweb team, see AUTHORS.
+ * :license: LGPL, see LICENSE for details.
+ *
+ */
+
+@import url("pyramid.css");
+
+div.header-small {
+ background-image: linear-gradient(white, #e2e2e2);
+ border-bottom: 1px solid #bbb;
+}
+
+div.logo-small {
+ padding: 10px;
+}
+
+img.logo {
+ width: 150px;
+}
+
+div.related a {
+ color: #e6820e;
+}
+
+a, a .pre {
+ color: #e6820e;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_themes/cubicweb/static/cubicweb.ico Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,1 @@
+../../../../../../web/data/favicon.ico
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_themes/cubicweb/static/logo-cubicweb-small.svg Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,1 @@
+logo-cubicweb.svg
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_themes/cubicweb/static/logo-cubicweb.svg Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,1 @@
+../../../../../../web/data/logo-cubicweb.svg
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/_themes/cubicweb/theme.conf Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,12 @@
+[theme]
+inherit = pyramid
+pygments_style = sphinx.pygments_styles.PyramidStyle
+stylesheet = cubicweb.css
+
+
+[options]
+logo = logo-cubicweb.svg
+favicon = cubicweb.ico
+in_progress = false
+outdated = false
+canonical_url =
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/MERGE_ME-tut-create-app.en.txt Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,386 @@
+.. -*- coding: utf-8 -*-
+
+
+Tutoriel : créer votre première application web pour Google AppEngine
+=====================================================================
+
+[TRANSLATE ME TO FRENCH]
+
+This tutorial will guide you step by step to build a blog application
+and discover the unique features of `LAX`. It assumes that you followed
+the :ref:`installation` guidelines and that both the `AppEngine SDK` and the
+`LAX` framework are setup on your computer.
+
+Creating a new application
+--------------------------
+
+We choosed in this tutorial to develop a blog as an example of web application
+and will go through each required steps/actions to have it running with `LAX`.
+When you installed `LAX`, you saw a directory named ``skel``. Make a copy of
+this directory and call it ``BlogDemo``.
+
+The location of this directory does not matter. But once decided, make sure your ``PYTHONPATH`` is properly set (:ref:`installation`).
+
+
+Defining a schema
+-----------------
+
+With `LAX`, the schema/datamodel is the core of the application. This is where
+you will define the type of content you have to hanlde in your application.
+
+Let us start with something simple and improve on it iteratively.
+
+In schema.py, we define two entities: ``Blog`` and ``BlogEntry``.
+
+::
+
+ class Blog(EntityType):
+ title = String(maxsize=50, required=True)
+ description = String()
+
+ class BlogEntry(EntityType):
+ title = String(maxsize=100, required=True)
+ publish_date = Date(default='TODAY')
+ text = String(fulltextindexed=True)
+ category = String(vocabulary=('important','business'))
+ entry_of = SubjectRelation('Blog', cardinality='?*')
+
+A Blog has a title and a description. The title is a string that is
+required 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 text. The title is a
+string that is required and must be less than 100 characters. The
+publish_date is a Date with a default value of TODAY, meaning that
+when a BlogEntry is created, its publish_date will be the current day
+unless it is modified. The text is a string that will be indexed in
+the full-text index and has no constraint.
+
+A BlogEntry also has a relationship ``entry_of`` that link it to a
+Blog. The cardinality ``?*`` means that a BlogEntry can be part of
+zero or one Blog (``?`` means `zero or one`) and that a Blog can
+have any number of BlogEntry (``*`` means `any number including
+zero`). For completeness, remember that ``+`` means `one or more`.
+
+Running the application
+-----------------------
+
+Defining this simple schema is enough to get us started. Make sure you
+followed the setup steps described in detail in the installation
+chapter (especially visiting http://localhost:8080/_load as an
+administrator), then launch the application with the command::
+
+ python dev_appserver.py BlogDemo
+
+and point your browser at http://localhost:8080/ (if it is easier for
+you, use the on-line demo at http://lax.appspot.com/).
+
+.. image:: images/lax-book.00-login.en.png
+ :alt: login screen
+
+After you log in, you will see the home page of your application. It
+lists the entity types: Blog and BlogEntry. If these links read
+``blog_plural`` and ``blogentry_plural`` it is because
+internationalization (i18n) is not working for you yet. Please ignore
+this for now.
+
+.. image:: images/lax-book.01-start.en.png
+ :alt: home page
+
+Creating system entities
+------------------------
+You can only create new users if you decided not to use google authentication.
+
+
+[WRITE ME : create users manages permissions etc]
+
+
+
+Creating application entites
+----------------------------
+
+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/lax-book.02-create-blog.en.png
+ :alt: from to create blog
+
+Click on the logo at top left to get back to the home page, then
+follow the Blog link 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/lax-book.03-list-one-blog.en.png
+ :alt: displaying a list of a single blog
+
+Clicking on this item will get you to its detailed description except
+that in this case, there is not much to display besides the name and
+the phrase ``everything about technology``.
+
+.. image:: images/lax-book.04-detail-one-blog.en.png
+ :alt: displaying the detailed view of a blog
+
+Now get back to the home page by clicking on the top-left logo, then
+create a new Blog called ``MyLife`` and get back to the home page
+again to follow the Blog link for the second time. The list now
+has two items.
+
+.. image:: images/lax-book.05-list-two-blog.en.png
+ :alt: displaying a list of two blogs
+
+
+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/lax-book.06-add-relation-entryof.en.png
+ :alt: editing a blog entry to add a relation to a blog
+
+Validate the changes by clicking ``Validate``. The entity BlogEntry
+that is displayed now includes a link to the entity Blog named
+``MyLife``.
+
+.. image:: images/lax-book.07-detail-one-blogentry.en.png
+ :alt: displaying the detailed view of a blogentry
+
+Remember that all of this was handled by the framework and that the
+only input that was provided so far is the schema. To get a graphical
+view of the schema, run the ``laxctl genschema BlogDemo`` command as
+explained in the installation section and point your browser to the
+URL http://localhost:8080/schema
+
+.. image:: images/lax-book.08-schema.en.png
+ :alt: graphical view of the schema (aka data-model)
+
+Site configuration
+------------------
+
+.. image:: images/lax-book.03-site-config-panel.en.png
+
+This panel allows you to configure the appearance of your application site.
+Six menus are available and we will go through each of them to explain how
+to use them.
+
+Navigation
+~~~~~~~~~~
+This menu provides you a way to adjust some navigation options depending on
+your needs, such as the number of entities to display by page of results.
+Follows the detailled list of available options:
+
+* navigation.combobox-limit: maximum number of entities to display in related
+ combo box (sample format: 23)
+* navigation.page-size: maximum number of objects displayed by page of results
+ (sample format: 23)
+* navigation.related-limit: maximum number of related entities to display in
+ the primary view (sample format: 23)
+* navigation.short-line-size: maximum number of characters in short description
+ (sample format: 23)
+
+UI
+~~
+This menu provides you a way to customize the user interface settings such as
+date format or encoding in the produced html.
+Follows the detailled list of available options:
+
+* ui.date-format : how to format date in the ui ("man strftime" for format description)
+* ui.datetime-format : how to format date and time in the ui ("man strftime" for format
+ description)
+* ui.default-text-format : default text format for rich text fields.
+* ui.encoding : user interface encoding
+* ui.fckeditor : should html fields being edited using fckeditor (a HTML WYSIWYG editor).
+ You should also select text/html as default text format to actually get fckeditor.
+* ui.float-format : how to format float numbers in the ui
+* ui.language : language of the user interface
+* ui.main-template : id of main template used to render pages
+* ui.site-title : site title, which is displayed right next to the logo in the header
+* ui.time-format : how to format time in the ui ("man strftime" for format description)
+
+
+Actions
+~~~~~~~
+This menu provides a way to configure the context in which you expect the actions
+to be displayed to the user and if you want the action to be visible or not.
+You must have notice that when you view a list of entities, an action box is
+available on the left column which display some actions as well as a drop-down
+menu for more actions.
+
+The context available are:
+
+* mainactions : actions listed in the left box
+* moreactions : actions listed in the `more` menu of the left box
+* addrelated : add actions listed in the left box
+* useractions : actions listed in the first section of drop-down menu
+ accessible from the right corner user login link
+* siteactions : actions listed in the second section of drop-down menu
+ accessible from the right corner user login link
+* hidden : select this to hide the specific action
+
+Boxes
+~~~~~
+The application has already a pre-defined set of boxes you can use right away.
+This configuration section allows you to place those boxes where you want in the
+application interface to customize it.
+
+The available boxes are:
+
+* actions box : box listing the applicable actions on the displayed data
+
+* boxes_blog_archives_box : box listing the blog archives
+
+* possible views box : box listing the possible views for the displayed data
+
+* rss box : RSS icon to get displayed data as a RSS thread
+
+* search box : search box
+
+* startup views box : box listing the configuration options available for
+ the application site, such as `Preferences` and `Site Configuration`
+
+Components
+~~~~~~~~~~
+[WRITE ME]
+
+Contextual components
+~~~~~~~~~~~~~~~~~~~~~
+[WRITE ME]
+
+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('CWGroup', 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.
+
+Change view permission
+~~~~~~~~~~~~~~~~~~~~~~
+
+
+
+Conclusion
+----------
+
+Exercise
+~~~~~~~~
+
+Create new blog entries in ``Tech-blog``.
+
+What we learned
+~~~~~~~~~~~~~~~
+
+Creating a simple schema was enough to set up a new application that
+can store blogs and blog entries.
+
+What is next ?
+~~~~~~~~~~~~~~
+
+Although the application is fully functionnal, its look is very
+basic. In the following section we will learn to create views to
+customize how data is displayed.
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/MERGE_ME-tut-create-gae-app.en.txt Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,218 @@
+.. -*- coding: utf-8 -*-
+
+.. _tutorielGAE:
+
+Tutoriel : créer votre première application web pour Google AppEngine
+=====================================================================
+
+Ce tutoriel va vous guider pas à pas a construire une apllication web
+de gestion de Blog afin de vous faire découvrir les fonctionnalités de
+*CubicWeb*.
+
+Nous supposons que vous avec déjà suivi le guide :ref:`installationGAE`.
+
+
+Créez une nouvelle application
+------------------------------
+
+Nous choisissons dans ce tutoriel de développer un blog comme un exemple
+d'application web et nous allons expliciter toutes les étapes nécessaires
+à sa réalisation.
+
+::
+
+ cubicweb-ctl newgapp blogdemo
+
+`newgapp` est la commande permettant de créer une instance *CubicWeb* pour
+le datastore.
+
+Assurez-vous que votre variable d'environnement ``PYTHONPATH`` est correctement
+initialisée (:ref:`installationGAE`)
+
+Définissez un schéma
+--------------------
+
+Le modèle de données ou schéma est au coeur d'une application *CubicWeb*.
+C'est là où vous allez devoir définir le type de contenu que votre application
+devra gérer.
+
+Commençons par un schéma simple que nous améliorerons progressivemment.
+
+Une fois votre instance ``blogdemo`` crée, vous trouverez un fichier ``schema.py``
+contenant la définition des entités suivantes : ``Blog`` and ``BlogEntry``.
+
+::
+
+ class Blog(EntityType):
+ title = String(maxsize=50, required=True)
+ description = String()
+
+ class BlogEntry(EntityType):
+ title = String(maxsize=100, required=True)
+ publish_date = Date(default='TODAY')
+ text = String(fulltextindexed=True)
+ category = String(vocabulary=('important','business'))
+ entry_of = SubjectRelation('Blog', cardinality='?*')
+
+
+Un ``Blog`` a un titre et une description. Le titre est une chaîne
+de caractères requise par la classe parente EntityType and ne doit
+pas excéder 50 caractères. La description est une chaîne de
+caractères sans contraintes.
+
+Une ``BlogEntry`` a un titre, une date de publication et du texte
+étant son contenu. Le titre est une chaîne de caractères qui ne
+doit pas excéder 100 caractères. La date de publication est de type Date et a
+pour valeur par défaut TODAY, ce qui signifie que lorsqu'une
+``BlogEntry`` sera créée, sa date de publication sera la date
+courante a moins de modifier ce champ. Le texte est une chaîne de
+caractères qui sera indexée en plein texte et sans contraintes.
+
+Une ``BlogEntry`` a aussi une relation nommée ``entry_of`` qui la
+relie à un ``Blog``. La cardinalité ``?*`` signifie que BlogEntry
+peut faire partie de zero a un Blog (``?`` signifie `zero ou un`) et
+qu'un Blog peut avoir une infinité de BlogEntry (``*`` signifie
+`n'importe quel nombre incluant zero`).
+Par soucis de complétude, nous rappellerons que ``+`` signifie
+`un ou plus`.
+
+Lancez l'application
+--------------------
+
+Définir ce simple schéma est suffisant pour commencer. Assurez-vous
+que vous avez suivi les étapes décrites dans la section installation
+(en particulier visitez http://localhost:8080/_load en tant qu'administrateur
+afin d'initialiser le datastore), puis lancez votre application avec la commande ::
+
+ python dev_appserver.py BlogDemo
+
+puis dirigez vous vers http://localhost:8080/ (ou si c'est plus facile
+vous pouvez utiliser la démo en ligne http://lax.appspot.com/).
+[FIXME] -- changer la demo en ligne en quelque chose qui marche (!)
+
+.. image:: images/lax-book.00-login.en.png
+ :alt: login screen
+
+Après vous être authentifié, vous arrivez sur la page d'accueil de votre
+application. Cette page liste les types d'entités accessibles dans votre
+application, en l'occurrence : Blog et Articles. Si vous lisez ``blog_plural``
+et ``blogentry_plural`` cela signifie que l'internationalisation (i18n)
+n'a pas encore fonctionné. Ignorez cela pour le moment.
+
+.. image:: images/lax-book.01-start.en.png
+ :alt: home page
+
+Créez des entités système
+-------------------------
+
+Vous ne pourrez créer de nouveaux utilisateurs que dans le cas où vous
+avez choisi de ne pas utiliser l'authentification Google.
+
+
+[WRITE ME : create users manages permissions etc]
+
+
+
+Créez des entités applicatives
+------------------------------
+
+Créez un Blog
+~~~~~~~~~~~~~
+
+Créons à présent quelques entités. Cliquez sur `[+]` sur la
+droite du lien Blog. Appelez cette nouvelle entité Blog ``Tech-Blog``
+et tapez pour la description ``everything about technology``,
+puis validez le formulaire d'édition en cliquant sur le bouton
+``Validate``.
+
+
+.. image:: images/lax-book.02-create-blog.en.png
+ :alt: from to create blog
+
+En cliquant sur le logo situé dans le coin gauche de la fenêtre,
+vous allez être redirigé vers la page d'accueil. Ensuite, si vous allez
+sur le lien Blog, vous devriez voir la liste des entités Blog, en particulier
+celui que vous venez juste de créer ``Tech-Blog``.
+
+.. image:: images/lax-book.03-list-one-blog.en.png
+ :alt: displaying a list of a single blog
+
+Si vous cliquez sur ``Tech-Blog`` vous devriez obtenir une description
+détaillée, ce qui dans notre cas, n'est rien de plus que le titre
+et la phrase ``everything about technology``
+
+
+.. image:: images/lax-book.04-detail-one-blog.en.png
+ :alt: displaying the detailed view of a blog
+
+Maintenant retournons sur la page d'accueil et créons un nouveau
+Blog ``MyLife`` et retournons sur la page d'accueil, puis suivons
+le lien Blog et nous constatons qu'à présent deux blogs sont listés.
+
+.. image:: images/lax-book.05-list-two-blog.en.png
+ :alt: displaying a list of two blogs
+
+Créons un article
+~~~~~~~~~~~~~~~~~
+
+Revenons sur la page d'accueil et cliquons sur `[+]` Ã droite du lien
+`articles`. Appellons cette nouvelle entité ``Hello World`` et introduisons
+un peut de texte avant de ``Valider``. Vous venez d'ajouter un article
+sans avoir précisé à quel Blog il appartenait. Dans la colonne de gauche
+se trouve une boite intitulé ``actions``, cliquez sur le menu ``modifier``.
+Vous êtes de retour sur le formulaire d'édition de l'article que vous
+venez de créer, à ceci près que ce formulaire a maintenant une nouvelle
+section intitulée ``ajouter relation``. Choisissez ``entry_of`` dans ce menu,
+cela va faire apparaitre une deuxième menu déroulant dans lequel vous
+allez pouvoir séléctionner le Blog ``MyLife``.
+
+Vous auriez pu aussi, au moment où vous avez crée votre article, sélectionner
+``appliquer`` au lieu de ``valider`` et le menu ``ajouter relation`` serait apparu.
+
+.. image:: images/lax-book.06-add-relation-entryof.en.png
+ :alt: editing a blog entry to add a relation to a blog
+
+Validez vos modifications en cliquant sur ``Valider``. L'entité article
+qui est listée contient maintenant un lien vers le Blog auquel il
+appartient, ``MyLife``.
+
+.. image:: images/lax-book.07-detail-one-blogentry.en.png
+ :alt: displaying the detailed view of a blogentry
+
+Rappelez-vous que pour le moment, tout a été géré par la plate-forme
+*CubicWeb* et que la seule chose qui a été fournie est le schéma de
+données. D'ailleurs pour obtenir une vue graphique du schéma, exécutez
+la commande ``laxctl genschema blogdemo`` et vous pourrez visualiser
+votre schéma a l'URL suivante : http://localhost:8080/schema
+
+.. image:: images/lax-book.08-schema.en.png
+ :alt: graphical view of the schema (aka data-model)
+
+
+Change view permission
+~~~~~~~~~~~~~~~~~~~~~~
+
+
+
+Conclusion
+----------
+
+Exercise
+~~~~~~~~
+
+Create new blog entries in ``Tech-blog``.
+
+What we learned
+~~~~~~~~~~~~~~~
+
+Creating a simple schema was enough to set up a new application that
+can store blogs and blog entries.
+
+What is next ?
+~~~~~~~~~~~~~~
+
+Although the application is fully functionnal, its look is very
+basic. In the following section we will learn to create views to
+customize how data is displayed.
+
+
--- a/doc/book/README Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-====
-Book
-====
-
-----
-Part
-----
-
-Chapter
-=======
-
-.. _Level1AnchorForLaterReference:
-
-Level 1 section
----------------
-
-Level 2 section
-~~~~~~~~~~~~~~~
-
-Level 3 section
-```````````````
-
-
-
-*CubicWeb*
-
-
-inline directives:
- :file:`directory/file`
- :envvar:`AN_ENV_VARIABLE`
- :command:`command --option arguments`
-
- :ref:, :mod:
-
-
-.. sourcecode:: python
-
- class SomePythonCode:
- ...
-
-.. XXX a comment, wont be rendered
-
-
-a [foot note]_
-
-.. [foot note] the foot note content
-
-
-Boxes
-=====
-
-- warning box:
- .. warning::
-
- Warning content
-- note box:
- .. note::
-
- Note content
-
-
-
-Cross references
-================
-
-To arbitrary section
---------------------
-
-:ref:`identifier` ou :ref:`label <identifier>`
-
-Label required of referencing node which as no title, else the node's title will be used.
-
-
-To API objects
---------------
-See the autodoc sphinx extension documentation. Quick overview:
-
-* ref to a class: :class:`cubicweb.devtools.testlib.AutomaticWebTest`
-
-* if you can to see only the class name in the generated documentation, add a ~:
- :class:`~cubicweb.devtools.testlib.AutomaticWebTest`
-
-* you can also use :mod: (module), :exc: (exception), :func: (function), :meth: (method)...
-
-* syntax explained above to specify label explicitly may also be used
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/additionnal_services/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,14 @@
+Additional services
+===================
+
+In this chapter, we introduce services crossing the *web -
+repository - administration* organisation of the first parts of the
+CubicWeb book. Those services can be either proper services (like the
+undo functionality) or mere *topical cross-sections* across CubicWeb.
+
+.. toctree::
+ :maxdepth: 2
+
+ undo
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/additionnal_services/undo.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,337 @@
+Undoing changes in CubicWeb
+---------------------------
+
+Many desktop applications offer the possibility for the user to
+undo its last changes : this *undo feature* has now been
+integrated into the CubicWeb framework. This document will
+introduce you to the *undo feature* both from the end-user and the
+application developer point of view.
+
+But because a semantic web application and a common desktop
+application are not the same thing at all, especially as far as
+undoing is concerned, we will first introduce *what* is the *undo
+feature* for now.
+
+What's *undoing* in a CubicWeb application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+What is an *undo feature* is quite intuitive in the context of a
+desktop application. But it is a bit subtler in the context of a
+Semantic Web application. This section introduces some of the main
+differences between a classical desktop and a Semantic Web
+applications to keep in mind in order to state precisely *what we
+want*.
+
+The notion transactions
+```````````````````````
+
+A CubicWeb application acts upon an *Entity-Relationship* model,
+described by a schema. This allows to ensure some data integrity
+properties. It also implies that changes are made by all-or-none
+groups called *transactions*, such that the data integrity is
+preserved whether the transaction is completely applied *or* none
+of it is applied.
+
+A transaction can thus include more actions than just those
+directly required by the main purpose of the user. For example,
+when a user *just* writes a new blog entry, the underlying
+*transaction* holds several *actions* as illustrated below :
+
+* By admin on 2012/02/17 15:18 - Created Blog entry : Torototo
+
+ #. Created Blog entry : Torototo
+ #. Added relation : Torototo owned by admin
+ #. Added relation : Torototo blog entry of Undo Blog
+ #. Added relation : Torototo in state draft (draft)
+ #. Added relation : Torototo created by admin
+
+Because of the very nature (all-or-none) of the transactions, the
+"undoable stuff" are the transactions and not the actions !
+
+Public and private actions within a transaction
+```````````````````````````````````````````````
+
+Actually, within the *transaction* "Created Blog entry :
+Torototo", two of those *actions* are said to be *public* and
+the others are said to be *private*. *Public* here means that the
+public actions (1 and 3) were directly requested by the end user ;
+whereas *private* means that the other actions (2, 4, 5) were
+triggered "under the hood" to fulfill various requirements for the
+user operation (ensuring integrity, security, ... ).
+
+And because quite a lot of actions can be triggered by a "simple"
+end-user request, most of which the end-user is not (and does not
+need or wish to be) aware, only the so-called public actions will
+appear [1]_ in the description of the an undoable transaction.
+
+* By admin on 2012/02/17 15:18 - Created Blog entry : Torototo
+
+ #. Created Blog entry : Torototo
+ #. Added relation : Torototo blog entry of Undo Blog
+
+But note that both public and private actions will be undone
+together when the transaction is undone.
+
+(In)dependent transactions : the simple case
+````````````````````````````````````````````
+
+A CubicWeb application can be used *simultaneously* by different users
+(whereas a single user works on an given office document at a
+given time), so that there is not always a single history
+time-line in the CubicWeb case. Moreover CubicWeb provides
+security through the mechanism of *permissions* granted to each
+user. This can lead to some transactions *not* being undoable in
+some contexts.
+
+In the simple case two (unprivileged) users Alice and Bob make
+relatively independent changes : then both Alice and Bob can undo
+their changes. But in some case there is a clean dependency
+between Alice's and Bob's actions or between actions of one of
+them. For example let's suppose that :
+
+- Alice has created a blog,
+- then has published a first post inside,
+- then Bob has published a second post in the same blog,
+- and finally Alice has updated its post contents.
+
+Then it is clear that Alice can undo her contents changes and Bob
+can undo his post creation independently. But Alice can not undo
+her post creation while she has not first undone her changes.
+It is also clear that Bob should *not* have the
+permissions to undo any of Alice's transactions.
+
+
+More complex dependencies between transactions
+``````````````````````````````````````````````
+
+But more surprising things can quickly happen. Going back to the
+previous example, Alice *can* undo the creation of the blog after
+Bob has published its post in it ! But this is possible only
+because the schema does not *require* for a post to be in a
+blog. Would the *blog entry of* relation have been mandatory, then
+Alice could not have undone the blog creation because it would
+have broken integrity constraint for Bob's post.
+
+When a user attempts to undo a transaction the system will check
+whether a later transaction has explicit dependency on the
+would-be-undone transaction. In this case the system will not even
+attempt the undo operation and inform the user.
+
+If no such dependency is detected the system will attempt the undo
+operation but it can fail, typically because of integrity
+constraint violations. In such a case the undo operation is
+completely [3]_ rollbacked.
+
+
+The *undo feature* for CubicWeb end-users
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The exposition of the undo feature to the end-user through a Web
+interface is still quite basic and will be improved toward a
+greater usability. But it is already fully functional. For now
+there are two ways to access the *undo feature* as long as the it
+has been activated in the instance configuration file with the
+option *undo-support=yes*.
+
+Immediately after having done the change to be canceled through
+the **undo** link in the message. This allows to undo an
+hastily action immediately. For example, just after having
+validated the creation of the blog entry *A second blog entry* we
+get the following message, allowing to undo the creation.
+
+.. image:: /images/undo_mesage_w600.png
+ :width: 600px
+ :alt: Screenshot of the undo link in the message
+ :align: center
+
+At any time we can access the **undo-history view** accessible from the
+start-up page.
+
+.. image:: /images/undo_startup-link_w600.png
+ :width: 600px
+ :alt: Screenshot of the startup menu with access to the history view
+ :align: center
+
+This view will provide inspection of the transaction and their (public)
+actions. Each transaction provides its own **undo** link. Only the
+transactions the user has permissions to see and undo will be shown.
+
+.. image:: /images/undo_history-view_w600.png
+ :width: 600px
+ :alt: Screenshot of the undo history main view
+ :align: center
+
+If the user attempts to undo a transaction which can't be undone or
+whose undoing fails, then a message will explain the situation and
+no partial undoing will be left behind.
+
+This is all for the end-user side of the undo mechanism : this is
+quite simple indeed ! Now, in the following section, we are going
+to introduce the developer side of the undo mechanism.
+
+The *undo feature* for CubicWeb application developers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A word of warning : this section is intended for developers,
+already having some knowledge of what's under CubicWeb's hood. If
+it is not *yet* the case, please refer to CubicWeb documentation
+http://docs.cubicweb.org/ .
+
+Overview
+````````
+
+The core of the undo mechanisms is at work in the *native source*,
+beyond the RQL. This does mean that *transactions* and *actions*
+are *no entities*. Instead they are represented at the SQL level
+and exposed through the *DB-API* supported by the repository
+*Connection* objects.
+
+Once the *undo feature* has been activated in the instance
+configuration file with the option *undo-support=yes*, each
+mutating operation (cf. [2]_) will be recorded in some special SQL
+table along with its associated transaction. Transaction are
+identified by a *txuuid* through which the functions of the
+*DB-API* handle them.
+
+On the web side the last commited transaction *txuuid* is
+remembered in the request's data to allow for imediate undoing
+whereas the *undo-history view* relies upon the *DB-API* to list
+the accessible transactions. The actual undoing is performed by
+the *UndoController* accessible at URL of the form
+`www.my.host/my/instance/undo?txuuid=...`
+
+The repository side
+```````````````````
+
+Please refer to the file `cubicweb/server/sources/native.py` and
+`cubicweb/transaction.py` for the details.
+
+The undoing information is mainly stored in three SQL tables:
+
+`transactions`
+ Stores the txuuid, the user eid and the date-and-time of
+ the transaction. This table is referenced by the two others.
+
+`tx_entity_actions`
+ Stores the undo information for actions on entities.
+
+`tx_relation_actions`
+ Stores the undo information for the actions on relations.
+
+When the undo support is activated, entries are added to those
+tables for each mutating operation on the data repository, and are
+deleted on each transaction undoing.
+
+Those table are accessible through the following methods of the
+repository `Connection` object :
+
+`undoable_transactions`
+ Returns a list of `Transaction` objects accessible to the user
+ and according to the specified filter(s) if any.
+
+`tx_info`
+ Returns a `Transaction` object from a `txuuid`
+
+`undo_transaction`
+ Returns the list of `Action` object for the given `txuuid`.
+
+ NB: By default it only return *public* actions.
+
+The web side
+````````````
+
+The exposure of the *undo feature* to the end-user through the Web
+interface relies on the *DB-API* introduced above. This implies
+that the *transactions* and *actions* are not *entities* linked by
+*relations* on which the usual views can be applied directly.
+
+That's why the file `cubicweb/web/views/undohistory.py` defines
+some dedicated views to access the undo information :
+
+`UndoHistoryView`
+ This is a *StartupView*, the one accessible from the home
+ page of the instance which list all transactions.
+
+`UndoableTransactionView`
+ This view handles the display of a single `Transaction` object.
+
+`UndoableActionBaseView`
+ This (abstract) base class provides private methods to build
+ the display of actions whatever their nature.
+
+`Undoable[Add|Remove|Create|Delete|Update]ActionView`
+ Those views all inherit from `UndoableActionBaseView` and
+ each handles a specific kind of action.
+
+`UndoableActionPredicate`
+ This predicate is used as a *selector* to pick the appropriate
+ view for actions.
+
+Apart from this main *undo-history view* a `txuuid` is stored in
+the request's data `last_undoable_transaction` in order to allow
+immediate undoing of a hastily validated operation. This is
+handled in `cubicweb/web/application.py` in the `main_publish` and
+`add_undo_link_to_msg` methods for the storing and displaying
+respectively.
+
+Once the undo information is accessible, typically through a
+`txuuid` in an *undo* URL, the actual undo operation can be
+performed by the `UndoController` defined in
+`cubicweb/web/views/basecontrollers.py`. This controller basically
+extracts the `txuuid` and performs a call to `undo_transaction` and
+in case of an undo-specific error, lets the top level publisher
+handle it as a validation error.
+
+
+Conclusion
+~~~~~~~~~~
+
+The undo mechanism relies upon a low level recording of the
+mutating operation on the repository. Those records are accessible
+through some method added to the *DB-API* and exposed to the
+end-user either through a whole history view of through an
+immediate undoing link in the message box.
+
+The undo feature is functional but the interface and configuration
+options are still quite reduced. One major improvement would be to
+be able to filter with a finer grain which transactions or actions
+one wants to see in the *undo-history view*. Another critical
+improvement would be to enable the undo feature on a part only of
+the entity-relationship schema to avoid storing too much useless
+data and reduce the underlying overhead.
+
+But both functionality are related to the strong design choice not
+to represent transactions and actions as entities and
+relations. This has huge benefits in terms of safety and conceptual
+simplicity but prevents from using lots of convenient CubicWeb
+features such as *facets* to access undo information.
+
+Before developing further the undo feature or eventually revising
+this design choice, it appears that some return of experience is
+strongly needed. So don't hesitate to try the undo feature in your
+application and send us some feedback.
+
+
+Notes
+~~~~~
+
+.. [1] The end-user Web interface could be improved to enable
+ user to choose whether he wishes to see private actions.
+
+.. [2] There is only five kind of elementary actions (beyond
+ merely accessing data for reading):
+
+ * **C** : creating an entity
+ * **D** : deleting an entity
+ * **U** : updating an entity attributes
+ * **A** : adding a relation
+ * **R** : removing a relation
+
+.. [3] Meaning none of the actions in the transaction is
+ undone. Depending upon the application, it might make sense
+ to enable *partial* undo. That is to say undo in which some
+ actions could not be undo without preventing to undo the
+ others actions in the transaction (as long as it does not
+ break schema integrity). This is not forbidden by the
+ back-end but is deliberately not supported by the front-end
+ (for now at least).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/additional-tips.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,64 @@
+
+.. _Additional Tips:
+
+Backups (mostly with postgresql)
+--------------------------------
+
+It is always a good idea to backup. If your system does not do that,
+you should set it up. Note that whenever you do an upgrade,
+`cubicweb-ctl` offers you to backup your database. There are a number
+of ways for doing backups.
+
+Using postgresql (and only that)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Before you
+go ahead, make sure the following permissions are correct ::
+
+ # chgrp postgres /var/lib/cubicweb/backup
+ # chmod g+ws /var/lib/cubicweb/backup
+ # chgrp postgres /etc/cubicweb.d/*<instance>*/sources
+ # chmod g+r /etc/cubicweb.d/*<instance>*/sources
+
+Simply use the pg_dump in a cron installed for `postgres` user on the database server::
+
+ # m h dom mon dow command
+ 0 2 * * * pg_dump -Fc --username=cubicweb --no-owner <instance> > /var/backups/<instance>-$(date '+%Y-%m-%d_%H:%M:%S').dump
+
+Using :command:`cubicweb-ctl db-dump`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The CubicWeb way is to use the :command:`db-dump` command. For that,
+you have to put your passwords in a user-only-readable file at the
+home directory of root user. The file is `.pgpass` (`chmod 0600`), in
+this case for a socket run connection to PostgreSQL ::
+
+ /var/run/postgresql:5432:<instance>:<database user>:<database password>
+
+The postgres documentation for the `.pgpass` format can be found `here`_
+
+Then add the following command to the crontab of the user (`crontab -e`)::
+
+ # m h dom mon dow command
+ 0 2 * * * cubicweb-ctl db-dump <instance>
+
+
+Backup ninja
+~~~~~~~~~~~~
+
+You can use a combination `backup-ninja`_ (which has a postgres script in the
+example directory), `backuppc`)_ (for versionning).
+
+Please note that in the *CubicWeb way* it adds a second location for your
+password which is error-prone.
+
+.. _`here` : http://www.postgresql.org/docs/current/static/libpq-pgpass.html
+.. _`backup-ninja` : https://labs.riseup.net/code/projects/show/backupninja/
+.. _`backuppc` : http://backuppc.sourceforge.net/
+
+.. warning::
+
+ Remember that these indications will fail you whenever you use
+ another database backend than postgres. Also it does properly handle
+ externally managed data such as files (using the Bytes File System
+ Storage).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/config.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,229 @@
+.. -*- coding: utf-8 -*-
+
+.. _ConfigEnv:
+
+Set-up of a *CubicWeb* environment
+==================================
+
+You can `configure the database`_ system of your choice:
+
+ - `PostgreSQL configuration`_
+ - `MySql configuration`_
+ - `SQLServer configuration`_
+ - `SQLite configuration`_
+
+For advanced features, have a look to:
+
+ - `Cubicweb resources configuration`_
+
+.. _`configure the database`: DatabaseInstallation_
+.. _`PostgreSQL configuration`: PostgresqlConfiguration_
+.. _`MySql configuration`: MySqlConfiguration_
+.. _`SQLServer configuration`: SQLServerConfiguration_
+.. _`SQLite configuration`: SQLiteConfiguration_
+.. _`Cubicweb resources configuration`: RessourcesConfiguration_
+
+
+
+.. _RessourcesConfiguration:
+
+Cubicweb resources configuration
+--------------------------------
+
+.. autodocstring:: cubicweb.cwconfig
+
+
+.. _DatabaseInstallation:
+
+Databases configuration
+-----------------------
+
+Each instance can be configured with its own database connection information,
+that will be stored in the instance's :file:`sources` file. The database to use
+will be chosen when creating the instance. CubicWeb is known to run with
+Postgresql (recommended), SQLServer and SQLite, and may run with MySQL.
+
+Other possible sources of data include CubicWeb, Subversion, LDAP and Mercurial,
+but at least one relational database is required for CubicWeb to work. You do
+not need to install a backend that you do not intend to use for one of your
+instances. SQLite is not fit for production use, but it works well for testing
+and ships with Python, which saves installation time when you want to get
+started quickly.
+
+.. _PostgresqlConfiguration:
+
+PostgreSQL
+~~~~~~~~~~
+
+Many Linux distributions ship with the appropriate PostgreSQL packages.
+Basically, you need to install the following packages:
+
+* `postgresql` and `postgresql-client`, which will pull the respective
+ versioned packages (e.g. `postgresql-9.1` and `postgresql-client-9.1`) and,
+ optionally,
+* a `postgresql-plpython-X.Y` package with a version corresponding to that of
+ the aforementioned packages (e.g. `postgresql-plpython-9.1`).
+
+If you run postgres version prior to 8.3, you'll also need the
+`postgresql-contrib-8.X` package for full-text search extension.
+
+If you run postgres on another host than the |cubicweb| repository, you should
+install the `postgresql-client` package on the |cubicweb| host, and others on the
+database host.
+
+For extra details concerning installation, please refer to the `PostgreSQL
+project online documentation`_.
+
+.. _`PostgreSQL project online documentation`: http://www.postgresql.org/docs
+
+
+Database cluster
+++++++++++++++++
+
+If you already have an existing cluster and PostgreSQL server running, you do
+not need to execute the initilization step of your PostgreSQL database unless
+you want a specific cluster for |cubicweb| databases or if your existing
+cluster doesn't use the UTF8 encoding (see note below).
+
+To initialize a PostgreSQL cluster, use the command ``initdb``::
+
+ $ initdb -E UTF8 -D /path/to/pgsql
+
+Notice the encoding specification. This is necessary since |cubicweb| usually
+want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll
+get error like::
+
+ new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII)
+ HINT: Use the same encoding as in the template database, or use template0 as template.
+
+Once initialized, start the database server PostgreSQL with the command::
+
+ $ postgres -D /path/to/psql
+
+If you cannot execute this command due to permission issues, please make sure
+that your username has write access on the database. ::
+
+ $ chown username /path/to/pgsql
+
+Database authentication
++++++++++++++++++++++++
+
+The database authentication is configured in `pg_hba.conf`. It can be either set
+to `ident sameuser` or `md5`. If set to `md5`, make sure to use an existing
+user of your database. If set to `ident sameuser`, make sure that your client's
+operating system user name has a matching user in the database. If not, please
+do as follow to create a user::
+
+ $ su
+ $ su - postgres
+ $ createuser -s -P username
+
+The option `-P` (for password prompt), will encrypt the password with the
+method set in the configuration file :file:`pg_hba.conf`. If you do not use this
+option `-P`, then the default value will be null and you will need to set it
+with::
+
+ $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql"
+
+The above login/password will be requested when you will create an instance with
+`cubicweb-ctl create` to initialize the database of your instance.
+
+Notice that the `cubicweb-ctl db-create` does database initialization that
+may requires a postgres superuser. That's why a login/password is explicitly asked
+at this step, so you can use there a superuser without using this user when running
+the instance. Things that require special privileges at this step:
+
+* database creation, require the 'create database' permission
+* install the plpython extension language (require superuser)
+* install the tsearch extension for postgres version prior to 8.3 (require superuser)
+
+To avoid using a super user each time you create an install, a nice trick is to
+install plpython (and tsearch when needed) on the special `template1` database,
+so they will be installed automatically when cubicweb databases are created
+without even with needs for special access rights. To do so, run ::
+
+ # Installation of plpythonu language by default ::
+ $ createlang -U pgadmin plpythonu template1
+ $ psql -U pgadmin template1
+ template1=# update pg_language set lanpltrusted=TRUE where lanname='plpythonu';
+
+Where `pgadmin` is a postgres superuser. The last command is necessary since by
+default plpython is an 'untrusted' language and as such can't be used by non
+superuser. This update fix that problem by making it trusted.
+
+To install the tsearch plain-text index extension on postgres prior to 8.3, run::
+
+ cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1
+
+
+.. _MySqlConfiguration:
+
+MySql
+~~~~~
+.. warning::
+ CubicWeb's MySQL support is not commonly used, so things may or may not work properly.
+
+You must add the following lines in ``/etc/mysql/my.cnf`` file::
+
+ transaction-isolation=READ-COMMITTED
+ default-storage-engine=INNODB
+ default-character-set=utf8
+ max_allowed_packet = 128M
+
+.. Note::
+ It is unclear whether mysql supports indexed string of arbitrary length or
+ not.
+
+
+.. _SQLServerConfiguration:
+
+SQLServer
+~~~~~~~~~
+
+As of this writing, support for SQLServer 2005 is functional but incomplete. You
+should be able to connect, create a database and go quite far, but some of the
+SQL generated from RQL queries is still currently not accepted by the
+backend. Porting to SQLServer 2008 is also an item on the backlog.
+
+The `source` configuration file may look like this (specific parts only are
+shown)::
+
+ [system]
+ db-driver=sqlserver2005
+ db-user=someuser
+ # database password not needed
+ #db-password=toto123
+ #db-create/init may ask for a pwd: just say anything
+ db-extra-arguments=Trusted_Connection
+ db-encoding=utf8
+
+
+You need to change the default settings on the database by running::
+
+ ALTER DATABASE <databasename> SET READ_COMMITTED_SNAPSHOT ON;
+
+The ALTER DATABASE command above requires some permissions that your
+user may not have. In that case you will have to ask your local DBA to
+run the query for you.
+
+You can check that the setting is correct by running the following
+query which must return '1'::
+
+ SELECT is_read_committed_snapshot_on
+ FROM sys.databases WHERE name='<databasename>';
+
+
+
+.. _SQLiteConfiguration:
+
+SQLite
+~~~~~~
+
+SQLite has the great advantage of requiring almost no configuration. Simply
+use 'sqlite' as db-driver, and set path to the dabase as db-name. Don't specify
+anything for db-user and db-password, they will be ignore anyway.
+
+.. Note::
+ SQLite is great for testing and to play with cubicweb but is not suited for
+ production environments.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/create-instance.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,100 @@
+.. -*- coding: utf-8 -*-
+
+Creation of your first instance
+===============================
+
+Instance creation
+-----------------
+
+Now that we created a cube, we can create an instance and access it via a web
+browser. We will use a `all-in-one` configuration to simplify things ::
+
+ cubicweb-ctl create -c all-in-one mycube myinstance
+
+.. note::
+ Please note that we created a new cube for a demo purposes but
+ you could have used an existing cube available in our standard library
+ such as blog or person for example.
+
+A series of questions will be prompted to you, the default answer is usually
+sufficient. You can anyway modify the configuration later on by editing
+configuration files. When a login/password are requested to access the database
+please use the credentials you created at the time you configured the database
+(:ref:`PostgresqlConfiguration`).
+
+It is important to distinguish here the user used to access the database and the
+user used to login to the cubicweb instance. When an instance starts, it uses
+the login/password for the database to get the schema and handle low level
+transaction. But, when :command:`cubicweb-ctl create` asks for a manager
+login/psswd of *CubicWeb*, it refers to the user you will use during the
+development to administrate your web instance. It will be possible, later on,
+to use this user to create other users for your final web instance.
+
+
+Instance administration
+-----------------------
+
+start / stop
+~~~~~~~~~~~~
+
+When this command is completed, the definition of your instance is
+located in :file:`~/etc/cubicweb.d/myinstance/*`. To launch it, you
+just type ::
+
+ cubicweb-ctl start -D myinstance
+
+The option `-D` specifies the *debug mode* : the instance is not
+running in server mode and does not disconnect from the terminal,
+which simplifies debugging in case the instance is not properly
+launched. You can see how it looks by visiting the URL
+`http://localhost:8080` (the port number depends of your
+configuration). To login, please use the cubicweb administrator
+login/password you defined when you created the instance.
+
+To shutdown the instance, Crtl-C in the terminal window is enough.
+If you did not use the option `-D`, then type ::
+
+ cubicweb-ctl stop myinstance
+
+This is it! All is settled down to start developping your data model...
+
+.. note::
+
+ The output of `cubicweb-ctl start -D myinstance` can be
+ overwhelming. It is possible to reduce the log level with the
+ `--loglevel` parameter as in `cubicweb-ctl start -D myinstance -l
+ info` to filter out all logs under `info` gravity.
+
+upgrade
+~~~~~~~
+
+A manual upgrade step is necessary whenever a new version of CubicWeb or
+a cube is installed, in order to synchronise the instance's
+configuration and schema with the new code. The command is::
+
+ cubicweb-ctl upgrade myinstance
+
+A series of questions will be asked. It always starts with a proposal
+to make a backup of your sources (where it applies). Unless you know
+exactly what you are doing (i.e. typically fiddling in debug mode, but
+definitely NOT migrating a production instance), you should answer YES
+to that.
+
+The remaining questions concern the migration steps of |cubicweb|,
+then of the cubes that form the whole application, in reverse
+dependency order.
+
+In principle, if the migration scripts have been properly written and
+tested, you should answer YES to all questions.
+
+Somtimes, typically while debugging a migration script, something goes
+wrong and the migration fails. Unfortunately the databse may be in an
+incoherent state. You have two options here:
+
+* fix the bug, restore the database and restart the migration process
+ from scratch (quite recommended in a production environement)
+
+* try to replay the migration up to the last successful commit, that
+ is answering NO to all questions up to the step that failed, and
+ finish by answering YES to the remaining questions.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/cubicweb-ctl.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,111 @@
+.. -*- coding: utf-8 -*-
+
+.. _cubicweb-ctl:
+
+``cubicweb-ctl`` tool
+=====================
+
+`cubicweb-ctl` is the swiss knife to manage *CubicWeb* instances.
+The general syntax is ::
+
+ cubicweb-ctl <command> [options command] <arguments commands>
+
+To view available commands ::
+
+ cubicweb-ctl
+ cubicweb-ctl --help
+
+Please note that the commands available depends on the *CubicWeb* packages
+and cubes that have been installed.
+
+To view the help menu on specific command ::
+
+ cubicweb-ctl <command> --help
+
+Listing available cubes and instance
+-------------------------------------
+
+* ``list``, provides a list of the available configuration, cubes
+ and instances.
+
+
+Creation of a new cube
+-----------------------
+
+Create your new cube cube ::
+
+ cubicweb-ctl newcube
+
+This will create a new cube in
+``/path/to/grshell-cubicweb/cubes/<mycube>`` for a Mercurial
+installation, or in ``/usr/share/cubicweb/cubes`` for a debian
+packages installation.
+
+Create an instance
+-------------------
+
+You must ensure `~/etc/cubicweb.d/` exists prior to this. On windows, the
+'~' part will probably expand to 'Documents and Settings/user'.
+
+To create an instance from an existing cube, execute the following
+command ::
+
+ cubicweb-ctl create <cube_name> <instance_name>
+
+This command will create the configuration files of an instance in
+``~/etc/cubicweb.d/<instance_name>``.
+
+The tool ``cubicweb-ctl`` executes the command ``db-create`` and
+``db-init`` when you run ``create`` so that you can complete an
+instance creation in a single command. But of course it is possible
+to issue these separate commands separately, at a later stage.
+
+Command to create/initialize an instance database
+-------------------------------------------------
+
+* ``db-create``, creates the system database of an instance (tables and
+ extensions only)
+* ``db-init``, initializes the system database of an instance
+ (schema, groups, users, workflows...)
+
+Commands to control instances
+-----------------------------
+
+* ``start``, starts one or more or all instances
+
+of special interest::
+
+ start -D
+
+will start in debug mode (under windows, starting without -D will not
+work; you need instead to setup your instance as a service).
+
+* ``stop``, stops one or more or all instances
+* ``restart``, restarts one or more or all instances
+* ``status``, returns the status of the instance(s)
+
+Commands to maintain instances
+------------------------------
+
+* ``upgrade``, launches the existing instances migration when a new version
+ of *CubicWeb* or the cubes installed is available
+* ``shell``, opens a (Python based) migration shell for manual maintenance of the instance
+* ``db-dump``, creates a dump of the system database
+* ``db-restore``, restores a dump of the system database
+* ``db-check``, checks data integrity of an instance. If the automatic correction
+ is activated, it is recommanded to create a dump before this operation.
+* ``schema-sync``, synchronizes the persistent schema of an instance with
+ the instance schema. It is recommanded to create a dump before this operation.
+
+Commands to maintain i18n catalogs
+----------------------------------
+* ``i18ncubicweb``, regenerates messages catalogs of the *CubicWeb* library
+* ``i18ncube``, regenerates the messages catalogs of a cube
+* ``i18ninstance``, recompiles the messages catalogs of an instance.
+ This is automatically done while upgrading.
+
+See also chapter :ref:`internationalization`.
+
+Other commands
+--------------
+* ``delete``, deletes an instance (configuration files and database)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,28 @@
+.. -*- coding: utf-8 -*-
+
+.. _Part3:
+
+--------------
+Administration
+--------------
+
+This part is for installation and administration of the *CubicWeb* framework and
+instances based on that framework.
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ setup
+ setup-windows
+ config
+ cubicweb-ctl
+ create-instance
+ instance-config
+ site-config
+ multisources
+ ldap
+ migration
+ additional-tips
+ rql-logs
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/instance-config.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,200 @@
+.. -*- coding: utf-8 -*-
+
+
+Configure an instance
+=====================
+
+While creating an instance, a configuration file is generated in::
+
+ $ (CW_INSTANCES_DIR) / <instance> / <configuration name>.conf
+
+For example::
+
+ /etc/cubicweb.d/myblog/all-in-one.conf
+
+It is a simple text file in the INI format
+(http://en.wikipedia.org/wiki/INI_file). In the following description,
+each option name is prefixed with its own section and followed by its
+default value if necessary, e.g. "`<section>.<option>` [value]."
+
+.. _`WebServerConfig`:
+
+Configuring the Web server
+--------------------------
+:`web.auth-model` [cookie]:
+ authentication mode, cookie or http
+:`web.realm`:
+ realm of the instance in http authentication mode
+:`web.http-session-time` [0]:
+ period of inactivity of an HTTP session before it closes automatically.
+ Duration in seconds, 0 meaning no expiration (or more exactly at the
+ closing of the browser client)
+
+:`main.anonymous-user`, `main.anonymous-password`:
+ login and password to use to connect to the RQL server with
+ HTTP anonymous connection. CWUser account should exist.
+
+:`main.base-url`:
+ url base site to be used to generate the urls of web pages
+
+Https configuration
+```````````````````
+It is possible to make a site accessible for anonymous http connections
+and https for authenticated users. This requires to
+use apache (for example) for redirection and the variable `main.https-url`
+of configuration file.
+
+For this to work you have to activate the following apache modules :
+
+* rewrite
+* proxy
+* http_proxy
+
+The command on Debian based systems for that is ::
+
+ a2enmod rewrite http_proxy proxy
+ /etc/init.d/apache2 restart
+
+:Example:
+
+ For an apache redirection of a site accessible via `http://localhost/demo`
+ and `https://localhost/demo` and actually running on port 8080, it
+ takes to the http:::
+
+ ProxyPreserveHost On
+ RewriteEngine On
+ RewriteCond %{REQUEST_URI} ^/demo
+ RewriteRule ^/demo$ /demo/
+ RewriteRule ^/demo/(.*) http://127.0.0.1:8080/$1 [L,P]
+
+ and for the https:::
+
+ ProxyPreserveHost On
+ RewriteEngine On
+ RewriteCond %{REQUEST_URI} ^/ demo
+ RewriteRule ^/demo$/demo/
+ RewriteRule ^/demo/(.*) http://127.0.0.1:8080/https/$1 [L,P]
+
+
+ and we will file in the all-in-one.conf of the instance:::
+
+ base-url = http://localhost/demo
+ https-url = https://localhost/demo
+
+Notice that if you simply want a site accessible through https, not *both* http
+and https, simply set `base-url` to the https url and the first section into your
+apache configuration (as you would have to do for an http configuration with an
+apache front-end).
+
+Setting up the web client
+-------------------------
+:`web.embed-allowed`:
+ regular expression matching sites which could be "embedded" in
+ the site (controllers 'embed')
+:`web.submit-url`:
+ url where the bugs encountered in the instance can be mailed to
+
+
+RQL server configuration
+------------------------
+:`main.host`:
+ host name if it can not be detected correctly
+:`main.pid-file`:
+ file where will be written the server pid
+:`main.uid`:
+ user account to use for launching the server when it is
+ root launched by init
+:`main.session-time [30*60]`:
+ timeout of a RQL session
+:`main.query-log-file`:
+ file where all requests RQL executed by the server are written
+
+
+Configuring e-mail
+------------------
+RQL and web server side:
+
+:`email.mangle-mails [no]`:
+ indicates whether the email addresses must be displayed as is or
+ transformed
+
+RQL server side:
+
+:`email.smtp-host [mail]`:
+ hostname hosting the SMTP server to use for outgoing mail
+:`email.smtp-port [25]`:
+ SMTP server port to use for outgoing mail
+:`email.sender-name`:
+ name to use for outgoing mail of the instance
+:`email.sender-addr`:
+ address for outgoing mail of the instance
+:`email.default dest-addrs`:
+ destination addresses by default, if used by the configuration of the
+ dissemination of the model (separated by commas)
+:`email.supervising-addrs`:
+ destination addresses of e-mails of supervision (separated by
+ commas)
+
+
+Configuring logging
+-------------------
+:`main.log-threshold`:
+ level of filtering messages (DEBUG, INFO, WARNING, ERROR)
+:`main.log-file`:
+ file to write messages
+
+
+.. _PersistentProperties:
+
+Configuring persistent properties
+---------------------------------
+Other configuration settings are in the form of entities `CWProperty`
+in the database. It must be edited via the web interface or by
+RQL queries.
+
+:`ui.encoding`:
+ Character encoding to use for the web
+:`navigation.short-line-size`:
+ number of characters for "short" display
+:`navigation.page-size`:
+ maximum number of entities to show per results page
+:`navigation.related-limit`:
+ number of related entities to show up on primary entity view
+:`navigation.combobox-limit`:
+ number of entities unrelated to show up on the drop-down lists of
+ the sight on an editing entity view
+
+Cross-Origin Resource Sharing
+-----------------------------
+
+CubicWeb provides some support for the CORS_ protocol. For now, the
+provided implementation only deals with access to a CubicWeb instance
+as a whole. Support for a finer granularity may be considered in the
+future.
+
+Specificities of the provided implementation:
+
+- ``Access-Control-Allow-Credentials`` is always true
+- ``Access-Control-Allow-Origin`` header in response will never be
+ ``*``
+- ``Access-Control-Expose-Headers`` can be configured globally (see below)
+- ``Access-Control-Max-Age`` can be configured globally (see below)
+- ``Access-Control-Allow-Methods`` can be configured globally (see below)
+- ``Access-Control-Allow-Headers`` can be configured globally (see below)
+
+
+A few parameters can be set to configure the CORS_ capabilities of CubicWeb.
+
+.. _CORS: http://www.w3.org/TR/cors/
+
+:`access-control-allow-origin`:
+ comma-separated list of allowed origin domains or "*" for any domain
+:`access-control-allow-methods`:
+ comma-separated list of allowed HTTP methods
+:`access-control-max-age`:
+ maximum age of cross-origin resource sharing (in seconds)
+:`access-control-allow-headers`:
+ comma-separated list of allowed HTTP custom headers (used in simple requests)
+:`access-control-expose-headers`:
+ comma-separated list of allowed HTTP custom headers (used in preflight requests)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/ldap.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,134 @@
+.. _LDAP:
+
+LDAP integration
+================
+
+Overview
+--------
+
+Using LDAP as a source for user credentials and information is quite
+easy. The most difficult part lies in building an LDAP schema or
+using an existing one.
+
+At cube creation time, one is asked if more sources are wanted. LDAP
+is one possible option at this time. Of course, it is always possible
+to set it up later using the `CWSource` entity type, which we discuss
+there.
+
+It is possible to add as many LDAP sources as wanted, which translates
+in as many `CWSource` entities as needed.
+
+The general principle of the LDAP source is, given a proper
+configuration, to create local users matching the users available in
+the directory and deriving local user attributes from directory users
+attributes. Then a periodic task ensures local user information
+synchronization with the directory.
+
+Users handled by such a source should not be edited directly from
+within the application instance itself. Rather, updates should happen
+at the LDAP server level.
+
+Credential checks are _always_ done against the LDAP server.
+
+.. Note::
+
+ There are currently two ldap source types: the older `ldapuser` and
+ the newer `ldapfeed`. The older will be deprecated anytime soon, as
+ the newer has now gained all the features of the old and does not
+ suffer from some of its illnesses.
+
+ The ldapfeed creates real `CWUser` entities, and then
+ activate/deactivate them depending on their presence/absence in the
+ corresponding LDAP source. Their attribute and state
+ (activated/deactivated) are hence managed by the source mechanism;
+ they should not be altered by other means (as such alterations may
+ be overridden in some subsequent source synchronisation).
+
+
+Configuration of an LDAPfeed source
+-----------------------------------
+
+Additional sources are created at cube creation time or later through the
+user interface.
+
+Configure an `ldapfeed` source from the user interface under `Manage` then
+`data sources`:
+
+* At this point `type` has been set to `ldapfeed`.
+
+* The `parser` attribute shall be set to `ldapfeed`.
+
+* The `url` attribute shall be set to an URL such as ldap://ldapserver.domain/.
+
+* The `configuration` attribute contains many options. They are described in
+ detail in the next paragraph.
+
+
+Options of an LDAPfeed source
+-----------------------------
+
+Let us enumerate the options by categories (LDAP server connection,
+LDAP schema mapping information).
+
+LDAP server connection options:
+
+* `auth-mode`, (choices are simple, cram_md5, digest_md5, gssapi, support
+ for the later being partial as of now)
+
+* `auth-realm`, realm to use when using gssapi/kerberos authentication
+
+* `data-cnx-dn`, user dn to use to open data connection to the ldap (eg
+ used to respond to rql queries)
+
+* `data-cnx-password`, password to use to open data connection to the
+ ldap (eg used to respond to rql queries)
+
+If the LDAP server accepts anonymous binds, then it is possible to
+leave data-cnx-dn and data-cnx-password empty. This is, however, quite
+unlikely in practice. Beware that the LDAP server might hide attributes
+such as "userPassword" while the rest of the attributes remain visible
+through an anonymous binding.
+
+LDAP schema mapping options:
+
+* `user-base-dn`, base DN to lookup for users
+
+* `user-scope`, user search scope (valid values: "BASE", "ONELEVEL",
+ "SUBTREE")
+
+* `user-classes`, classes of user (with Active Directory, you want to
+ say "user" here)
+
+* `user-filter`, additional filters to be set in the ldap query to
+ find valid users
+
+* `user-login-attr`, attribute used as login on authentication (with
+ Active Directory, you want to use "sAMAccountName" here)
+
+* `user-default-group`, name of a group in which ldap users will be by
+ default. You can set multiple groups by separating them by a comma
+
+* `user-attrs-map`, map from ldap user attributes to cubicweb
+ attributes (with Active Directory, you want to use
+ sAMAccountName:login,mail:email,givenName:firstname,sn:surname)
+
+
+Other notes
+-----------
+
+* Cubicweb is able to start if ldap cannot be reached, even on
+ cubicweb-ctl start ... If some source ldap server cannot be used
+ while an instance is running, the corresponding users won't be
+ authenticated but their status will not change (e.g. they will not
+ be deactivated)
+
+* The user-base-dn is a key that helps cubicweb map CWUsers to LDAP
+ users: beware updating it
+
+* When a user is removed from an LDAP source, it is deactivated in the
+ CubicWeb instance; when a deactivated user comes back in the LDAP
+ source, it (automatically) is activated again
+
+* You can use the :class:`CWSourceHostConfig` to have variants for a source
+ configuration according to the host the instance is running on. To do so
+ go on the source's view from the sources management view.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/migration.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,38 @@
+.. -*- coding: utf-8 -*-
+
+Migrating cubicweb instances - benefits from a distributed architecture
+=======================================================================
+
+Migrate apache & cubicweb
+-------------------------
+
+**Aim** : do the migration for N cubicweb instances hosted on a server to another with no downtime.
+
+**Prerequisites** : have an explicit definition of the database host (not default or localhost). In our case, the database is hosted on another host.
+
+**Steps** :
+
+1. *on new machine* : install your environment (*pseudocode*) ::
+
+ apt-get install cubicweb cubicweb-applications apache2
+
+2. *on old machine* : copy your cubicweb and apache configuration to the new machine ::
+
+ scp /etc/cubicweb.d/ newmachine:/etc/cubicweb.d/
+ scp /etc/apache2/sites-available/ newmachine:/etc/apache2/sites-available/
+
+3. *on new machine* : start your instances ::
+
+ cubicweb start
+
+4. *on new machine* : enable sites and modules for apache and start it, test it using by modifying your /etc/host file.
+
+5. change dns entry from your oldmachine to newmachine
+
+6. shutdown your *old machine* (if it doesn't host other services or your database)
+
+7. That's it.
+
+**Possible enhancements** : use right from the start a pound server behind your apache, that way you can add backends and smoothily migrate by shuting down backends that pound will take into account.
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/multisources.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,6 @@
+Multiple sources of data
+========================
+
+Data sources include SQL, LDAP, RQL, mercurial and subversion.
+
+.. XXX feed me
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/pyro.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,62 @@
+.. _UsingPyro:
+
+Working with a distributed client (using Pyro)
+==============================================
+
+In some circumstances, it is practical to split the repository and
+web-client parts of the application for load-balancing reasons. Or
+one wants to access the repository from independant scripts to consult
+or update the database.
+
+Prerequisites
+-------------
+
+For this to work, several steps have to be taken in order.
+
+You must first ensure that the appropriate software is installed and
+running (see :ref:`ConfigEnv`)::
+
+ pyro-nsd -x -p 6969
+
+Then you have to set appropriate options in your configuration. For
+instance::
+
+ pyro-server=yes
+ pyro-ns-host=localhost:6969
+
+ pyro-instance-id=myinstancename
+
+Connect to the CubicWeb repository from a python script
+-------------------------------------------------------
+
+Assuming pyro-nsd is running and your instance is configured with ``pyro-server=yes``,
+you will be able to use :mod:`cubicweb.dbapi` api to initiate the connection.
+
+.. note::
+ Regardless of whether your instance is pyro activated or not, you can still
+ achieve this by using cubicweb-ctl shell scripts in a simpler way, as by default
+ it creates a repository 'in-memory' instead of connecting through pyro. That
+ also means you've to be on the host where the instance is running.
+
+Finally, the client (for instance a python script) must connect specifically
+as in the following example code:
+
+.. sourcecode:: python
+
+ from cubicweb import dbapi
+
+ cnx = dbapi.connect(database='instance-id', user='admin', password='admin')
+ cnx.load_appobjects()
+ cur = cnx.cursor()
+ for name in (u'Personal', u'Professional', u'Computers'):
+ cur.execute('INSERT Tag T: T name %(n)s', {'n': name})
+ cnx.commit()
+
+Calling :meth:`cubicweb.dbapi.load_appobjects`, will populate the
+cubicweb registries (see :ref:`VRegistryIntro`) with the application
+objects installed on the host where the script runs. You'll then be
+allowed to use the ORM goodies and custom entity methods and views. Of
+course this is optional, without it you can still get the repository
+data through the connection but in a roughly way: only RQL cursors
+will be available, e.g. you can't even build entity objects from the
+result set.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/rql-logs.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,14 @@
+.. -*- coding: utf-8 -*-
+
+RQL logs
+========
+
+You can configure the *CubicWeb* instance to keep a log
+of the queries executed against your database. To do so,
+edit the configuration file of your instance
+``.../etc/cubicweb.d/myapp/all-in-one.conf`` and uncomment the
+variable ``query-log-file``::
+
+ # web instance query log file
+ query-log-file=/tmp/rql-myapp.log
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/setup-windows.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,146 @@
+.. -*- coding: utf-8 -*-
+
+.. _SetUpWindowsEnv:
+
+Installing a development environement on Windows
+================================================
+
+Setting up a Windows development environment is not too complicated
+but it requires a series of small steps.
+
+We propose an example of a typical |cubicweb| installation on Windows
+from sources. We assume everything goes into ``C:\\`` and for any
+package, without version specification, "the latest is
+the greatest".
+
+Mind that adjusting the installation drive should be straightforward.
+
+
+
+Install the required elements
+-----------------------------
+
+|cubicweb| requires some base elements that must be installed to run
+correctly. So, first of all, you must install them :
+
+* python >= 2.6 and < 3
+ (`Download Python <http://www.python.org/download/>`_).
+ You can also consider the Python(x,y) distribution
+ (`Download Python(x,y) <http://code.google.com/p/pythonxy/wiki/Downloads>`_)
+ as it makes things easier for Windows user by wrapping in a single installer
+ python 2.7 plus numerous useful third-party modules and
+ applications (including Eclipse + pydev, which is an arguably good
+ IDE for Python under Windows).
+
+* `Twisted <http://twistedmatrix.com/trac/>`_ is an event-driven
+ networking engine
+ (`Download Twisted <http://twistedmatrix.com/trac/>`_)
+
+* `lxml <http://codespeak.net/lxml/>`_ library
+ (version >=2.2.1) allows working with XML and HTML
+ (`Download lxml <http://pypi.python.org/pypi/lxml/2.2.1>`_)
+
+* `Postgresql <http://www.postgresql.org/>`_,
+ an object-relational database system
+ (`Download Postgresql <http://www.enterprisedb.com/products/pgdownload.do#windows>`_)
+ and its python drivers
+ (`Download psycopg <http://www.stickpeople.com/projects/python/win-psycopg/#Version2>`_)
+
+* A recent version of `gettext`
+ (`Download gettext <http://download.logilab.org/pub/gettext/gettext-0.17-win32-setup.exe>`_).
+
+* `rql <http://www.logilab.org/project/rql>`_,
+ the recent version of the Relationship Query Language parser.
+
+Install optional elements
+-------------------------
+
+We recommend you to install the following elements. They are not
+mandatory but they activate very interesting features in |cubicweb|:
+
+* `python-ldap <http://pypi.python.org/pypi/python-ldap>`_
+ provides access to LDAP/Active directory directories
+ (`Download python-ldap <http://www.osuch.org/python-ldap>`_).
+
+* `graphviz <http://www.graphviz.org/>`_
+ which allow schema drawings.
+ (`Download graphviz <http://www.graphviz.org/Download_windows.php>`_).
+ It is quite recommended (albeit not mandatory).
+
+Other elements will activate more features once installed. Take a look
+at :ref:`InstallDependencies`.
+
+Useful tools
+------------
+
+Some additional tools could be useful to develop :ref:`cubes <AvailableCubes>`
+with the framework.
+
+* `mercurial <http://mercurial.selenic.com/>`_ and its standard windows GUI
+ (`TortoiseHG <http://tortoisehg.bitbucket.org/>`_) allow you to get the source
+ code of |cubicweb| from control version repositories. So you will be able to
+ get the latest development version and pre-release bugfixes in an easy way
+ (`Download mercurial <http://bitbucket.org/tortoisehg/stable/wiki/download>`_).
+
+* You can also consider the ssh client `Putty` in order to peruse
+ mercurial over ssh (`Download <http://www.putty.org/>`_).
+
+* If you are an Eclipse user, mercurial can be integrated using the
+ `MercurialEclipse` plugin
+ (`Home page <http://www.vectrace.com/mercurialeclipse/>`_).
+
+Getting the sources
+-------------------
+
+There are two ways to get the sources of |cubicweb| and its
+:ref:`cubes <AvailableCubes>`:
+
+* download the latest release (:ref:`SourceInstallation`)
+* get the development version using Mercurial
+ (:ref:`MercurialInstallation`)
+
+Environment variables
+---------------------
+
+You will need some convenience environment variables once all is set up. These
+variables are settable through the GUI by getting at the `System properties`
+window (by righ-clicking on `My Computer` -> `properties`).
+
+In the `advanced` tab, there is an `Environment variables` button. Click on
+it. That opens a small window allowing edition of user-related and system-wide
+variables.
+
+We will consider only user variables. First, the ``PATH`` variable. Assuming
+you are logged as user *Jane*, add the following paths, separated by
+semi-colons::
+
+ C:\Documents and Settings\Jane\My Documents\Python\cubicweb\cubicweb\bin
+ C:\Program Files\Graphviz2.24\bin
+
+The ``PYTHONPATH`` variable should also contain::
+
+ C:\Documents and Settings\Jane\My Documents\Python\cubicweb\
+
+From now, on a fresh `cmd` shell, you should be able to type::
+
+ cubicweb-ctl list
+
+... and get a meaningful output.
+
+Running an instance as a service
+--------------------------------
+
+This currently assumes that the instances configurations is located at
+``C:\\etc\\cubicweb.d``. For a cube 'my_instance', you will find
+``C:\\etc\\cubicweb.d\\my_instance\\win32svc.py``.
+
+Now, register your instance as a windows service with::
+
+ win32svc install
+
+Then start the service with::
+
+ net start cubicweb-my_instance
+
+In case this does not work, you should be able to see error reports in
+the application log, using the windows event log viewer.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/setup.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,269 @@
+.. -*- coding: utf-8 -*-
+
+.. _SetUpEnv:
+
+Installation of a *CubicWeb* environment
+========================================
+
+Official releases are available from the `CubicWeb.org forge`_ and from
+`PyPI`_. Since CubicWeb is developed using `Agile software development
+<http://en.wikipedia.org/wiki/Agile_software_development>`_ techniques, releases
+happen frequently. In a version numbered X.Y.Z, X changes after a few years when
+the API breaks, Y changes after a few weeks when features are added and Z
+changes after a few days when bugs are fixed.
+
+Depending on your needs, you will chose a different way to install CubicWeb on
+your system:
+
+- `Installation on Debian/Ubuntu`_
+- `Installation on Windows`_
+- `Installation in a virtualenv`_
+- `Installation with pip`_
+- `Installation with easy_install`_
+- `Installation from tarball`_
+
+If you are a power-user and need the very latest features, you will
+
+- `Install from version control`_
+
+Once the software is installed, move on to :ref:`ConfigEnv` for better control
+and advanced features of |cubicweb|.
+
+.. _`Installation on Debian/Ubuntu`: DebianInstallation_
+.. _`Installation on Windows`: WindowsInstallation_
+.. _`Installation in a virtualenv`: VirtualenvInstallation_
+.. _`Installation with pip`: PipInstallation_
+.. _`Installation with easy_install`: EasyInstallInstallation_
+.. _`Installation from tarball`: TarballInstallation_
+.. _`Install from version control`: MercurialInstallation_
+
+
+.. _DebianInstallation:
+
+Debian/Ubuntu install
+---------------------
+
+|cubicweb| is packaged for Debian/Ubuntu (and derived
+distributions). Their integrated package-management system make
+installation and upgrade much easier for users since
+dependencies (like databases) are automatically installed.
+
+Depending on the distribution you are using, add the appropriate line to your
+`list of sources` (for example by editing ``/etc/apt/sources.list``).
+
+For Debian 7.0 Wheezy (stable)::
+
+ deb http://download.logilab.org/production/ wheezy/
+
+For Debian Sid (unstable)::
+
+ deb http://download.logilab.org/production/ sid/
+
+For Ubuntu 12.04 Precise Pangolin (Long Term Support) and newer::
+
+ deb http://download.logilab.org/production/ precise/
+
+The repositories are signed with the `Logilab's gnupg key`_. You can download
+and register the key to avoid warnings::
+
+ wget -q http://download.logilab.org/logilab-dists-key.asc -O- | sudo apt-key add -
+
+Update your list of packages and perform the installation::
+
+ apt-get update
+ apt-get install cubicweb cubicweb-dev
+
+``cubicweb`` installs the framework itself, allowing you to create new
+instances. ``cubicweb-dev`` installs the development environment
+allowing you to develop new cubes.
+
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of available cubes using ``apt-cache search cubicweb`` or at the
+`CubicWeb.org forge`_.
+
+.. note::
+
+ `cubicweb-dev` will install basic sqlite support. You can easily setup
+ :ref:`cubicweb with other database <DatabaseInstallation>` using the following
+ virtual packages :
+
+ * `cubicweb-postgresql-support` contains the necessary dependencies for
+ using :ref:`cubicweb with postgresql datatabase <PostgresqlConfiguration>`
+
+ * `cubicweb-mysql-support` contains the necessary dependencies for using
+ :ref:`cubicweb with mysql database <MySqlConfiguration>`.
+
+.. _`list of sources`: http://wiki.debian.org/SourcesList
+.. _`Logilab's gnupg key`: http://download.logilab.org/logilab-dists-key.asc
+.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/
+
+.. _WindowsInstallation:
+
+Windows Install
+---------------
+
+You need to have `python`_ version >= 2.5 and < 3 installed.
+
+If you want an automated install, your best option is probably the
+:ref:`EasyInstallInstallation`. EasyInstall is a tool that helps users to
+install python packages along with their dependencies, searching for suitable
+pre-compiled binaries on the `The Python Package Index`_.
+
+If you want better control over the process as well as a suitable development
+environment or if you are having problems with `easy_install`, read on to
+:ref:`SetUpWindowsEnv`.
+
+.. _python: http://www.python.org/
+.. _`The Python Package Index`: http://pypi.python.org
+
+.. _VirtualenvInstallation:
+
+`Virtualenv` install
+--------------------
+
+|cubicweb| can be safely installed, used and contained inside a
+`virtualenv`_. You can use either :ref:`pip <PipInstallation>` or
+:ref:`easy_install <EasyInstallInstallation>` to install |cubicweb|
+inside an activated virtual environment.
+
+.. _PipInstallation:
+
+`pip` install
+-------------
+
+`pip <http://pip.openplans.org/>`_ is a python tool that helps downloading,
+building, installing, and managing Python packages and their dependencies. It
+is fully compatible with `virtualenv`_ and installs the packages from sources
+published on the `The Python Package Index`_.
+
+.. _`virtualenv`: http://virtualenv.openplans.org/
+
+A working compilation chain is needed to build the modules that include C
+extensions. If you really do not want to compile anything, installing `lxml <http://lxml.de/>`_,
+`Twisted Web <http://twistedmatrix.com/trac/wiki/Downloads/>`_ and `libgecode
+<http://www.gecode.org/>`_ will help.
+
+For Debian, these minimal dependencies can be obtained by doing::
+
+ apt-get install gcc python-pip python-dev python-lxml
+
+or, if you prefer to get as much as possible from pip::
+
+ apt-get install gcc python-pip python-dev libxslt1-dev libxml2-dev
+
+For Windows, you can install pre-built packages (possible `source
+<http://www.lfd.uci.edu/~gohlke/pythonlibs/>`_). For a minimal setup, install:
+
+- pip http://www.lfd.uci.edu/~gohlke/pythonlibs/#pip
+- setuptools http://www.lfd.uci.edu/~gohlke/pythonlibs/#setuptools
+- libxml-python http://www.lfd.uci.edu/~gohlke/pythonlibs/#libxml-python>
+- lxml http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml and
+- twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
+
+Make sure to choose the correct architecture and version of Python.
+
+Finally, install |cubicweb| and its dependencies, by running::
+
+ pip install cubicweb
+
+Many other :ref:`cubes <AvailableCubes>` are available. A list is available at
+`PyPI <http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
+or at the `CubicWeb.org forge`_.
+
+For example, installing the *blog cube* is achieved by::
+
+ pip install cubicweb-blog
+
+.. _EasyInstallInstallation:
+
+`easy_install` install
+----------------------
+
+.. note::
+
+ If you are not a Windows user and you have a compilation environment, we
+ recommend you to use the PipInstallation_.
+
+`easy_install`_ is a python utility that helps downloading, installing, and
+managing python packages and their dependencies.
+
+Install |cubicweb| and its dependencies, run::
+
+ easy_install cubicweb
+
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of available cubes on `PyPI
+<http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
+or at the `CubicWeb.org Forge`_.
+
+For example, installing the *blog cube* is achieved by::
+
+ easy_install cubicweb-blog
+
+.. note::
+
+ If you encounter problem with :ref:`cubes <AvailableCubes>` installation,
+ consider using :ref:`PipInstallation` which is more stable
+ but can not installed pre-compiled binaries.
+
+.. _`easy_install`: http://packages.python.org/distribute/easy_install.html
+
+
+.. _SourceInstallation:
+
+Install from source
+-------------------
+
+.. _TarballInstallation:
+
+You can download the archive containing the sources from
+`http://download.logilab.org/pub/cubicweb/ <http://download.logilab.org/pub/cubicweb/>`_.
+
+Make sure you also have all the :ref:`InstallDependencies`.
+
+Once uncompressed, you can install the framework from inside the uncompressed
+folder with::
+
+ python setup.py install
+
+Or you can run |cubicweb| directly from the source directory by
+setting the :ref:`resource mode <RessourcesConfiguration>` to `user`. This will
+ease the development with the framework.
+
+There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
+list of availble cubes at the `CubicWeb.org Forge`_.
+
+
+.. _MercurialInstallation:
+
+Install from version control system
+-----------------------------------
+
+To keep-up with on-going development, clone the :ref:`Mercurial
+<MercurialPresentation>` repository::
+
+ hg clone -u stable http://hg.logilab.org/cubicweb # stable branch
+ hg clone http://hg.logilab.org/cubicweb # development branch
+
+To get many of CubicWeb's dependencies and a nice set of base cubes, run the
+`clone_deps.py` script located in `cubicweb/bin/`::
+
+ python cubicweb/bin/clone_deps.py
+
+(Windows users should replace slashes with antislashes).
+
+This script will clone a set of mercurial repositories into the
+directory containing the ``cubicweb`` repository, and update them to the
+latest published version tag (if any).
+
+.. note::
+
+ In every cloned repositories, a `hg tags` will display a list of
+ tags in reverse chronological order. One reasonnable option is to go to a
+ tagged version: the latest published version or example, as done by
+ the `clone_deps` script)::
+
+ hg update cubicweb-version-3.12.2
+
+Make sure you also have all the :ref:`InstallDependencies`.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/admin/site-config.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,94 @@
+.. -*- coding: utf-8 -*-
+
+User interface for web site configuration
+=========================================
+
+.. image:: ../images/lax-book_03-site-config-panel_en.png
+
+This panel allows you to configure the appearance of your instance site.
+Six menus are available and we will go through each of them to explain how
+to use them.
+
+Navigation
+~~~~~~~~~~
+This menu provides you a way to adjust some navigation options depending on
+your needs, such as the number of entities to display by page of results.
+Follows the detailled list of available options :
+
+* navigation.combobox-limit : maximum number of entities to display in related
+ combo box (sample format: 23)
+* navigation.page-size : maximum number of objects displayed by page of results
+ (sample format: 23)
+* navigation.related-limit : maximum number of related entities to display in
+ the primary view (sample format: 23)
+* navigation.short-line-size : maximum number of characters in short description
+ (sample format: 23)
+
+UI
+~~
+This menu provides you a way to customize the user interface settings such as
+date format or encoding in the produced html.
+Follows the detailled list of available options :
+
+* ui.date-format : how to format date in the ui ("man strftime" for format description)
+* ui.datetime-format : how to format date and time in the ui ("man strftime" for format
+ description)
+* ui.default-text-format : default text format for rich text fields.
+* ui.encoding : user interface encoding
+* ui.fckeditor :should html fields being edited using fckeditor (a HTML WYSIWYG editor).
+ You should also select text/html as default text format to actually get fckeditor.
+* ui.float-format : how to format float numbers in the ui
+* ui.language : language of the user interface
+* ui.main-template : id of main template used to render pages
+* ui.site-title : site title, which is displayed right next to the logo in the header
+* ui.time-format : how to format time in the ui ("man strftime" for format description)
+
+
+Actions
+~~~~~~~
+This menu provides a way to configure the context in which you expect the actions
+to be displayed to the user and if you want the action to be visible or not.
+You must have notice that when you view a list of entities, an action box is
+available on the left column which display some actions as well as a drop-down
+menu for more actions.
+
+The context available are :
+
+* mainactions : actions listed in the left box
+* moreactions : actions listed in the `more` menu of the left box
+* addrelated : add actions listed in the left box
+* useractions : actions listed in the first section of drop-down menu
+ accessible from the right corner user login link
+* siteactions : actions listed in the second section of drop-down menu
+ accessible from the right corner user login link
+* hidden : select this to hide the specific action
+
+Boxes
+~~~~~
+The instance has already a pre-defined set of boxes you can use right away.
+This configuration section allows you to place those boxes where you want in the
+instance interface to customize it.
+
+The available boxes are :
+
+* actions box : box listing the applicable actions on the displayed data
+
+* boxes_blog_archives_box : box listing the blog archives
+
+* possible views box : box listing the possible views for the displayed data
+
+* rss box : RSS icon to get displayed data as a RSS thread
+
+* search box : search box
+
+* startup views box : box listing the configuration options available for
+ the instance site, such as `Preferences` and `Site Configuration`
+
+Components
+~~~~~~~~~~
+[WRITE ME]
+
+Contextual components
+~~~~~~~~~~~~~~~~~~~~~
+[WRITE ME]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/depends.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,58 @@
+.. -*- coding: utf-8 -*-
+
+.. _InstallDependencies:
+
+Installation dependencies
+=========================
+
+When you run CubicWeb from source, either by downloading the tarball or
+cloning the mercurial tree, here is the list of tools and libraries you need
+to have installed in order for CubicWeb to work:
+
+* yapps - http://theory.stanford.edu/~amitp/yapps/ -
+ http://pypi.python.org/pypi/Yapps2
+
+* pygraphviz - http://networkx.lanl.gov/pygraphviz/ -
+ http://pypi.python.org/pypi/pygraphviz
+
+* docutils - http://docutils.sourceforge.net/ - http://pypi.python.org/pypi/docutils
+
+* lxml - http://codespeak.net/lxml - http://pypi.python.org/pypi/lxml
+
+* twisted - http://twistedmatrix.com/ - http://pypi.python.org/pypi/Twisted
+
+* logilab-common - http://www.logilab.org/project/logilab-common -
+ http://pypi.python.org/pypi/logilab-common/
+
+* logilab-database - http://www.logilab.org/project/logilab-database -
+ http://pypi.python.org/pypi/logilab-database/
+
+* logilab-constraint - http://www.logilab.org/project/logilab-constraint -
+ http://pypi.python.org/pypi/constraint/
+
+* logilab-mtconverter - http://www.logilab.org/project/logilab-mtconverter -
+ http://pypi.python.org/pypi/logilab-mtconverter
+
+* rql - http://www.logilab.org/project/rql - http://pypi.python.org/pypi/rql
+
+* yams - http://www.logilab.org/project/yams - http://pypi.python.org/pypi/yams
+
+* indexer - http://www.logilab.org/project/indexer -
+ http://pypi.python.org/pypi/indexer
+
+* passlib - https://code.google.com/p/passlib/ -
+ http://pypi.python.org/pypi/passlib
+
+If you're using a Postgresql database (recommended):
+
+* psycopg2 - http://initd.org/projects/psycopg2 - http://pypi.python.org/pypi/psycopg2
+* plpythonu extension
+
+Other optional packages:
+
+* fyzz - http://www.logilab.org/project/fyzz -
+ http://pypi.python.org/pypi/fyzz *to activate Sparql querying*
+
+
+Any help with the packaging of CubicWeb for more than Debian/Ubuntu (including
+eggs, buildouts, etc) will be greatly appreciated.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/docstrings-conventions.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,106 @@
+Javascript docstrings
+=====================
+
+Whereas in Python source code we only need to include a module docstrings
+using the directive `.. automodule:: mypythonmodule`, we will have to
+explicitely define Javascript modules and functions in the doctrings since
+there is no native directive to include Javascript files.
+
+Rest generation
+---------------
+
+`pyjsrest` is a small utility parsing Javascript doctrings and generating the
+corresponding Restructured file used by Sphinx to generate HTML documentation.
+This script will have the following structure::
+
+ ===========
+ filename.js
+ ===========
+ .. module:: filename.js
+
+We use the `.. module::` directive to register a javascript library
+as a Python module for Sphinx. This provides an entry in the module index.
+
+The contents of the docstring found in the javascript file will be added as is
+following the module declaration. No treatment will be done on the doctring.
+All the documentation structure will be in the docstrings and will comply
+with the following rules.
+
+Docstring structure
+-------------------
+
+Basically we document javascript with RestructuredText docstring
+following the same convention as documenting Python code.
+
+The doctring in Javascript files must be contained in standard
+Javascript comment signs, starting with `/**` and ending with `*/`,
+such as::
+
+ /**
+ * My comment starts here.
+ * This is the second line prefixed with a `*`.
+ * ...
+ * ...
+ * All the follwing line will be prefixed with a `*` followed by a space.
+ * ...
+ * ...
+ */
+
+
+Comments line prefixed by `//` will be ignored. They are reserved for source
+code comments dedicated to developers.
+
+
+Javscript functions docstring
+-----------------------------
+
+By default, the `function` directive describes a module-level function.
+
+`function` directive
+~~~~~~~~~~~~~~~~~~~~
+
+Its purpose is to define the function prototype such as::
+
+ .. function:: loadxhtml(url, data, reqtype, mode)
+
+If any namespace is used, we should add it in the prototype for now,
+until we define an appropriate directive::
+
+ .. function:: jQuery.fn.loadxhtml(url, data, reqtype, mode)
+
+Function parameters
+~~~~~~~~~~~~~~~~~~~
+
+We will define function parameters as a bulleted list, where the
+parameter name will be backquoted and followed by its description.
+
+Example of a javascript function docstring::
+
+ .. function:: loadxhtml(url, data, reqtype, mode)
+
+ cubicweb loadxhtml plugin to make jquery handle xhtml response
+
+ fetches `url` and replaces this's content with the result
+
+ Its arguments are:
+
+ * `url`
+
+ * `mode`, how the replacement should be done (default is 'replace')
+ Possible values are :
+ - 'replace' to replace the node's content with the generated HTML
+ - 'swap' to replace the node itself with the generated HTML
+ - 'append' to append the generated HTML to the node's content
+
+
+Optional parameter specification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Javascript functions handle arguments not listed in the function signature.
+In the javascript code, they will be flagged using `/* ... */`. In the docstring,
+we flag those optional arguments the same way we would define it in
+Python::
+
+ .. function:: asyncRemoteExec(fname, arg1=None, arg2=None)
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/faq.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,437 @@
+.. -*- coding: utf-8 -*-
+
+Frequently Asked Questions (FAQ)
+================================
+
+
+Generalities
+````````````
+
+Why do you use the LGPL license to prevent me from doing X ?
+------------------------------------------------------------
+
+LGPL means that *if* you redistribute your application, you need to
+redistribute the changes you made to CubicWeb under the LGPL licence.
+
+Publishing a web site has nothing to do with redistributing source
+code according to the terms of the LGPL. A fair amount of companies
+use modified LGPL code for internal use. And someone could publish a
+*CubicWeb* component under a BSD licence for others to plug into a
+LGPL framework without any problem. The only thing we are trying to
+prevent here is someone taking the framework and packaging it as
+closed source to his own clients.
+
+Why does not CubicWeb have a template language ?
+------------------------------------------------
+
+There are enough template languages out there. You can use your
+preferred template language if you want. [explain how to use a
+template language]
+
+*CubicWeb* does not define its own templating language as this was
+not our goal. Based on our experience, we realized that
+we could gain productivity by letting designers use design tools
+and developpers develop without the use of the templating language
+as an intermediary that could not be anyway efficient for both parties.
+Python is the templating language that we use in *CubicWeb*, but again,
+it does not prevent you from using a templating language.
+
+Moreover, CubicWeb currently supports `simpletal`_ out of the box and
+it is also possible to use the `cwtags`_ library to build html trees
+using the `with statement`_ with more comfort than raw strings.
+
+.. _`simpletal`: http://www.owlfish.com/software/simpleTAL/
+.. _`cwtags`: http://www.cubicweb.org/project/cwtags
+.. _`with statement`: http://www.python.org/dev/peps/pep-0343/
+
+Why do you think using pure python is better than using a template language ?
+-----------------------------------------------------------------------------
+
+Python is an Object Oriented Programming language and as such it
+already provides a consistent and strong architecture and syntax
+a templating language would not reach.
+
+Using Python instead of a template langage for describing the user interface
+makes it to maintain with real functions/classes/contexts without the need of
+learning a new dialect. By using Python, we use standard OOP techniques and
+this is a key factor in a robust application.
+
+CubicWeb looks pretty recent. Is it stable ?
+--------------------------------------------
+
+It is constantly evolving, piece by piece. The framework has evolved since
+2001 and data has been migrated from one schema to the other ever since. There
+is a well-defined way to handle data and schema migration.
+
+You can see the roadmap there:
+http://www.cubicweb.org/project/cubicweb?tab=projectroadmap_tab.
+
+
+Why is the RQL query language looking similar to X ?
+----------------------------------------------------
+
+It may remind you of SQL but it is higher level than SQL, more like
+SPARQL. Except that SPARQL did not exist when we started the project.
+With version 3.4, CubicWeb has support for SPARQL.
+
+The RQL language is what is going to make a difference with django-
+like frameworks for several reasons.
+
+1. accessing data is *much* easier with it. One can write complex
+ queries with RQL that would be tedious to define and hard to maintain
+ using an object/filter suite of method calls.
+
+2. it offers an abstraction layer allowing your applications to run
+ on multiple back-ends. That means not only various SQL backends
+ (postgresql, sqlite, sqlserver, mysql), but also non-SQL data stores like
+ LDAP directories and subversion/mercurial repositories (see the `vcsfile`
+ component).
+
+Which ajax library is CubicWeb using ?
+--------------------------------------
+
+CubicWeb uses jQuery_ and provides a few helpers on top of that. Additionally,
+some jQuery plugins are provided (some are provided in specific cubes).
+
+.. _jQuery: http://jquery.com
+
+
+Development
+```````````
+
+How to change the instance logo ?
+---------------------------------
+
+The logo is managed by css. You must provide a custom css that will contain
+the code below:
+
+::
+
+ #logo {
+ background-image: url("logo.jpg");
+ }
+
+
+``logo.jpg`` is in ``mycube/data`` directory.
+
+How to create an anonymous user ?
+---------------------------------
+
+This allows to browse the site without being authenticated. In the
+``all-in-one.conf`` file of your instance, define the anonymous user
+as follows ::
+
+ # login of the CubicWeb user account to use for anonymous user (if you want to
+ # allow anonymous)
+ anonymous-user=anon
+
+ # password of the CubicWeb user account matching login
+ anonymous-password=anon
+
+You also must ensure that this `anon` user is a registered user of
+the DB backend. If not, you can create through the administation
+interface of your instance by adding a user with in the group `guests`.
+
+.. note::
+ While creating a new instance, you can decide to allow access
+ to anonymous user, which will automatically execute what is
+ decribed above.
+
+How to load data from a python script ?
+---------------------------------------
+Please, refer to :ref:`UsingPyro`.
+
+
+How to format an entity date attribute ?
+----------------------------------------
+
+If your schema has an attribute of type `Date` or `Datetime`, you usually want to
+format it when displaying it. First, you should define your preferred format
+using the site configuration panel
+``http://appurl/view?vid=systempropertiesform`` and then set ``ui.date`` and/or
+``ui.datetime``. Then in the view code, use:
+
+.. sourcecode:: python
+
+ entity.printable_value(date_attribute)
+
+which will always return a string whatever the attribute's type (so it's
+recommended also for other attribute types). By default it expects to generate
+HTML, so it deals with rich text formating, xml escaping...
+
+How to update a database after a schema modification ?
+------------------------------------------------------
+
+It depends on what has been modified in the schema.
+
+* update the permissions and properties of an entity or a relation:
+ ``sync_schema_props_perms('MyEntityOrRelation')``.
+
+* add an attribute: ``add_attribute('MyEntityType', 'myattr')``.
+
+* add a relation: ``add_relation_definition('SubjRelation', 'MyRelation', 'ObjRelation')``.
+
+I get `NoSelectableObject` exceptions, how do I debug selectors ?
+-----------------------------------------------------------------
+
+You just need to put the appropriate context manager around view/component
+selection. One standard place for components is in cubicweb/vregistry.py:
+
+.. sourcecode:: python
+
+ def possible_objects(self, *args, **kwargs):
+ """return an iterator on possible objects in this registry for the given
+ context
+ """
+ from logilab.common.registry import traced_selection
+ with traced_selection():
+ for appobjects in self.itervalues():
+ try:
+ yield self._select_best(appobjects, *args, **kwargs)
+ except NoSelectableObject:
+ continue
+
+This will yield additional WARNINGs, like this::
+
+ 2009-01-09 16:43:52 - (cubicweb.selectors) WARNING: selector one_line_rset returned 0 for <class 'cubicweb.web.views.basecomponents.WFHistoryVComponent'>
+
+For views, you can put this context in `cubicweb/web/views/basecontrollers.py` in
+the `ViewController`:
+
+.. sourcecode:: python
+
+ def _select_view_and_rset(self, rset):
+ ...
+ try:
+ from logilab.common.registry import traced_selection
+ with traced_selection():
+ view = self._cw.vreg['views'].select(vid, req, rset=rset)
+ except ObjectNotFound:
+ self.warning("the view %s could not be found", vid)
+ req.set_message(req._("The view %s could not be found") % vid)
+ vid = vid_from_rset(req, rset, self._cw.vreg.schema)
+ view = self._cw.vreg['views'].select(vid, req, rset=rset)
+ ...
+
+I get "database is locked" when executing tests
+-----------------------------------------------
+
+If you have "database is locked" as error when you are executing security tests,
+it is usually because commit or rollback are missing before login() calls.
+
+You can also use a context manager, to avoid such errors, as described
+here: :ref:`securitytest`.
+
+
+What are hooks used for ?
+-------------------------
+
+Hooks are executed around (actually before or after) events. The most common
+events are data creation, update and deletion. They permit additional constraint
+checking (those not expressible at the schema level), pre and post computations
+depending on data movements.
+
+As such, they are a vital part of the framework.
+
+Other kinds of hooks, called Operations, are available
+for execution just before commit.
+
+For more information, read :ref:`hooks` section.
+
+
+Configuration
+`````````````
+
+How to configure a LDAP source ?
+--------------------------------
+
+See :ref:`LDAP`.
+
+How to import LDAP users in |cubicweb| ?
+----------------------------------------
+
+ Here is a useful script which enables you to import LDAP users
+ into your *CubicWeb* instance by running the following:
+
+.. sourcecode:: python
+
+ import os
+ import pwd
+ import sys
+
+ from logilab.database import get_connection
+
+ def getlogin():
+ """avoid using os.getlogin() because of strange tty/stdin problems
+ (man 3 getlogin)
+ Another solution would be to use $LOGNAME, $USER or $USERNAME
+ """
+ return pwd.getpwuid(os.getuid())[0]
+
+
+ try:
+ database = sys.argv[1]
+ except IndexError:
+ print 'USAGE: python ldap2system.py <database>'
+ sys.exit(1)
+
+ if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'):
+ cnx = get_connection(user=getlogin(), database=database)
+ cursor = cnx.cursor()
+
+ insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, '
+ ' firstname, surname, last_login_time, upassword) '
+ "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, "
+ "%(surname)s, %(mtime)s, './fqEz5LeZnT6');")
+ update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;"
+ cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'")
+ for eid, type, source, extid, mtime in cursor.fetchall():
+ if type != 'CWUser':
+ print "don't know what to do with entity type", type
+ continue
+ if source != 'ldapuser':
+ print "don't know what to do with source type", source
+ continue
+ ldapinfos = dict(x.strip().split('=') for x in extid.split(','))
+ login = ldapinfos['uid']
+ firstname = ldapinfos['uid'][0].upper()
+ surname = ldapinfos['uid'][1:].capitalize()
+ if login != 'jcuissinat':
+ args = dict(eid=eid, type=type, source=source, login=login,
+ firstname=firstname, surname=surname, mtime=mtime)
+ print args
+ cursor.execute(insert, args)
+ cursor.execute(update, args)
+
+ cnx.commit()
+ cnx.close()
+
+
+Security
+````````
+
+How to reset the password for user joe ?
+----------------------------------------
+
+If you want to reset the admin password for ``myinstance``, do::
+
+ $ cubicweb-ctl reset-admin-pwd myinstance
+
+You need to generate a new encrypted password::
+
+ $ python
+ >>> from cubicweb.server.utils import crypt_password
+ >>> crypt_password('joepass')
+ 'qHO8282QN5Utg'
+ >>>
+
+and paste it in the database::
+
+ $ psql mydb
+ mydb=> update cw_cwuser set cw_upassword='qHO8282QN5Utg' where cw_login='joe';
+ UPDATE 1
+
+if you're running over SQL Server, you need to use the CONVERT
+function to convert the string to varbinary(255). The SQL query is
+therefore::
+
+ update cw_cwuser set cw_upassword=CONVERT(varbinary(255), 'qHO8282QN5Utg') where cw_login='joe';
+
+Be careful, the encryption algorithm is different on Windows and on
+Unix. You cannot therefore use a hash generated on Unix to fill in a
+Windows database, nor the other way round.
+
+
+You can prefer use a migration script similar to this shell invocation instead::
+
+ $ cubicweb-ctl shell <instance>
+ >>> from cubicweb import Binary
+ >>> from cubicweb.server.utils import crypt_password
+ >>> crypted = crypt_password('joepass')
+ >>> rset = rql('Any U WHERE U is CWUser, U login "joe"')
+ >>> joe = rset.get_entity(0,0)
+ >>> joe.cw_set(upassword=Binary(crypted))
+
+Please, refer to the script example is provided in the `misc/examples/chpasswd.py` file.
+
+The more experimented people would use RQL request directly::
+
+ >>> rql('SET X upassword %(a)s WHERE X is CWUser, X login "joe"',
+ ... {'a': crypted})
+
+I've just created a user in a group and it doesn't work !
+---------------------------------------------------------
+
+You are probably getting errors such as ::
+
+ remove {'PR': 'Project', 'C': 'CWUser'} from solutions since your_user has no read access to cost
+
+This is because you have to put your user in the "users" group. The user has to
+be in both groups.
+
+How is security implemented ?
+------------------------------
+
+The basis for security is a mapping from operations to groups or
+arbitrary RQL expressions. These mappings are scoped to entities and
+relations.
+
+This is an example for an Entity Type definition:
+
+.. sourcecode:: python
+
+ class Version(EntityType):
+ """a version is defining the content of a particular project's
+ release"""
+ # definition of attributes is voluntarily missing
+ __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'),)}
+
+The above means that permission to read a Version is granted to any
+user that is part of one of the groups 'managers', 'users', 'guests'.
+The 'add' permission is granted to users in group 'managers' or
+'logilab' or to users in group G, if G is linked by a permission
+entity named "add_version" to the version's project.
+
+An example for a Relation Definition (RelationType both defines a
+relation type and implicitly one relation definition, on which the
+permissions actually apply):
+
+.. sourcecode:: python
+
+ class version_of(RelationType):
+ """link a version to its project. A version is necessarily linked
+ to one and only one project. """
+ # some lines voluntarily missing
+ __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'),) }
+
+The main difference lies in the basic available operations (there is
+no 'update' operation) and the usage of an RRQLExpression (rql
+expression for a relation) instead of an ERQLExpression (rql
+expression for an entity).
+
+You can find additional information in the section :ref:`securitymodel`.
+
+Is it possible to bypass security from the UI (web front) part ?
+----------------------------------------------------------------
+
+No. Only Hooks/Operations can do that.
+
+Can PostgreSQL and CubicWeb authentication work with kerberos ?
+----------------------------------------------------------------
+
+If you have PostgreSQL set up to accept kerberos authentication, you can set
+the db-host, db-name and db-user parameters in the `sources` configuration
+file while leaving the password blank. It should be enough for your
+instance to connect to postgresql with a kerberos ticket.
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,19 @@
+.. -*- coding: utf-8 -*-
+
+.. _Part4:
+
+----------
+Appendixes
+----------
+
+The following chapters are reference material.
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ faq
+ rql/index
+ mercurial
+ depends
+ docstrings-conventions
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/mercurial.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,131 @@
+.. -*- coding: utf-8 -*-
+
+.. _MercurialPresentation:
+
+Introducing Mercurial
+=====================
+
+Introduction
+````````````
+Mercurial_ manages a distributed repository containing revisions
+trees (each revision indicates the changes required to obtain the
+next, and so on). Locally, we have a repository containing revisions
+tree, and a working directory. It is possible
+to put in its working directory, one of the versions of its local repository,
+modify and then push it in its repository.
+It is also possible to get revisions from another repository or to export
+its own revisions from the local repository to another repository.
+
+.. _Mercurial: http://www.selenic.com/mercurial/
+
+In contrast to CVS/Subversion, we usually create a repository per
+project to manage.
+
+In a collaborative development, we usually create a central repository
+accessible to all developers of the project. These central repository is used
+as a reference. According to their needs, everyone can have a local repository,
+that they will have to synchronize with the central repository from time to time.
+
+
+Major commands
+``````````````
+* Create a local repository::
+
+ hg clone ssh://myhost//home/src/repo
+
+* See the contents of the local repository (graphical tool in Qt)::
+
+ hgview
+
+* Add a sub-directory or file in the current directory::
+
+ hg add subdir
+
+* Move to the working directory a specific revision (or last
+ revision) from the local repository::
+
+ hg update [identifier-revision]
+ hg up [identifier-revision]
+
+* Get in its local repository, the tree of revisions contained in a
+ remote repository (this does not change the local directory)::
+
+ hg pull ssh://myhost//home/src/repo
+ hg pull -u ssh://myhost//home/src/repo # equivalent to pull + update
+
+* See what are the heads of branches of the local repository if a `pull`
+ returned a new branch::
+
+ hg heads
+
+* Submit the working directory in the local repository (and create a new
+ revision)::
+
+ hg commit
+ hg ci
+
+* Merge with the mother revision of local directory, another revision from
+ the local respository (the new revision will be then two mothers
+ revisions)::
+
+ hg merge identifier-revision
+
+* Export to a remote repository, the tree of revisions in its content
+ local respository (this does not change the local directory)::
+
+ hg push ssh://myhost//home/src/repo
+
+* See what local revisions are not in another repository::
+
+ hg outgoing ssh://myhost//home/src/repo
+
+* See what are the revisions of a repository not found locally::
+
+ hg incoming ssh://myhost//home/src/repo
+
+* See what is the revision of the local repository which has been taken out
+ from the working directory and amended::
+
+ hg parent
+
+* See the differences between the working directory and the mother revision
+ of the local repository, possibly to submit them in the local repository::
+
+ hg diff
+ hg commit-tool
+ hg ct
+
+
+Best Practices
+``````````````
+* Remember to `hg pull -u` regularly, and particularly before
+ a `hg commit`.
+
+* Remember to `hg push` when your repository contains a version
+ relatively stable of your changes.
+
+* If a `hg pull -u` created a new branch head:
+
+ 1. find its identifier with `hg head`
+ 2. merge with `hg merge`
+ 3. `hg ci`
+ 4. `hg push`
+
+Installation of the guestrepo extension
+```````````````````````````````````````
+
+Set up the guestrepo extension by getting a copy of the sources
+from https://bitbucket.org/selinc/guestrepo and adding the following
+lines to your ``~/.hgrc``: ::
+
+ [extensions]
+ guestrepo=/path/to/guestrepo/guestrepo
+
+
+More information
+````````````````
+
+For more information about Mercurial, please refer to the Mercurial project online documentation_.
+
+.. _documentation: http://www.selenic.com/mercurial/wiki/
+
Binary file doc/book/annexes/rql/Graph-ex.gif has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/rql/debugging.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,55 @@
+.. -*- coding: utf-8 -*-
+
+.. _DEBUGGING:
+
+Debugging RQL
+-------------
+
+Available levels
+~~~~~~~~~~~~~~~~
+
+Server debugging flags. They may be combined using binary operators.
+
+.. autodata:: cubicweb.server.DBG_NONE
+.. autodata:: cubicweb.server.DBG_RQL
+.. autodata:: cubicweb.server.DBG_SQL
+.. autodata:: cubicweb.server.DBG_REPO
+.. autodata:: cubicweb.server.DBG_MS
+.. autodata:: cubicweb.server.DBG_HOOKS
+.. autodata:: cubicweb.server.DBG_OPS
+.. autodata:: cubicweb.server.DBG_MORE
+.. autodata:: cubicweb.server.DBG_ALL
+
+
+Enable verbose output
+~~~~~~~~~~~~~~~~~~~~~
+
+To debug your RQL statements, it can be useful to enable a verbose output:
+
+.. sourcecode:: python
+
+ from cubicweb import server
+ server.set_debug(server.DBG_RQL|server.DBG_SQL|server.DBG_ALL)
+
+.. autofunction:: cubicweb.server.set_debug
+
+Another example showing how to debug hooks at a specific code site:
+
+.. sourcecode:: python
+
+ from cubicweb.server import debugged, DBG_HOOKS
+ with debugged(DBG_HOOKS):
+ person.cw_set(works_for=company)
+
+
+Detect largest RQL queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+See `Profiling and performance` chapter (see :ref:`PROFILING`).
+
+
+API
+~~~
+
+.. autoclass:: cubicweb.server.debugged
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/rql/implementation.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,159 @@
+
+
+Implementation
+--------------
+
+BNF grammar
+~~~~~~~~~~~
+
+The terminal elements are in capital letters, non-terminal in lowercase.
+The value of the terminal elements (between quotes) is a Python regular
+expression.
+::
+
+ statement ::= (select | delete | insert | update) ';'
+
+
+ # select specific rules
+ select ::= 'DISTINCT'? E_TYPE selected_terms restriction? group? sort?
+
+ selected_terms ::= expression ( ',' expression)*
+
+ group ::= 'GROUPBY' VARIABLE ( ',' VARIABLE)*
+
+ sort ::= 'ORDERBY' sort_term ( ',' sort_term)*
+
+ sort_term ::= VARIABLE sort_method =?
+
+ sort_method ::= 'ASC' | 'DESC'
+
+
+ # delete specific rules
+ delete ::= 'DELETE' (variables_declaration | relations_declaration) restriction?
+
+
+ # insert specific rules
+ insert ::= 'INSERT' variables_declaration ( ':' relations_declaration)? restriction?
+
+
+ # update specific rules
+ update ::= 'SET' relations_declaration restriction
+
+
+ # common rules
+ variables_declaration ::= E_TYPE VARIABLE (',' E_TYPE VARIABLE)*
+
+ relations_declaration ::= simple_relation (',' simple_relation)*
+
+ simple_relation ::= VARIABLE R_TYPE expression
+
+ restriction ::= 'WHERE' relations
+
+ relations ::= relation (LOGIC_OP relation)*
+ | '(' relations')'
+
+ relation ::= 'NOT'? VARIABLE R_TYPE COMP_OP? expression
+ | 'NOT'? R_TYPE VARIABLE 'IN' '(' expression (',' expression)* ')'
+
+ expression ::= var_or_func_or_const (MATH_OP var_or_func_or_const) *
+ | '(' expression ')'
+
+ var_or_func_or_const ::= VARIABLE | function | constant
+
+ function ::= FUNCTION '(' expression ( ',' expression) * ')'
+
+ constant ::= KEYWORD | STRING | FLOAT | INT
+
+ # tokens
+ LOGIC_OP ::= ',' | 'OR' | 'AND'
+ MATH_OP ::= '+' | '-' | '/' | '*'
+ COMP_OP ::= '>' | '>=' | '=' | '<=' | '<' | '~=' | 'LIKE'
+
+ FUNCTION ::= 'MIN' | 'MAX' | 'SUM' | 'AVG' | 'COUNT' | 'UPPER' | 'LOWER'
+
+ VARIABLE ::= '[A-Z][A-Z0-9]*'
+ E_TYPE ::= '[A-Z]\w*'
+ R_TYPE ::= '[a-z_]+'
+
+ KEYWORD ::= 'TRUE' | 'FALSE' | 'NULL' | 'TODAY' | 'NOW'
+ STRING ::= "'([^'\]|\\.)*'" |'"([^\"]|\\.)*\"'
+ FLOAT ::= '\d+\.\d*'
+ INT ::= '\d+'
+
+
+Internal representation (syntactic tree)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The tree research does not contain the selected variables
+(e.g. there is only what follows "WHERE").
+
+The insertion tree does not contain the variables inserted or relations
+defined on these variables (e.g. there is only what follows "WHERE").
+
+The removal tree does not contain the deleted variables and relations
+(e.g. there is only what follows the "WHERE").
+
+The update tree does not contain the variables and relations updated
+(e.g. there is only what follows the "WHERE").
+
+::
+
+ Select ((Relationship | And | Or)?, Group?, Sort?)
+ Insert (Relations | And | Or)?
+ Delete (Relationship | And | Or)?
+ Update (Relations | And | Or)?
+
+ And ((Relationship | And | Or), (Relationship | And | Or))
+ Or ((Relationship | And | Or), (Relationship | And | Or))
+
+ Relationship ((VariableRef, Comparison))
+
+ Comparison ((Function | MathExpression | Keyword | Constant | VariableRef) +)
+
+ Function (())
+ MathExpression ((MathExpression | Keyword | Constant | VariableRef), (MathExpression | Keyword | Constant | VariableRef))
+
+ Group (VariableRef +)
+ Sort (SortTerm +)
+ SortTerm (VariableRef +)
+
+ VariableRef ()
+ Variable ()
+ Keyword ()
+ Constant ()
+
+
+Known limitations
+~~~~~~~~~~~~~~~~~
+
+- The current implementation does not support linking two relations of type 'is'
+ with an OR. I do not think that the negation is supported on this type of
+ relation (XXX to be confirmed).
+
+- missing COALESCE and certainly other things...
+
+- writing an rql query requires knowledge of the used schema (with real relation
+ names and entities, not those viewed in the user interface). On the other
+ hand, we cannot really bypass that, and it is the job of a user interface to
+ hide the RQL.
+
+
+Topics
+~~~~~~
+
+It would be convenient to express the schema matching
+relations (non-recursive rules)::
+
+ Document class Type <-> Document occurence_of Fiche class Type
+ Sheet class Type <-> Form collection Collection class Type
+
+Therefore 1. becomes::
+
+ Document X where
+ X class C, C name 'Cartoon'
+ X owned_by U, U login 'syt'
+ X available true
+
+I'm not sure that we should handle this at RQL level ...
+
+There should also be a special relation 'anonymous'.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/rql/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,14 @@
+.. _RQLChapter:
+
+Relation Query Language (RQL)
+=============================
+
+This chapter describes the Relation Query Language syntax and its implementation in CubicWeb.
+
+.. toctree::
+ :maxdepth: 2
+
+ intro
+ language
+ debugging
+ implementation
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/rql/intro.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,162 @@
+
+.. _rql_intro:
+
+Introduction
+------------
+
+Goals of RQL
+~~~~~~~~~~~~
+
+The goal is to have a semantic language in order to:
+
+- query relations in a clear syntax
+- empowers access to data repository manipulation
+- making attributes/relations browsing easy
+
+As such, attributes will be regarded as cases of special relations (in
+terms of usage, the user should see no syntactic difference between an
+attribute and a relation).
+
+Comparison with existing languages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+SQL
+```
+
+RQL may remind of SQL but works at a higher abstraction level (the *CubicWeb*
+framework generates SQL from RQL to fetch data from relation databases). RQL is
+focused on browsing relations. The user needs only to know about the *CubicWeb*
+data model he is querying, but not about the underlying SQL model.
+
+Sparql
+``````
+
+The query language most similar to RQL is SPARQL_, defined by the W3C to serve
+for the semantic web.
+
+Versa
+`````
+
+We should look in more detail, but here are already some ideas for the moment
+... Versa_ is the language most similar to what we wanted to do, but the model
+underlying data being RDF, there are some things such as namespaces or
+handling of the RDF types which does not interest us. On the functionality
+level, Versa_ is very comprehensive including through many functions of
+conversion and basic types manipulation, which we may want to look at one time
+or another. Finally, the syntax is a little esoteric.
+
+Datalog
+```````
+
+Datalog_ is a prolog derived query langage which applies to relational
+databases. It is more expressive than RQL in that it accepts either
+extensional_ and intensional_ predicates (or relations). As of now,
+RQL only deals with intensional relations.
+
+The different types of queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Search (`Any`)
+ Extract entities and attributes of entities.
+
+Insert entities (`INSERT`)
+ Insert new entities or relations in the database.
+ It can also directly create relationships for the newly created entities.
+
+Update entities, create relations (`SET`)
+ Update existing entities in the database,
+ or create relations between existing entities.
+
+Delete entities or relationship (`DELETE`)
+ Remove entities or relations existing in the database.
+
+
+RQL relation expressions
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+RQL expressions apply to a live database defined by a
+:ref:`datamodel_definition`. Apart from the main type, or head, of the
+expression (search, insert, etc.) the most common constituent of an
+RQL expression is a (set of) relation expression(s).
+
+An RQL relation expression contains three components:
+
+* the subject, which is an entity type
+* the predicate, which is a relation definition (an arc of the schema)
+* the object, which is either an attribute or a relation to another entity
+
+.. image:: Graph-ex.gif
+ :alt: <subject> <predicate> <object>
+ :align: center
+
+.. warning::
+
+ A relation is always expressed in the order: ``subject``,
+ ``predicate``, ``object``.
+
+ It is important to determine if the entity type is subject or object
+ to construct a valid expression. Inverting the subject/object is an
+ error since the relation cannot be found in the schema.
+
+ If one does not have access to the code, one can find the order by
+ looking at the schema image in manager views (the subject is located
+ at the beginning of the arrow).
+
+An example of two related relation expressions::
+
+ P works_for C, P name N
+
+RQL variables represent typed entities. The type of entities is
+either automatically inferred (by looking at the possible relation
+definitions, see :ref:`RelationDefinition`) or explicitely constrained
+using the ``is`` meta relation.
+
+In the example above, we barely need to look at the schema. If
+variable names (in the RQL expression) and relation type names (in the
+schema) are expresssively designed, the human reader can infer as much
+as the |cubicweb| querier.
+
+The ``P`` variable is used twice but it always represent the same set
+of entities. Hence ``P works_for C`` and ``P name N`` must be
+compatible in the sense that all the Ps (which *can* refer to
+different entity types) must accept the ``works_for`` and ``name``
+relation types. This does restrict the set of possible values of P.
+
+Adding another relation expression::
+
+ P works_for C, P name N, C name "logilab"
+
+This further restricts the possible values of P through an indirect
+constraint on the possible values of ``C``. The RQL-level unification_
+happening there is translated to one (or several) joins_ at the
+database level.
+
+.. note::
+
+ In |cubicweb|, the term `relation` is often found without ambiguity
+ instead of `predicate`. This predicate is also known as the
+ `property` of the triple in `RDF concepts`_
+
+
+RQL Operators
+~~~~~~~~~~~~~
+
+An RQL expression's head can be completed using various operators such
+as ``ORDERBY``, ``GROUPBY``, ``HAVING``, ``LIMIT`` etc.
+
+RQL relation expressions can be grouped with ``UNION`` or
+``WITH``. Predicate oriented keywords such as ``EXISTS``, ``OR``,
+``NOT`` are available.
+
+The complete zoo of RQL operators is described extensively in the
+following chapter (:ref:`RQL`).
+
+.. _RDF concepts: http://www.w3.org/TR/rdf-concepts/
+.. _Versa: http://wiki.xml3k.org/Versa
+.. _SPARQL: http://www.w3.org/TR/rdf-sparql-query/
+.. _unification: http://en.wikipedia.org/wiki/Unification_(computing)
+.. _joins: http://en.wikipedia.org/wiki/Join_(SQL)
+.. _Datalog: http://en.wikipedia.org/wiki/Datalog
+.. _intensional: http://en.wikipedia.org/wiki/Intensional_definition
+.. _extensional: http://en.wikipedia.org/wiki/Extension_(predicate_logic)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/annexes/rql/language.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,804 @@
+.. -*- coding: utf-8 -*-
+
+.. _RQL:
+
+RQL syntax
+----------
+
+.. _RQLKeywords:
+
+Reserved keywords
+~~~~~~~~~~~~~~~~~
+
+::
+
+ AND, ASC, BEING, DELETE, DESC, DISTINCT, EXISTS, FALSE, GROUPBY,
+ HAVING, ILIKE, INSERT, LIKE, LIMIT, NOT, NOW, NULL, OFFSET,
+ OR, ORDERBY, SET, TODAY, TRUE, UNION, WHERE, WITH
+
+The keywords are not case sensitive. You should not use them when defining your
+schema, or as RQL variable names.
+
+
+.. _RQLCase:
+
+Case
+~~~~
+
+* Variables should be all upper-cased.
+
+* Relation should be all lower-cased and match exactly names of relations defined
+ in the schema.
+
+* Entity types should start with an upper cased letter and be followed by at least
+ a lower cased latter.
+
+
+.. _RQLVariables:
+
+Variables and typing
+~~~~~~~~~~~~~~~~~~~~
+
+Entities and values to browse and/or select are represented in the query by
+*variables* that must be written in capital letters.
+
+With RQL, we do not distinguish between entities and attributes. The value of an
+attribute is considered as an entity of a particular type (see below), linked to
+one (real) entity by a relation called the name of the attribute, where the
+entity is the subject and the attribute the object.
+
+The possible type(s) for each variable is derived from the schema according to
+the constraints expressed above and thanks to the relations between each
+variable.
+
+We can restrict the possible types for a variable using the special relation
+**is** in the restrictions.
+
+
+.. _VirtualRelations:
+
+Virtual relations
+~~~~~~~~~~~~~~~~~
+
+Those relations may only be used in RQL query but are not actual attributes of
+your entities.
+
+* `has_text`: relation to use to query the full text index (only for entities
+ having fulltextindexed attributes).
+
+* `identity`: relation to use to tell that a RQL variable is the same as another
+ when you've to use two different variables for querying purpose. On the
+ opposite it's also useful together with the ``NOT`` operator to tell that two
+ variables should not identify the same entity
+
+
+.. _RQLLiterals:
+
+Literal expressions
+~~~~~~~~~~~~~~~~~~~
+
+Bases types supported by RQL are those supported by yams schema. Literal values
+are expressed as explained below:
+
+* string should be between double or single quotes. If the value contains a
+ quote, it should be preceded by a backslash '\\'
+
+* floats separator is dot '.'
+
+* boolean values are ``TRUE`` and ``FALSE`` keywords
+
+* date and time should be expressed as a string with ISO notation : YYYY/MM/DD
+ [hh:mm], or using keywords ``TODAY`` and ``NOW``
+
+You may also use the ``NULL`` keyword, meaning 'unspecified'.
+
+
+.. _RQLOperators:
+
+Operators
+~~~~~~~~~
+
+.. _RQLLogicalOperators:
+
+Logical operators
+`````````````````
+::
+
+ AND, OR, NOT, ','
+
+',' is equivalent to 'AND' but with the smallest among the priority of logical
+operators (see :ref:`RQLOperatorsPriority`).
+
+.. _RQLMathematicalOperators:
+
+Mathematical operators
+``````````````````````
+
++----------+---------------------+-----------+--------+
+| Operator | Description | Example | Result |
++==========+=====================+===========+========+
+| `+` | addition | 2 + 3 | 5 |
++----------+---------------------+-----------+--------+
+| `-` | subtraction | 2 - 3 | -1 |
++----------+---------------------+-----------+--------+
+| `*` | multiplication | 2 * 3 | 6 |
++----------+---------------------+-----------+--------+
+| / | division | 4 / 2 | 2 |
++----------+---------------------+-----------+--------+
+| % | modulo (remainder) | 5 % 4 | 1 |
++----------+---------------------+-----------+--------+
+| ^ | exponentiation | 2.0 ^ 3.0 | 8 |
++----------+---------------------+-----------+--------+
+| & | bitwise AND | 91 & 15 | 11 |
++----------+---------------------+-----------+--------+
+| `|` | bitwise OR | 32 | 3 | 35 |
++----------+---------------------+-----------+--------+
+| # | bitwise XOR | 17 # 5 | 20 |
++----------+---------------------+-----------+--------+
+| ~ | bitwise NOT | ~1 | -2 |
++----------+---------------------+-----------+--------+
+| << | bitwise shift left | 1 << 4 | 16 |
++----------+---------------------+-----------+--------+
+| >> | bitwise shift right | 8 >> 2 | 2 |
++----------+---------------------+-----------+--------+
+
+
+Notice integer division truncates results depending on the backend behaviour. For
+instance, postgresql does.
+
+
+.. _RQLComparisonOperators:
+
+Comparison operators
+````````````````````
+ ::
+
+ =, !=, <, <=, >=, >, IN
+
+
+The syntax to use comparison operators is:
+
+ `VARIABLE attribute <operator> VALUE`
+
+The `=` operator is the default operator and can be omitted, i.e. :
+
+ `VARIABLE attribute = VALUE`
+
+is equivalent to
+
+ `VARIABLE attribute VALUE`
+
+
+The operator `IN` provides a list of possible values:
+
+.. sourcecode:: sql
+
+ Any X WHERE X name IN ('chauvat', 'fayolle', 'di mascio', 'thenault')
+
+
+.. _RQLStringOperators:
+
+String operators
+````````````````
+::
+
+ LIKE, ILIKE, ~=, REGEXP
+
+The ``LIKE`` string operator can be used with the special character `%` in
+a string as wild-card:
+
+.. sourcecode:: sql
+
+ -- match every entity whose name starts with 'Th'
+ Any X WHERE X name ~= 'Th%'
+ -- match every entity whose name endswith 'lt'
+ Any X WHERE X name LIKE '%lt'
+ -- match every entity whose name contains a 'l' and a 't'
+ Any X WHERE X name LIKE '%l%t%'
+
+``ILIKE`` is the case insensitive version of ``LIKE``. It's not
+available on all backend (e.g. sqlite doesn't support it). If not available for
+your backend, ``ILIKE`` will behave like ``LIKE``.
+
+`~=` is a shortcut version of ``ILIKE``, or of ``LIKE`` when the
+former is not available on the back-end.
+
+
+The ``REGEXP`` is an alternative to ``LIKE`` that supports POSIX
+regular expressions:
+
+.. sourcecode:: sql
+
+ -- match entities whose title starts with a digit
+ Any X WHERE X title REGEXP "^[0-9].*"
+
+
+The underlying SQL operator used is back-end-dependent :
+
+- the ``~`` operator is used for postgresql,
+- the ``REGEXP`` operator for mysql and sqlite.
+
+Other back-ends are not supported yet.
+
+
+.. _RQLOperatorsPriority:
+
+Operators priority
+``````````````````
+
+#. `(`, `)`
+#. `^`, `<<`, `>>`
+#. `*`, `/`, `%`, `&`
+#. `+`, `-`, `|`, `#`
+#. `NOT`
+#. `AND`
+#. `OR`
+#. `,`
+
+
+.. _RQLSearchQuery:
+
+Search Query
+~~~~~~~~~~~~
+
+Simplified grammar of search query: ::
+
+ [ `DISTINCT`] `Any` V1 (, V2) \*
+ [ `GROUPBY` V1 (, V2) \*] [ `ORDERBY` <orderterms>]
+ [ `LIMIT` <value>] [ `OFFSET` <value>]
+ [ `WHERE` <triplet restrictions>]
+ [ `WITH` V1 (, V2)\* BEING (<query>)]
+ [ `HAVING` <other restrictions>]
+ [ `UNION` <query>]
+
+Selection
+`````````
+
+The fist occuring clause is the selection of terms that should be in the result
+set. Terms may be variable, literals, function calls, arithmetic, etc. and each
+term is separated by a comma.
+
+There will be as much column in the result set as term in this clause, respecting
+order.
+
+Syntax for function call is somewhat intuitive, for instance:
+
+.. sourcecode:: sql
+
+ Any UPPER(N) WHERE P firstname N
+
+
+Grouping and aggregating
+````````````````````````
+
+The ``GROUPBY`` keyword is followed by a list of terms on which results
+should be grouped. They are usually used with aggregate functions, responsible to
+aggregate values for each group (see :ref:`RQLAggregateFunctions`).
+
+For grouped queries, all selected variables must be either aggregated (i.e. used
+by an aggregate function) or grouped (i.e. listed in the ``GROUPBY``
+clause).
+
+
+Sorting
+```````
+
+The ``ORDERBY`` keyword if followed by the definition of the selection
+order: variable or column number followed by sorting method (``ASC``,
+``DESC``), ``ASC`` being the default. If the sorting method is not
+specified, then the sorting is ascendant (`ASC`).
+
+
+Pagination
+``````````
+
+The ``LIMIT`` and ``OFFSET`` keywords may be respectively used to
+limit the number of results and to tell from which result line to start (for
+instance, use `LIMIT 20` to get the first 20 results, then `LIMIT 20 OFFSET 20`
+to get the next 20.
+
+
+Restrictions
+````````````
+
+The ``WHERE`` keyword introduce one of the "main" part of the query, where
+you "define" variables and add some restrictions telling what you're interested
+in.
+
+It's a list of triplets "subject relation object", e.g. `V1 relation
+(V2 | <static value>)`. Triplets are separated using :ref:`RQLLogicalOperators`.
+
+.. note::
+
+ About the negation operator (``NOT``):
+
+ * ``NOT X relation Y`` is equivalent to ``NOT EXISTS(X relation Y)``
+
+ * ``Any X WHERE NOT X owned_by U`` means "entities that have no relation
+ ``owned_by``".
+
+ * ``Any X WHERE NOT X owned_by U, U login "syt"`` means "the entity have no
+ relation ``owned_by`` with the user syt". They may have a relation "owned_by"
+ with another user.
+
+In this clause, you can also use ``EXISTS`` when you want to know if some
+expression is true and do not need the complete set of elements that make it
+true. Testing for existence is much faster than fetching the complete set of
+results, especially when you think about using ``OR`` against several expressions. For instance
+if you want to retrieve versions which are in state "ready" or tagged by
+"priority", you should write :
+
+.. sourcecode:: sql
+
+ Any X ORDERBY PN,N
+ WHERE X num N, X version_of P, P name PN,
+ EXISTS(X in_state S, S name "ready")
+ OR EXISTS(T tags X, T name "priority")
+
+not
+
+.. sourcecode:: sql
+
+ Any X ORDERBY PN,N
+ WHERE X num N, X version_of P, P name PN,
+ (X in_state S, S name "ready")
+ OR (T tags X, T name "priority")
+
+Both queries aren't at all equivalent :
+
+* the former will retrieve all versions, then check for each one which are in the
+ matching state of or tagged by the expected tag,
+
+* the later will retrieve all versions, state and tags (cartesian product!),
+ compute join and then exclude each row which are in the matching state or
+ tagged by the expected tag. This implies that you won't get any result if the
+ in_state or tag tables are empty (ie there is no such relation in the
+ application). This is usually NOT what you want.
+
+Another common case where you may want to use ``EXISTS`` is when you
+find yourself using ``DISTINCT`` at the beginning of your query to
+remove duplicate results. The typical case is when you have a
+multivalued relation such as Version version_of Project and you want
+to retrieve projects which have a version:
+
+.. sourcecode:: sql
+
+ Any P WHERE V version_of P
+
+will return each project number of versions times. So you may be
+tempted to use:
+
+.. sourcecode:: sql
+
+ DISTINCT ANY P WHERE V version_of P
+
+This will work, but is not efficient, as it will use the ``SELECT
+DISTINCT`` SQL predicate, which needs to retrieve all projects, then
+sort them and discard duplicates, which can have a very high cost for
+large result sets. So the best way to write this is:
+
+.. sourcecode:: sql
+
+ ANY P WHERE EXISTS V version_of P
+
+
+You can also use the question mark (`?`) to mark optional relations. This allows
+you to select entities related **or not** to another. It is a similar concept
+to `Left outer join`_:
+
+ the result of a left outer join (or simply left join) for table A and B
+ always contains all records of the "left" table (A), even if the
+ join-condition does not find any matching record in the "right" table (B).
+
+You must use the `?` behind a variable to specify that the relation to
+that variable is optional. For instance:
+
+- Bugs of a project attached or not to a version
+
+ .. sourcecode:: sql
+
+ Any X, V WHERE X concerns P, P eid 42, X corrected_in V?
+
+ You will get a result set containing all the project's tickets, with either the
+ version in which it's fixed or None for tickets not related to a version.
+
+
+- All cards and the project they document if any
+
+ .. sourcecode:: sql
+
+ Any C, P WHERE C is Card, P? documented_by C
+
+Notice you may also use outer join:
+
+- on the RHS of attribute relation, e.g.
+
+ .. sourcecode:: sql
+
+ Any X WHERE X ref XR, Y name XR?
+
+ so that Y is outer joined on X by ref/name attributes comparison
+
+
+- on any side of an ``HAVING`` expression, e.g.
+
+ .. sourcecode:: sql
+
+ Any X WHERE X creation_date XC, Y creation_date YC
+ HAVING YEAR(XC)=YEAR(YC)?
+
+ so that Y is outer joined on X by comparison of the year extracted from their
+ creation date.
+
+ .. sourcecode:: sql
+
+ Any X WHERE X creation_date XC, Y creation_date YC
+ HAVING YEAR(XC)?=YEAR(YC)
+
+ would outer join X on Y instead.
+
+
+Having restrictions
+```````````````````
+
+The ``HAVING`` clause, as in SQL, may be used to restrict a query
+according to value returned by an aggregate function, e.g.
+
+.. sourcecode:: sql
+
+ Any X GROUPBY X WHERE X relation Y HAVING COUNT(Y) > 10
+
+It may however be used for something else: In the ``WHERE`` clause, we are
+limited to triplet expressions, so some things may not be expressed there. Let's
+take an example : if you want to get people whose upper-cased first name equals to
+another person upper-cased first name. There is no proper way to express this
+using triplet, so you should use something like:
+
+.. sourcecode:: sql
+
+ Any X WHERE X firstname XFN, Y firstname YFN, NOT X identity Y HAVING UPPER(XFN) = UPPER(YFN)
+
+Another example: imagine you want person born in 2000:
+
+.. sourcecode:: sql
+
+ Any X WHERE X birthday XB HAVING YEAR(XB) = 2000
+
+Notice that while we would like this to work without the HAVING clause, this
+can't be currently be done because it introduces an ambiguity in RQL's grammar
+that can't be handled by Yapps_, the parser's generator we're using.
+
+
+Sub-queries
+```````````
+
+The ``WITH`` keyword introduce sub-queries clause. Each sub-query has the
+form:
+
+ V1(,V2) BEING (rql query)
+
+Variables at the left of the ``BEING`` keyword defines into which
+variables results from the sub-query will be mapped to into the outer query.
+Sub-queries are separated from each other using a comma.
+
+Let's say we want to retrieve for each project its number of versions and its
+number of tickets. Due to the nature of relational algebra behind the scene, this
+can't be achieved using a single query. You have to write something along the
+line of:
+
+.. sourcecode:: sql
+
+ Any X, VC, TC WHERE X identity XX
+ WITH X, VC BEING (Any X, COUNT(V) GROUPBY X WHERE V version_of X),
+ XX, TC BEING (Any X, COUNT(T) GROUPBY X WHERE T ticket_of X)
+
+Notice that we can't reuse a same variable name as alias for two different
+sub-queries, hence the usage of 'X' and 'XX' in this example, which are then
+unified using the special `identity` relation (see :ref:`VirtualRelations`).
+
+.. warning::
+
+ Sub-queries define a new variable scope, so even if a variable has the same name
+ in the outer query and in the sub-query, they technically **aren't** the same
+ variable. So:
+
+ .. sourcecode:: sql
+
+ Any W, REF WITH W, REF BEING
+ (Any W, REF WHERE W is Workcase, W ref REF,
+ W concerned_by D, D name "Logilab")
+
+ could be written:
+
+ .. sourcecode:: sql
+
+ Any W, REF WITH W, REF BEING
+ (Any W1, REF1 WHERE W1 is Workcase, W1 ref REF1,
+ W1 concerned_by D, D name "Logilab")
+
+ Also, when a variable is coming from a sub-query, you currently can't reference
+ its attribute or inlined relations in the outer query, you've to fetch them in
+ the sub-query. For instance, let's say we want to sort by project name in our
+ first example, we would have to write:
+
+ .. sourcecode:: sql
+
+
+ Any X, VC, TC ORDERBY XN WHERE X identity XX
+ WITH X, XN, VC BEING (Any X, COUNT(V) GROUPBY X,XN WHERE V version_of X, X name XN),
+ XX, TC BEING (Any X, COUNT(T) GROUPBY X WHERE T ticket_of X)
+
+ instead of:
+
+ .. sourcecode:: sql
+
+ Any X, VC, TC ORDERBY XN WHERE X identity XX, X name XN,
+ WITH X, XN, VC BEING (Any X, COUNT(V) GROUPBY X WHERE V version_of X),
+ XX, TC BEING (Any X, COUNT(T) GROUPBY X WHERE T ticket_of X)
+
+ which would result in a SQL execution error.
+
+
+Union
+`````
+
+You may get a result set containing the concatenation of several queries using
+the ``UNION``. The selection of each query should have the same number of
+columns.
+
+.. sourcecode:: sql
+
+ (Any X, XN WHERE X is Person, X surname XN) UNION (Any X,XN WHERE X is Company, X name XN)
+
+
+.. _RQLFunctions:
+
+Available functions
+~~~~~~~~~~~~~~~~~~~
+
+Below is the list of aggregate and transformation functions that are supported
+nativly by the framework. Notice that cubes may define additional functions.
+
+.. _RQLAggregateFunctions:
+
+Aggregate functions
+```````````````````
++------------------------+----------------------------------------------------------+
+| ``COUNT(Any)`` | return the number of rows |
++------------------------+----------------------------------------------------------+
+| ``MIN(Any)`` | return the minimum value |
++------------------------+----------------------------------------------------------+
+| ``MAX(Any)`` | return the maximum value |
++------------------------+----------------------------------------------------------+
+| ``AVG(Any)`` | return the average value |
++------------------------+----------------------------------------------------------+
+| ``SUM(Any)`` | return the sum of values |
++------------------------+----------------------------------------------------------+
+| ``COMMA_JOIN(String)`` | return each value separated by a comma (for string only) |
++------------------------+----------------------------------------------------------+
+
+All aggregate functions above take a single argument. Take care some aggregate
+functions (e.g. ``MAX``, ``MIN``) may return `None` if there is no
+result row.
+
+.. _RQLStringFunctions:
+
+String transformation functions
+```````````````````````````````
+
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``UPPER(String)`` | upper case the string |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``LOWER(String)`` | lower case the string |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``LENGTH(String)`` | return the length of the string |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``SUBSTRING(String, start, length)`` | extract from the string a string starting at given index and of |
+| | given length |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``LIMIT_SIZE(String, max size)`` | if the length of the string is greater than given max size, |
+| | strip it and add ellipsis ("..."). The resulting string will |
+| | hence have max size + 3 characters |
++-----------------------------------------------+-----------------------------------------------------------------+
+| ``TEXT_LIMIT_SIZE(String, format, max size)`` | similar to the above, but allow to specify the MIME type of the |
+| | text contained by the string. Supported formats are text/html, |
+| | text/xhtml and text/xml. All others will be considered as plain |
+| | text. For non plain text format, sgml tags will be first removed|
+| | before limiting the string. |
++-----------------------------------------------+-----------------------------------------------------------------+
+
+.. _RQLDateFunctions:
+
+Date extraction functions
+`````````````````````````
+
++----------------------+----------------------------------------+
+| ``YEAR(Date)`` | return the year of a date or datetime |
++----------------------+----------------------------------------+
+| ``MONTH(Date)`` | return the month of a date or datetime |
++----------------------+----------------------------------------+
+| ``DAY(Date)`` | return the day of a date or datetime |
++----------------------+----------------------------------------+
+| ``HOUR(Datetime)`` | return the hours of a datetime |
++----------------------+----------------------------------------+
+| ``MINUTE(Datetime)`` | return the minutes of a datetime |
++----------------------+----------------------------------------+
+| ``SECOND(Datetime)`` | return the seconds of a datetime |
++----------------------+----------------------------------------+
+| ``WEEKDAY(Date)`` | return the day of week of a date or |
+| | datetime. Sunday == 1, Saturday == 7. |
++----------------------+----------------------------------------+
+
+.. _RQLOtherFunctions:
+
+Other functions
+```````````````
++-------------------+--------------------------------------------------------------------+
+| ``ABS(num)`` | return the absolute value of a number |
++-------------------+--------------------------------------------------------------------+
+| ``RANDOM()`` | return a pseudo-random value from 0.0 to 1.0 |
++-------------------+--------------------------------------------------------------------+
+| ``FSPATH(X)`` | expect X to be an attribute whose value is stored in a |
+| | :class:`BFSStorage` and return its path on the file system |
++-------------------+--------------------------------------------------------------------+
+| ``FTIRANK(X)`` | expect X to be an entity used in a has_text relation, and return a |
+| | number corresponding to the rank order of each resulting entity |
++-------------------+--------------------------------------------------------------------+
+| ``CAST(Type, X)`` | expect X to be an attribute and return it casted into the given |
+| | final type |
++-------------------+--------------------------------------------------------------------+
+
+
+.. _RQLExamples:
+
+Examples
+~~~~~~~~
+
+- *Search for the object of identifier 53*
+
+ .. sourcecode:: sql
+
+ Any X WHERE X eid 53
+
+- *Search material such as comics, owned by syt and available*
+
+ .. sourcecode:: sql
+
+ Any X WHERE X is Document,
+ X occurence_of F, F class C, C name 'Comics',
+ X owned_by U, U login 'syt',
+ X available TRUE
+
+- *Looking for people working for eurocopter interested in training*
+
+ .. sourcecode:: sql
+
+ Any P WHERE P is Person, P work_for S, S name 'Eurocopter',
+ P interested_by T, T name 'training'
+
+- *Search note less than 10 days old written by jphc or ocy*
+
+ .. sourcecode:: sql
+
+ Any N WHERE N is Note, N written_on D, D day> (today -10),
+ N written_by P, P name 'jphc' or P name 'ocy'
+
+- *Looking for people interested in training or living in Paris*
+
+ .. sourcecode:: sql
+
+ Any P WHERE P is Person, EXISTS(P interested_by T, T name 'training') OR
+ (P city 'Paris')
+
+- *The surname and firstname of all people*
+
+ .. sourcecode:: sql
+
+ Any N, P WHERE X is Person, X name N, X firstname P
+
+ Note that the selection of several entities generally force
+ the use of "Any" because the type specification applies otherwise
+ to all the selected variables. We could write here
+
+ .. sourcecode:: sql
+
+ String N, P WHERE X is Person, X name N, X first_name P
+
+
+ Note: You can not specify several types with * ... where X is FirstType or X is SecondType*.
+ To specify several types explicitly, you have to do
+
+
+ .. sourcecode:: sql
+
+ Any X WHERE X is IN (FirstType, SecondType)
+
+
+.. _RQLInsertQuery:
+
+Insertion query
+~~~~~~~~~~~~~~~
+
+ `INSERT` <entity type> V1 (, <entity type> V2) \ * `:` <assignments>
+ [ `WHERE` <restriction>]
+
+:assignments:
+ list of relations to assign in the form `V1 relationship V2 | <static value>`
+
+The restriction can define variables used in assignments.
+
+Caution, if a restriction is specified, the insertion is done for
+*each line result returned by the restriction*.
+
+- *Insert a new person named 'foo'*
+
+ .. sourcecode:: sql
+
+ INSERT Person X: X name 'foo'
+
+- *Insert a new person named 'foo', another called 'nice' and a 'friend' relation
+ between them*
+
+ .. sourcecode:: sql
+
+ INSERT Person X, Person Y: X name 'foo', Y name 'nice', X friend Y
+
+- *Insert a new person named 'foo' and a 'friend' relation with an existing
+ person called 'nice'*
+
+ .. sourcecode:: sql
+
+ INSERT Person X: X name 'foo', X friend Y WHERE Y name 'nice'
+
+.. _RQLSetQuery:
+
+Update and relation creation queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ `SET` <assignements>
+ [ `WHERE` <restriction>]
+
+Caution, if a restriction is specified, the update is done *for
+each result line returned by the restriction*.
+
+- *Renaming of the person named 'foo' to 'bar' with the first name changed*
+
+ .. sourcecode:: sql
+
+ SET X name 'bar', X firstname 'original' WHERE X is Person, X name 'foo'
+
+- *Insert a relation of type 'know' between objects linked by
+ the relation of type 'friend'*
+
+ .. sourcecode:: sql
+
+ SET X know Y WHERE X friend Y
+
+
+.. _RQLDeleteQuery:
+
+Deletion query
+~~~~~~~~~~~~~~
+
+ `DELETE` (<entity type> V) | (V1 relation v2 ),...
+ [ `WHERE` <restriction>]
+
+Caution, if a restriction is specified, the deletion is made *for
+each line result returned by the restriction*.
+
+- *Deletion of the person named 'foo'*
+
+ .. sourcecode:: sql
+
+ DELETE Person X WHERE X name 'foo'
+
+- *Removal of all relations of type 'friend' from the person named 'foo'*
+
+ .. sourcecode:: sql
+
+ DELETE X friend Y WHERE X is Person, X name 'foo'
+
+
+.. _Yapps: http://theory.stanford.edu/~amitp/yapps/
+.. _Left outer join: http://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/cubes/available-cubes.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,66 @@
+.. _AvailableCubes:
+
+Available cubes
+---------------
+
+An instance is made of several basic cubes. In the set of available
+basic cubes we can find for example:
+
+Base entity types
+~~~~~~~~~~~~~~~~~
+* addressbook_: PhoneNumber and PostalAddress
+* card_: Card, generic documenting card
+* event_: Event (define events, display them in calendars)
+* file_: File (to allow users to upload and store binary or text files)
+* link_: Link (to collect links to web resources)
+* mailinglist_: MailingList (to reference a mailing-list and the URLs
+ for its archives and its admin interface)
+* person_: Person (easily mixed with addressbook)
+* task_: Task (something to be done between start and stop date)
+* zone_: Zone (to define places within larger places, for example a
+ city in a state in a country)
+
+
+Classification
+~~~~~~~~~~~~~~
+* folder_: Folder (to organize things by grouping them in folders)
+* keyword_: Keyword (to define classification schemes)
+* tag_: Tag (to tag anything)
+
+Other features
+~~~~~~~~~~~~~~
+* basket_: Basket (like a shopping cart)
+* blog_: a blogging system using Blog and BlogEntry entity types
+* comment_: system to attach comment threads to entities)
+* email_: archiving management for emails (`Email`, `Emailpart`,
+ `Emailthread`), trigger action in cubicweb through email
+
+
+
+
+
+.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
+.. _basket: http://www.cubicweb.org/project/cubicweb-basket
+.. _card: http://www.cubicweb.org/project/cubicweb-card
+.. _blog: http://www.cubicweb.org/project/cubicweb-blog
+.. _comment: http://www.cubicweb.org/project/cubicweb-comment
+.. _email: http://www.cubicweb.org/project/cubicweb-email
+.. _event: http://www.cubicweb.org/project/cubicweb-event
+.. _file: http://www.cubicweb.org/project/cubicweb-file
+.. _folder: http://www.cubicweb.org/project/cubicweb-folder
+.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
+.. _link: http://www.cubicweb.org/project/cubicweb-link
+.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
+.. _person: http://www.cubicweb.org/project/cubicweb-person
+.. _tag: http://www.cubicweb.org/project/cubicweb-tag
+.. _task: http://www.cubicweb.org/project/cubicweb-task
+.. _zone: http://www.cubicweb.org/project/cubicweb-zone
+
+To declare the use of a cube, once installed, add the name of the cube
+and its dependency relation in the `__depends_cubes__` dictionary
+defined in the file `__pkginfo__.py` of your own component.
+
+.. note::
+ The listed cubes above are available as debian-packages on `CubicWeb's forge`_.
+
+.. _`CubicWeb's forge`: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/cubes/cc-newcube.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,58 @@
+Creating a new cube from scratch
+--------------------------------
+
+Let's start by creating the cube environment in which we will develop ::
+
+ cd ~/cubes
+ # use cubicweb-ctl to generate a template for the cube
+ # will ask some questions, most with nice default
+ cubicweb-ctl newcube mycube
+ # makes the cube source code managed by mercurial
+ cd mycube
+ hg init
+ hg add .
+ hg ci
+
+If all went well, you should see the cube you just created in the list
+returned by ``cubicweb-ctl list`` in the *Available cubes* section.
+If not, please refer to :ref:`ConfigurationEnv`.
+
+To reuse an existing cube, add it to the list named
+``__depends_cubes__`` which is defined in :file:`__pkginfo__.py`.
+This variable is used for the instance packaging (dependencies handled
+by system utility tools such as APT) and to find used cubes when the
+database for the instance is created (import_erschema('MyCube') will
+not properly work otherwise).
+
+On a Unix system, the available cubes are usually stored in the
+directory :file:`/usr/share/cubicweb/cubes`. If you are using the
+cubicweb mercurial repository (:ref:`SourceInstallation`), the cubes
+are searched in the directory
+:file:`/path/to/cubicweb_toplevel/cubes`. In this configuration
+cubicweb itself ought to be located at
+:file:`/path/to/cubicweb_toplevel/cubicweb`.
+
+.. note::
+
+ Please note that if you do not wish to use default directory for your cubes
+ library, you should set the :envvar:`CW_CUBES_PATH` environment variable to
+ add extra directories where cubes will be search, and you'll then have to use
+ the option `--directory` to specify where you would like to place the source
+ code of your cube:
+
+ ``cubicweb-ctl newcube --directory=/path/to/cubes/library mycube``
+
+
+.. XXX resurrect once live-server is back
+.. Usage of :command:`cubicweb-ctl liveserver`
+.. -------------------------------------------
+
+.. To quickly test a new cube, you can also use the `liveserver` command for cubicweb-ctl
+.. which allows to create an instance in memory (using an SQLite database by
+.. default) and make it accessible through a web server ::
+
+.. cubicweb-ctl live-server mycube
+
+.. or by using an existing database (SQLite or Postgres)::
+
+.. cubicweb-ctl live-server -s myfile_sources mycube
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/cubes/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,11 @@
+Cubes
+=====
+
+This chapter describes how to define your own cubes and reuse already available cubes.
+
+.. toctree::
+ :maxdepth: 1
+
+ layout.rst
+ cc-newcube.rst
+ available-cubes.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/cubes/layout.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,153 @@
+
+.. _foundationsCube:
+
+.. _cubelayout:
+
+Standard structure for a cube
+-----------------------------
+
+A cube is structured as follows:
+
+::
+
+ mycube/
+ |
+ |-- data/
+ | |-- cubes.mycube.css
+ | |-- cubes.mycube.js
+ | `-- external_resources
+ |
+ |-- debian/
+ | |-- changelog
+ | |-- compat
+ | |-- control
+ | |-- copyright
+ | |-- cubicweb-mycube.prerm
+ | `-- rules
+ |
+ |-- entities.py
+ |
+ |-- i18n/
+ | |-- en.po
+ | |-- es.po
+ | `-- fr.po
+ |
+ |-- __init__.py
+ |
+ |-- MANIFEST.in
+ |
+ |-- migration/
+ | |-- postcreate.py
+ | `-- precreate.py
+ |
+ |-- __pkginfo__.py
+ |
+ |-- schema.py
+ |
+ |-- setup.py
+ |
+ |-- site_cubicweb.py
+ |
+ |-- hooks.py
+ |
+ |-- test/
+ | |-- data/
+ | | `-- bootstrap_cubes
+ | |-- pytestconf.py
+ | |-- realdb_test_mycube.py
+ | `-- test_mycube.py
+ |
+ `-- views.py
+
+
+We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
+``schema.py`` or ``hooks.py``. For example, we could have:
+
+::
+
+ mycube/
+ |
+ |-- entities.py
+ |-- hooks.py
+ `-- views/
+ |-- __init__.py
+ |-- forms.py
+ |-- primary.py
+ `-- widgets.py
+
+
+where :
+
+* ``schema`` contains the schema definition (server side only)
+* ``entities`` contains the entity definitions (server side and web interface)
+* ``hooks`` contains hooks and/or views notifications (server side only)
+* ``views`` contains the web interface components (web interface only)
+* ``test`` contains tests related to the cube (not installed)
+* ``i18n`` contains message catalogs for supported languages (server side and
+ web interface)
+* ``data`` contains data files for static content (images, css,
+ javascript code)...(web interface only)
+* ``migration`` contains initialization files for new instances (``postcreate.py``)
+ and a file containing dependencies of the component depending on the version
+ (``depends.map``)
+* ``debian`` contains all the files managing debian packaging (you will find
+ the usual files ``control``, ``rules``, ``changelog``... not installed)
+* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
+ and the current version (server side and web interface) or sub-cubes used by
+ the cube.
+
+
+At least you should have the file ``__pkginfo__.py``.
+
+
+The :file:`__init__.py` and :file:`site_cubicweb.py` files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX WRITEME
+
+The :file:`__pkginfo__.py` file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It contains metadata describing your cube, mostly useful for packaging.
+
+Two important attributes of this module are __depends__ and __recommends__
+dictionaries that indicates what should be installed (and each version if
+necessary) for the cube to work.
+
+Dependency on other cubes are expected to be of the form 'cubicweb-<cubename>'.
+
+When an instance is created, dependencies are automatically installed, while
+recommends are not.
+
+Recommends may be seen as a kind of 'weak dependency'. Eg, the most important
+effect of recommending a cube is that, if cube A recommends cube B, the cube B
+will be loaded before the cube A (same thing happend when A depends on B).
+
+Having this behaviour is sometime desired: on schema creation, you may rely on
+something defined in the other's schema; on database creation, on something
+created by the other's postcreate, and so on.
+
+
+:file:`migration/precreate.py` and :file:`migration/postcreate.py`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX detail steps of instance creation
+
+
+External resources such as image, javascript and css files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX naming convention external_resources file
+
+
+Out-of the box testing
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
+
+
+Packaging and distribution
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/dataimport.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,138 @@
+.. -*- coding: utf-8 -*-
+
+.. _dataimport:
+
+Dataimport
+==========
+
+*CubicWeb* is designed to manipulate huge of amount of data, and provides utilities to do so.
+
+The main entry point is :mod:`cubicweb.dataimport.importer` which defines an
+:class:`ExtEntitiesImporter` class responsible for importing data from an external source in the
+form :class:`ExtEntity` objects. An :class:`ExtEntity` is a transitional representation of an
+entity to be imported in the CubicWeb instance; building this representation is usually
+domain-specific -- e.g. dependent of the kind of data source (RDF, CSV, etc.) -- and is thus the
+responsibility of the end-user.
+
+Along with the importer, a *store* must be selected, which is responsible for insertion of data into
+the database. There exists different kind of stores_, allowing to insert data within different
+levels of the *CubicWeb* API and with different speed/security tradeoffs. Those keeping all the
+*CubicWeb* hooks and security will be slower but the possible errors in insertion (bad data types,
+integrity error, ...) will be handled.
+
+
+Example
+-------
+
+Consider the following schema snippet.
+
+.. code-block:: python
+
+ class Person(EntityType):
+ name = String(required=True)
+
+ class knows(RelationDefinition):
+ subject = 'Person'
+ object = 'Person'
+
+along with some data in a ``people.csv`` file::
+
+ # uri,name,knows
+ http://www.example.org/alice,Alice,
+ http://www.example.org/bob,Bob,http://www.example.org/alice
+
+The following code (using a shell context) defines a function `extentities_from_csv` to read
+`Person` external entities coming from a CSV file and calls the :class:`ExtEntitiesImporter` to
+insert corresponding entities and relations into the CubicWeb instance.
+
+.. code-block:: python
+
+ from cubicweb.dataimport import ucsvreader, RQLObjectStore
+ from cubicweb.dataimport.importer import ExtEntity, ExtEntitiesImporter
+
+ def extentities_from_csv(fpath):
+ """Yield Person ExtEntities read from `fpath` CSV file."""
+ with open(fpath) as f:
+ for uri, name, knows in ucsvreader(f, skipfirst=True, skip_empty=False):
+ yield ExtEntity('Personne', uri,
+ {'nom': set([name]), 'connait': set([knows])})
+
+ extenties = extentities_from_csv('people.csv')
+ store = RQLObjectStore(cnx)
+ importer = ExtEntitiesImporter(schema, store)
+ importer.import_entities(extenties)
+ commit()
+ rset = cnx.execute('String N WHERE X nom N, X connait Y, Y nom "Alice"')
+ assert rset[0][0] == u'Bob', rset
+
+Importer API
+------------
+
+.. automodule:: cubicweb.dataimport.importer
+
+
+Stores
+~~~~~~
+
+Stores are responsible to insert properly formatted entities and relations into the database. They
+have the following API::
+
+ >>> user_eid = store.prepare_insert_entity('CWUser', login=u'johndoe')
+ >>> group_eid = store.prepare_insert_entity('CWUser', name=u'unknown')
+ >>> store.relate(user_eid, 'in_group', group_eid)
+ >>> store.flush()
+ >>> store.commit()
+ >>> store.finish()
+
+Some stores **require a flush** to copy data in the database, so if you want to have store
+independent code you should explicitly call it. (There may be multiple flushes during the
+process, or only one at the end if there is no memory issue). This is different from the
+commit which validates the database transaction. At last, the `finish()` method should be called in
+case the store requires additional work once everything is done.
+
+* ``prepare_insert_entity(<entity type>, **kwargs) -> eid``: given an entity
+ type, attributes and inlined relations, return the eid of the entity to be
+ inserted, *with no guarantee that anything has been inserted in database*.
+
+* ``prepare_update_entity(<entity type>, eid, **kwargs) -> None``: given an
+ entity type and eid, promise for update given attributes and inlined
+ relations *with no guarantee that anything has been inserted in database*.
+
+* ``prepare_insert_relation(eid_from, rtype, eid_to) -> None``: indicate that a
+ relation ``rtype`` should be added between entities with eids ``eid_from``
+ and ``eid_to``. Similar to ``prepare_insert_entity()``, *there is no
+ guarantee that the relation has been inserted in database*.
+
+* ``flush() -> None``: flush any temporary data to database. May be called
+ several times during an import.
+
+* ``commit() -> None``: commit the database transaction.
+
+* ``finish() -> None``: additional stuff to do after import is terminated.
+
+ObjectStore
+-----------
+
+This store keeps objects in memory for *faster* validation. It may be useful in development
+mode. However, as it will not enforce the constraints of the schema nor insert anything in the
+database, so it may miss some problems.
+
+
+RQLObjectStore
+--------------
+
+This store works with an actual RQL repository, and it may be used in production mode.
+
+
+NoHookRQLObjectStore
+--------------------
+
+This store works similarly to the *RQLObjectStore* but bypasses some *CubicWeb* hooks to be faster.
+
+
+SQLGenObjectStore
+-----------------
+
+This store relies on *COPY FROM*/execute many sql commands to directly push data using SQL commands
+rather than using the whole *CubicWeb* API. For now, **it only works with PostgresSQL** as it requires
+the *COPY FROM* command.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/datamodel/baseschema.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,42 @@
+.. _pre_defined_entity_types:
+
+Pre-defined entities in the library
+-----------------------------------
+
+The library defines a set of entity schemas that are required by the system
+or commonly used in *CubicWeb* instances.
+
+
+Entity types used to store the schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`CWEType`, entity type
+* _`CWRType`, relation type
+* _`CWRelation`, relation definition
+* _`CWAttribute`, attribute relation definition
+* _`CWConstraint`, `CWConstraintType`, `RQLExpression`
+
+Entity types used to manage users and permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* _`CWUser`, system users
+* _`CWGroup`, users groups
+
+Entity types used to manage workflows
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* :ref:`Workflow <Workflow>`, workflow entity, linked to some entity types which may use this workflow
+* _`State`, workflow state
+* _`Transition`, workflow transition
+* _`TrInfo`, record of a transition trafic for an entity
+
+Other entity types
+~~~~~~~~~~~~~~~~~~
+* _`CWCache`, cache entities used to improve performances
+* _`CWProperty`, used to configure the instance
+
+* _`EmailAddress`, email address, used by the system to send notifications
+ to the users and also used by others optionnals schemas
+
+* _`Bookmark`, an entity type used to allow a user to customize his links within
+ the instance
+
+* _`ExternalUri`, used for semantic web site to indicate that an entity is the
+ same as another from an external site
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/datamodel/define-workflows.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,160 @@
+.. -*- coding: utf-8 -*-
+
+.. _Workflow:
+
+Defining a Workflow
+===================
+
+General
+-------
+
+A workflow describes how certain entities have to evolve between different
+states. Hence we have a set of states, and a "transition graph", i.e. a set of
+possible transitions from one state to another state.
+
+We will define a simple workflow for a blog, with only the following two states:
+`submitted` and `published`. You may want to take a look at :ref:`TutosBase` if
+you want to quickly setup an instance running a blog.
+
+Setting up a workflow
+---------------------
+
+We want to create a workflow to control the quality of the BlogEntry
+submitted on the instance. When a BlogEntry is created by a user
+its state should be `submitted`. To be visible to all, it has to
+be in the state `published`. To move it from `submitted` to `published`,
+we need a transition that we can call `approve_blogentry`.
+
+A BlogEntry state should not be modifiable by every user.
+So we have to define a group of users, `moderators`, and
+this group will have appropriate permissions to publish a BlogEntry.
+
+There are two ways to create a workflow: from the user interface, or
+by defining it in ``migration/postcreate.py``. This script is executed
+each time a new ``cubicweb-ctl db-init`` is done. We strongly
+recommend to create the workflow in ``migration/postcreate.py`` and we
+will now show you how. Read `Two bits of warning`_ to understand why.
+
+The state of an entity is managed by the `in_state` attribute which
+can be added to your entity schema by inheriting from
+`cubicweb.schema.WorkflowableEntityType`.
+
+
+About our example of BlogEntry, we must have:
+
+.. sourcecode:: python
+
+ from cubicweb.schema import WorkflowableEntityType
+
+ class BlogEntry(WorkflowableEntityType):
+ ...
+
+
+Creating states, transitions and group permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The :mod:`postcreate` script is executed in a special environment,
+adding several |cubicweb| primitives that can be used.
+
+They are all defined in the :class:`ServerMigrationHelper` class.
+We will only discuss the methods we use to create a workflow in this example.
+
+A workflow is a collection of entities of type ``State`` and of type
+``Transition`` which are standard *CubicWeb* entity types.
+
+To define a workflow for BlogDemo, please add the following lines
+to ``migration/postcreate.py``:
+
+.. sourcecode:: python
+
+ _ = unicode
+
+ moderators = add_entity('CWGroup', name=u"moderators")
+
+This adds the `moderators` user group.
+
+.. sourcecode:: python
+
+ wf = add_workflow(u'blog publication workflow', 'BlogEntry')
+
+At first, instanciate a new workflow object with a gentle description
+and the concerned entity types (this one can be a tuple for multiple
+value).
+
+.. sourcecode:: python
+
+ submitted = wf.add_state(_('submitted'), initial=True)
+ published = wf.add_state(_('published'))
+
+This will create two entities of type ``State``, one with name
+'submitted', and the other with name 'published'.
+
+``add_state`` expects as first argument the name of the state you want
+to create and an optional argument to say if it is supposed to be the
+initial state of the entity type.
+
+.. sourcecode:: python
+
+ wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
+
+This will create an entity of type ``Transition`` with name
+`approve_blogentry` which will be linked to the ``State`` entities
+created before.
+
+``add_transition`` expects
+
+ * as the first argument: the name of the transition
+ * then the list of states on which the transition can be triggered,
+ * the target state of the transition,
+ * and the permissions
+ (e.g. a list of user groups who can apply the transition; the user
+ has to belong to at least one of the listed group to perform the action).
+
+.. sourcecode:: python
+
+ checkpoint()
+
+.. note::
+ Do not forget to add the `_()` in front of all states and
+ transitions names while creating a workflow so that they will be
+ identified by the i18n catalog scripts.
+
+In addition to the user groups (one of which the user needs to belong
+to), we could have added a RQL condition. In this case, the user can
+only perform the action if the two conditions are satisfied.
+
+If we use an RQL condition on a transition, we can use the following variables:
+
+* `X`, the entity on which we may pass the transition
+* `U`, the user executing that may pass the transition
+
+
+.. image:: ../../images/03-transitions-view_en.png
+
+You can notice that in the action box of a BlogEntry, the state is now
+listed as well as the possible transitions for the current state
+defined by the workflow.
+
+The transitions will only be displayed for users having the right permissions.
+In our example, the transition `approve_blogentry` will only be displayed
+for the users belonging to the group `moderators` or `managers`.
+
+
+Two bits of warning
+~~~~~~~~~~~~~~~~~~~
+
+We could perfectly use the administration interface to do these
+operations. It is a convenient thing to do at times (when doing
+development, to quick-check things). But it is not recommended beyond
+that because it is a bit complicated to do it right and it will be
+only local to your instance (or, said a bit differently, such a
+workflow only exists in an instance database). Furthermore, you cannot
+write unit tests against deployed instances, and experience shows it
+is mandatory to have tests for any mildly complicated workflow
+setup.
+
+Indeed, if you create the states and transitions through the user
+interface, next time you initialize the database you will have to
+re-create all the workflow entities. The user interface should only be
+a reference for you to view the states and transitions, but is not the
+appropriate interface to define your application workflow.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/datamodel/definition.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,912 @@
+.. -*- coding: utf-8 -*-
+
+.. _datamodel_definition:
+
+Yams *schema*
+-------------
+
+The **schema** is the core piece of a *CubicWeb* instance as it
+defines and handles the data model. It is based on entity types that
+are either already defined in `Yams`_ and the *CubicWeb* standard
+library; or more specific types defined in cubes. The schema for a
+cube is defined in a `schema` python module or package.
+
+.. _`Yams`: http://www.logilab.org/project/yams
+
+.. _datamodel_overview:
+
+Overview
+~~~~~~~~
+
+The core idea of the yams schema is not far from the classical
+`Entity-relationship`_ model. But while an E/R model (or `logical
+model`) traditionally has to be manually translated to a lower-level
+data description language (such as the SQL `create table`
+sublanguage), also often described as the `physical model`, no such
+step is required with |yams| and |cubicweb|.
+
+.. _`Entity-relationship`: http://en.wikipedia.org/wiki/Entity-relationship_model
+
+This is because in addition to high-level, logical |yams| models, one
+uses the |rql| data manipulation language to query, insert, update and
+delete data. |rql| abstracts as much of the underlying SQL database as
+a |yams| schema abstracts from the physical layout. The vagaries of
+SQL are avoided.
+
+As a bonus point, such abstraction make it quite comfortable to build
+or use different backends to which |rql| queries apply.
+
+So, as in the E/R formalism, the building blocks are ``entities``
+(:ref:`EntityType`), ``relationships`` (:ref:`RelationType`,
+:ref:`RelationDefinition`) and ``attributes`` (handled like relation
+with |yams|).
+
+Let us detail a little the divergences between E/R and |yams|:
+
+* all relationship are binary which means that to represent a
+ non-binary relationship, one has to use an entity,
+* relationships do not support attributes (yet, see:
+ http://www.cubicweb.org/ticket/341318), hence the need to reify it
+ as an entity if need arises,
+* all entities have an `eid` attribute (an integer) that is its
+ primary key (but it is possible to declare uniqueness on other
+ attributes)
+
+Also |yams| supports the notions of:
+
+* entity inheritance (quite experimental yet, and completely
+ undocumented),
+* relation type: that is, relationships can be established over a set
+ of couple of entity types (henre the distinction made between
+ `RelationType` and `RelationDefinition` below)
+
+Finally |yams| has a few concepts of its own:
+
+* relationships being oriented and binary, we call the left hand
+ entity type the `subject` and the right hand entity type the
+ `object`
+
+.. note::
+
+ The |yams| schema is available at run time through the .schema
+ attribute of the `vregistry`. It's an instance of
+ :class:`cubicweb.schema.Schema`, which extends
+ :class:`yams.schema.Schema`.
+
+.. _EntityType:
+
+Entity type
+~~~~~~~~~~~
+
+An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
+a set of attributes and relations, and some permissions which define who can add, read,
+update or delete entities of this type.
+
+The following built-in types are available: ``String``,
+``Int``, ``BigInt``, ``Float``, ``Decimal``, ``Boolean``,
+``Date``, ``Datetime``, ``Time``, ``Interval``, ``Byte`` and
+``Password``. They can only be used as attributes of an other entity
+type.
+
+There is also a `RichString` kindof type:
+
+ .. autoclass:: yams.buildobjs.RichString
+
+The ``__unique_together__`` class attribute is a list of tuples of names of
+attributes or inlined relations. For each tuple, CubicWeb ensures the unicity
+of the combination. For example:
+
+.. sourcecode:: python
+
+ class State(EntityType):
+ __unique_together__ = [('name', 'state_of')]
+
+ name = String(required=True)
+ state_of = SubjectRelation('Workflow', cardinality='1*',
+ composite='object', inlined=True)
+
+
+You can find more base entity types in
+:ref:`pre_defined_entity_types`.
+
+.. XXX yams inheritance
+
+.. _RelationType:
+
+Relation type
+~~~~~~~~~~~~~
+
+A relation type is an instance of
+:class:`yams.schema.RelationSchema`. A relation type is simply a
+semantic definition of a kind of relationship that may occur in an
+application.
+
+It may be referenced by zero, one or more relation definitions.
+
+It is important to choose a good name, at least to avoid conflicts
+with some semantically different relation defined in other cubes
+(since there's only a shared name space for these names).
+
+A relation type holds the following properties (which are hence shared
+between all relation definitions of that type):
+
+* `inlined`: boolean handling the physical optimization for archiving
+ the relation in the subject entity table, instead of creating a specific
+ table for the relation. This applies to relations where cardinality
+ of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
+ definitions.
+
+* `symmetric`: boolean indicating that the relation is symmetrical, which
+ means that `X relation Y` implies `Y relation X`.
+
+.. _RelationDefinition:
+
+Relation definition
+~~~~~~~~~~~~~~~~~~~
+
+A relation definition is an instance of
+:class:`yams.schema.RelationDefinition`. It is a complete triplet
+"<subject entity type> <relation type> <object entity type>".
+
+When creating a new instance of that class, the corresponding
+:class:`RelationType` instance is created on the fly if necessary.
+
+Properties
+``````````
+
+The available properties for relation definitions are enumerated
+here. There are several kind of properties, as some relation
+definitions are actually attribute definitions, and other are not.
+
+Some properties may be completely optional, other may have a default
+value.
+
+Common properties for attributes and relations:
+
+* `description`: a unicode string describing an attribute or a
+ relation. By default this string will be used in the editing form of
+ the entity, which means that it is supposed to help the end-user and
+ should be flagged by the function `_` to be properly
+ internationalized.
+
+* `constraints`: a list of conditions/constraints that the relation has to
+ satisfy (c.f. `Constraints`_)
+
+* `cardinality`: a two character string specifying the cardinality of
+ the relation. The first character defines the cardinality of the
+ relation on the subject, and the second on the object. When a
+ relation can have multiple subjects or objects, the cardinality
+ applies to all, not on a one-to-one basis (so it must be
+ consistent...). Default value is '**'. The possible values are
+ inspired from regular expression syntax:
+
+ * `1`: 1..1
+ * `?`: 0..1
+ * `+`: 1..n
+ * `*`: 0..n
+
+Attributes properties:
+
+* `unique`: boolean indicating if the value of the attribute has to be
+ unique or not within all entities of the same type (false by
+ default)
+
+* `indexed`: boolean indicating if an index needs to be created for
+ this attribute in the database (false by default). This is useful
+ only if you know that you will have to run numerous searches on the
+ value of this attribute.
+
+* `default`: default value of the attribute. In case of date types, the values
+ which could be used correspond to the RQL keywords `TODAY` and `NOW`.
+
+* `metadata`: Is also accepted as an argument of the attribute contructor. It is
+ not really an attribute property. see `Metadata`_ for details.
+
+Properties for `String` attributes:
+
+* `fulltextindexed`: boolean indicating if the attribute is part of
+ the full text index (false by default) (*applicable on the type
+ `Byte` as well*)
+
+* `internationalizable`: boolean indicating if the value of the
+ attribute is internationalizable (false by default)
+
+Relation properties:
+
+* `composite`: string indicating that the subject (composite ==
+ 'subject') is composed of the objects of the relations. For the
+ opposite case (when the object is composed of the subjects of the
+ relation), we just set 'object' as value. The composition implies
+ that when the relation is deleted (so when the composite is deleted,
+ at least), the composed are also deleted.
+
+* `fulltext_container`: string indicating if the value if the full
+ text indexation of the entity on one end of the relation should be
+ used to find the entity on the other end. The possible values are
+ 'subject' or 'object'. For instance the use_email relation has that
+ property set to 'subject', since when performing a full text search
+ people want to find the entity using an email address, and not the
+ entity representing the email address.
+
+Constraints
+```````````
+
+By default, the available constraint types are:
+
+General Constraints
+......................
+
+* `SizeConstraint`: allows to specify a minimum and/or maximum size on
+ string (generic case of `maxsize`)
+
+* `BoundaryConstraint`: allows to specify a minimum and/or maximum value
+ on numeric types and date
+
+.. sourcecode:: python
+
+ from yams.constraints import BoundaryConstraint, TODAY, NOW, Attribute
+
+ class DatedEntity(EntityType):
+ start = Date(constraints=[BoundaryConstraint('>=', TODAY())])
+ end = Date(constraints=[BoundaryConstraint('>=', Attribute('start'))])
+
+ class Before(EntityType);
+ last_time = DateTime(constraints=[BoundaryConstraint('<=', NOW())])
+
+* `IntervalBoundConstraint`: allows to specify an interval with
+ included values
+
+.. sourcecode:: python
+
+ class Node(EntityType):
+ latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
+
+* `UniqueConstraint`: identical to "unique=True"
+
+* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
+
+Constraints can be dependent on a fixed value (90, Date(2015,3,23)) or a variable.
+In this second case, yams can handle :
+
+* `Attribute`: compare to the value of another attribute.
+* `TODAY`: compare to the current Date.
+* `NOW`: compare to the current Datetime.
+
+RQL Based Constraints
+......................
+
+RQL based constraints may take three arguments. The first one is the ``WHERE``
+clause of a RQL query used by the constraint. The second argument ``mainvars``
+is the ``Any`` clause of the query. By default this include `S` reserved for the
+subject of the relation and `O` for the object. Additional variables could be
+specified using ``mainvars``. The argument expects a single string with all
+variable's name separated by spaces. The last one, ``msg``, is the error message
+displayed when the constraint fails. As RQLVocabularyConstraint never fails the
+third argument is not available.
+
+* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
+ by the subject and/or the object of relation. In this query the variables
+ `S` and `O` are reserved for the relation subject and object entities.
+
+* `RQLVocabularyConstraint`: similar to the previous type of constraint except
+ that it does not express a "strong" constraint, which means it is only used to
+ restrict the values listed in the drop-down menu of editing form, but it does
+ not prevent another entity to be selected.
+
+* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
+ attribute is unique in a specific context. The Query must **never** return more
+ than a single result to be satisfied. In this query the variables `S` is
+ reserved for the relation subject entity. The other variables should be
+ specified with the second constructor argument (mainvars). This constraint type
+ should be used when __unique_together__ doesn't fit.
+
+.. XXX note about how to add new constraint
+
+.. _securitymodel:
+
+The security model
+~~~~~~~~~~~~~~~~~~
+
+The security model of `CubicWeb` is based on `Access Control List`.
+The main principles are:
+
+* users and groups of users
+* a user belongs to at least one group of user
+* permissions (`read`, `update`, `create`, `delete`)
+* permissions are assigned to groups (and not to users)
+
+For *CubicWeb* in particular:
+
+* we associate rights at the entities/relations schema level
+
+* the default groups are: `managers`, `users` and `guests`
+
+* users belong to the `users` group
+
+* there is a virtual group called `owners` to which we can associate only
+ `delete` and `update` permissions
+
+ * we can not add users to the `owners` group, they are implicitly added to it
+ according to the context of the objects they own
+
+ * the permissions of this group are only checked on `update`/`delete` actions
+ if all the other groups the user belongs to do not provide those permissions
+
+Setting permissions is done with the class attribute `__permissions__`
+of entity types and relation definitions. The value of this attribute
+is a dictionary where the keys are the access types (action), and the
+values are the authorized groups or rql expressions.
+
+For an entity type, the possible actions are `read`, `add`, `update` and
+`delete`.
+
+For a relation, the possible actions are `read`, `add`, and `delete`.
+
+For an attribute, the possible actions are `read`, `add` and `update`,
+and they are a refinement of an entity type permission.
+
+.. note::
+
+ By default, the permissions of an entity type attributes are
+ equivalent to the permissions of the entity type itself.
+
+ It is possible to provide custom attribute permissions which are
+ stronger than, or are more lenient than the entity type
+ permissions.
+
+ In a situation where all attributes were given custom permissions,
+ the entity type permissions would not be checked, except for the
+ `delete` action.
+
+For each access type, a tuple indicates the name of the authorized groups and/or
+one or multiple RQL expressions to satisfy to grant access. The access is
+provided if the user is in one of the listed groups or if one of the RQL condition
+is satisfied.
+
+Default permissions
+```````````````````
+
+The default permissions for ``EntityType`` are:
+
+.. sourcecode:: python
+
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests',),
+ 'update': ('managers', 'owners',),
+ 'delete': ('managers', 'owners'),
+ 'add': ('managers', 'users',)
+ }
+
+The default permissions for relations are:
+
+.. sourcecode:: python
+
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
+ 'delete': ('managers', 'users'),
+ 'add': ('managers', 'users',)}
+
+The default permissions for attributes are:
+
+.. sourcecode:: python
+
+ __permissions__ = {'read': ('managers', 'users', 'guests',),
+ 'add': ('managers', ERQLExpression('U has_add_permission X'),
+ 'update': ('managers', ERQLExpression('U has_update_permission X')),}
+
+.. note::
+
+ The default permissions for attributes are not syntactically
+ equivalent to the default permissions of the entity types, but the
+ rql expressions work by delegating to the entity type permissions.
+
+
+The standard user groups
+````````````````````````
+
+* `guests`
+
+* `users`
+
+* `managers`
+
+* `owners`: virtual group corresponding to the entity's owner.
+ This can only be used for the actions `update` and `delete` of an entity
+ type.
+
+It is also possible to use specific groups if they are defined in the precreate
+script of the cube (``migration/precreate.py``). Defining groups in postcreate
+script or later makes them unavailable for security purposes (in this case, an
+`sync_schema_props_perms` command has to be issued in a CubicWeb shell).
+
+
+Use of RQL expression for write permissions
+```````````````````````````````````````````
+
+It is possible to define RQL expression to provide update permission (`add`,
+`delete` and `update`) on entity type / relation definitions. An rql expression
+is a piece of query (corresponds to the WHERE statement of an RQL query), and the
+expression will be considered as satisfied if it returns some results. They can
+not be used in `read` permission.
+
+To use RQL expression in entity type permission:
+
+* you have to use the class :class:`~cubicweb.schema.ERQLExpression`
+
+* 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
+
+For RQL expressions on a relation type, the principles are the same except for
+the following:
+
+* you have to use the class :class:`~cubicweb.schema.RRQLExpression` instead of
+ :class:`~cubicweb.schema.ERQLExpression`
+
+* 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
+
+To define security for attributes of an entity (non-final relation), you have to
+use the class :class:`~cubicweb.schema.ERQLExpression` in which `X` represents
+the entity the attribute belongs to.
+
+It is possible to use in those expression a special relation
+`has_<ACTION>_permission` where the subject is the user (eg 'U') and the object
+is any variable representing an entity (usually 'X' in
+:class:`~cubicweb.schema.ERQLExpression`, 'S' or 'O' in
+:class:`~cubicweb.schema.RRQLExpression`), meaning that the user needs to have
+permission to execute the action <ACTION> on the entities represented by this
+variable. It's recommanded to use this feature whenever possible since it
+simplify greatly complex security definition and upgrade.
+
+
+.. sourcecode:: python
+
+ class my_relation(RelationDefinition):
+ __permissions__ = {'read': ('managers', 'users'),
+ 'add': ('managers', RRQLExpression('U has_update_permission S')),
+ 'delete': ('managers', RRQLExpression('U has_update_permission S'))
+ }
+
+In the above example, user will be allowed to add/delete `my_relation` if he has
+the `update` permission on the subject of the relation.
+
+.. note::
+
+ Potentially, the `use of an RQL expression to add an entity or a relation` can
+ cause problems for the user interface, because if the expression uses the
+ entity or the relation to create, we are not able to verify the permissions
+ before we actually added the entity (please note that this is not a problem for
+ the RQL server at all, because the permissions checks are done after the
+ creation). In such case, the permission check methods
+ (CubicWebEntitySchema.check_perm and has_perm) can indicate that the user is
+ not allowed to create this entity while it would obtain the permission. To
+ compensate this problem, it is usually necessary in such case to use an action
+ that reflects the schema permissions but which check properly the permissions
+ so that it would show up only if possible.
+
+
+Use of RQL expression for reading rights
+````````````````````````````````````````
+
+The principles are the same but with the following restrictions:
+
+* you can not use rql expression for the `read` permission of relations and
+ attributes,
+
+* you can not use special `has_<ACTION>_permission` relation in the rql
+ expression.
+
+
+Important notes about write permissions checking
+````````````````````````````````````````````````
+
+Write permissions (e.g. 'add', 'update', 'delete') are checked in core hooks.
+
+When a permission is checked slightly vary according to if it's an entity or
+relation, and if the relation is an attribute relation or not). It's important to
+understand that since according to when a permission is checked, values returned
+by rql expressions may changes, hence the permission being granted or not.
+
+Here are the current rules:
+
+1. permission to add/update entity and its attributes are checked on
+ commit
+
+2. permission to delete an entity is checked in 'before_delete_entity' hook
+
+3. permission to add a relation is checked either:
+
+ - in 'before_add_relation' hook if the relation type is in the
+ `BEFORE_ADD_RELATIONS` set
+
+ - else at commit time if the relation type is in the `ON_COMMIT_ADD_RELATIONS`
+ set
+
+ - else in 'after_add_relation' hook (the default)
+
+4. permission to delete a relation is checked in 'before_delete_relation' hook
+
+Last but not least, remember queries issued from hooks and operation are by
+default 'unsafe', eg there are no read or write security checks.
+
+See :mod:`cubicweb.hooks.security` for more details.
+
+
+.. _yams_example:
+
+
+Derived attributes and relations
+--------------------------------
+
+.. note:: **TODO** Check organisation of the whole chapter of the documentation
+
+Cubicweb offers the possibility to *query* data using so called
+*computed* relations and attributes. Those are *seen* by RQL requests
+as normal attributes and relations but are actually derived from other
+attributes and relations. In a first section we'll informally review
+two typical use cases. Then we see how to use computed attributes and
+relations in your schema. Last we will consider various significant
+aspects of their implementation and the impact on their usage.
+
+Motivating use cases
+~~~~~~~~~~~~~~~~~~~~
+
+Computed (or reified) relations
+```````````````````````````````
+
+It often arises that one must represent a ternary relation, or a
+family of relations. For example, in the context of an exhibition
+catalog you might want to link all *contributors* to the *work* they
+contributed to, but this contribution can be as *illustrator*,
+*author*, *performer*, ...
+
+The classical way to describe this kind of information within an
+entity-relationship schema is to *reify* the relation, that is turn
+the relation into a entity. In our example the schema will have a
+*Contribution* entity type used to represent the family of the
+contribution relations.
+
+
+.. sourcecode:: python
+
+ class ArtWork(EntityType):
+ name = String()
+ ...
+
+ class Person(EntityType):
+ name = String()
+ ...
+
+ class Contribution(EntityType):
+ contributor = SubjectRelation('Person', cardinality='1*', inlined=True)
+ manifestation = SubjectRelation('ArtWork')
+ role = SubjectRelation('Role')
+
+ class Role(EntityType):
+ name = String()
+
+But then, in order to query the illustrator(s) ``I`` of a work ``W``,
+one has to write::
+
+ Any I, W WHERE C is Contribution, C contributor I, C manifestation W,
+ C role R, R name 'illustrator'
+
+whereas we would like to be able to simply write::
+
+ Any I, W WHERE I illustrator_of W
+
+This is precisely what the computed relations allow.
+
+
+Computed (or synthesized) attribute
+```````````````````````````````````
+
+Assuming a trivial schema for describing employees in companies, one
+can be interested in the total of salaries payed by a company for
+all its employees. One has to write::
+
+ Any C, SUM(SA) GROUPBY S WHERE E works_for C, E salary SA
+
+whereas it would be most convenient to simply write::
+
+ Any C, TS WHERE C total_salary TS
+
+And this is again what computed attributes provide.
+
+
+Using computed attributes and relations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Computed (or reified) relations
+```````````````````````````````
+
+In the above case we would define the *computed relation*
+``illustrator_of`` in the schema by:
+
+.. sourcecode:: python
+
+ class illustrator_of(ComputedRelation):
+ rule = ('C is Contribution, C contributor S, C manifestation O,'
+ 'C role R, R name "illustrator"')
+
+You will note that:
+
+* the ``S`` and ``O`` RQL variables implicitly identify the subject and
+ object of the defined computed relation, akin to what happens in
+ RRQLExpression
+* the possible subject and object entity types are inferred from the rule;
+* computed relation definitions always have empty *add* and *delete* permissions
+* *read* permissions can be defined, permissions from the relations used in the
+ rewrite rule **are not considered** ;
+* nothing else may be defined on the `ComputedRelation` subclass beside
+ description, permissions and rule (e.g. no cardinality, composite, etc.,).
+ `BadSchemaDefinition` is raised on attempt to specify other attributes;
+* computed relations can not be used in 'SET' and 'DELETE' rql queries
+ (`BadQuery` exception raised).
+
+
+NB: The fact that the *add* and *delete* permissions are *empty* even
+for managers is expected to make the automatic UI not attempt to edit
+them.
+
+Computed (or synthesized) attributes
+````````````````````````````````````
+
+In the above case we would define the *computed attribute*
+``total_salary`` on the ``Company`` entity type in the schema by:
+
+.. sourcecode:: python
+
+ class Company(EntityType):
+ name = String()
+ total_salary = Int(formula='Any SUM(SA) GROUPBY E WHERE P works_for X, E salary SA')
+
+* the ``X`` RQL variable implicitly identifies the entity holding the
+ computed attribute, akin to what happens in ERQLExpression;
+* the type inferred from the formula is checked against the declared type, and
+ `BadSchemaDefinition` is raised if they don't match;
+* the computed attributes always have empty *update* permissions
+* `BadSchemaDefinition` is raised on attempt to set 'update' permissions;
+* 'read' permissions can be defined, permissions regarding the formula
+ **are not considered**;
+* other attribute's property (inlined, ...) can be defined as for normal attributes;
+* Similarly to computed relation, computed attribute can't be used in 'SET' and
+ 'DELETE' rql queries (`BadQuery` exception raised).
+
+
+API and implementation
+~~~~~~~~~~~~~~~~~~~~~~
+
+Representation in the data backend
+``````````````````````````````````
+
+Computed relations have no direct representation at the SQL table
+level. Instead, each time a query is issued the query is rewritten to
+replace the computed relation by its equivalent definition and the
+resulting rewritten query is performed in the usual way.
+
+On the contrary, computed attributes are represented as a column in the
+table for their host entity type, just like normal attributes. Their
+value is kept up-to-date with respect to their defintion by a system
+of hooks (also called triggers in most RDBMS) which recomputes them
+when the relations and attributes they depend on are modified.
+
+Yams API
+````````
+
+When accessing the schema through the *yams API* (not when defining a
+schema in a ``schema.py`` file) the computed attributes and relations
+are represented as follows:
+
+relations
+ The ``yams.RelationSchema`` class has a new ``rule`` attribute
+ holding the rule as a string. If this attribute is set all others
+ must not be set.
+attributes
+ A new property ``formula`` is added on class
+ ``yams.RelationDefinitionSchema`` alomng with a new keyword
+ argument ``formula`` on the initializer.
+
+Migration
+`````````
+
+The migrations are to be handled as summarized in the array below.
+
++------------+---------------------------------------------------+---------------------------------------+
+| | Computed rtype | Computed attribute |
++============+===================================================+=======================================+
+| add | * add_relation_type | * add_attribute |
+| | * add_relation_definition should trigger an error | * add_relation_definition |
++------------+---------------------------------------------------+---------------------------------------+
+| modify | * sync_schema_prop_perms: | * sync_schema_prop_perms: |
+| | checks the rule is | |
+| (rule or | synchronized with the database | - empty the cache, |
+| formula) | | - check formula, |
+| | | - make sure all the values get |
+| | | updated |
++------------+---------------------------------------------------+---------------------------------------+
+| del | * drop_relation_type | * drop_attribute |
+| | * drop_relation_definition should trigger an error| * drop_relation_definition |
++------------+---------------------------------------------------+---------------------------------------+
+
+
+Defining your schema using yams
+-------------------------------
+
+Entity type definition
+~~~~~~~~~~~~~~~~~~~~~~
+
+An entity type is defined by a Python class which inherits from
+:class:`yams.buildobjs.EntityType`. The class definition contains the
+description of attributes and relations for the defined entity type.
+The class name corresponds to the entity type name. It is expected to
+be defined in the module ``mycube.schema``.
+
+:Note on schema definition:
+
+ The code in ``mycube.schema`` is not meant to be executed. The class
+ EntityType mentioned above is different from the EntitySchema class
+ described in the previous chapter. EntityType is a helper class to
+ make Entity definition easier. Yams will process EntityType classes
+ and create EntitySchema instances from these class definitions. Similar
+ manipulation happen for relations.
+
+When defining a schema using python files, you may use the following shortcuts:
+
+- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
+
+- `vocabulary`: specify static possible values of an attribute
+
+- `maxsize`: integer providing the maximum size of a string (no limit by default)
+
+For example:
+
+.. sourcecode:: python
+
+ class Person(EntityType):
+ """A person with the properties and the relations necessary for my
+ application"""
+
+ last_name = String(required=True, fulltextindexed=True)
+ first_name = String(required=True, fulltextindexed=True)
+ title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
+ date_of_birth = Date()
+ works_for = SubjectRelation('Company', cardinality='?*')
+
+
+The entity described above defines three attributes of type String,
+last_name, first_name and title, an attribute of type Date for the date of
+birth and a relation that connects a `Person` to another entity of type
+`Company` through the semantic `works_for`.
+
+
+
+:Naming convention:
+
+ Entity class names must start with an uppercase letter. The common
+ usage is to use ``CamelCase`` names.
+
+ Attribute and relation names must start with a lowercase letter. The
+ common usage is to use ``underscore_separated_words``. Attribute and
+ relation names starting with a single underscore are permitted, to
+ denote a somewhat "protected" or "private" attribute.
+
+ In any case, identifiers starting with "CW" or "cw" are reserved for
+ internal use by the framework.
+
+ .. _Metadata:
+
+ Some attribute using the name of another attribute as prefix are considered
+ metadata. For example, if an EntityType have both a ``data`` and
+ ``data_format`` attribute, ``data_format`` is view as the ``format`` metadata
+ of ``data``. Later the :meth:`cw_attr_metadata` method will allow you to fetch
+ metadata related to an attribute. There are only three valid metadata names:
+ ``format``, ``encoding`` and ``name``.
+
+
+The name of the Python attribute corresponds to the name of the attribute
+or the relation in *CubicWeb* application.
+
+An attribute is defined in the schema as follows::
+
+ attr_name = AttrType(*properties, metadata={})
+
+where
+
+* `AttrType`: is one of the type listed in EntityType_,
+
+* `properties`: is a list of the attribute needs to satisfy (see `Properties`_
+ for more details),
+
+* `metadata`: is a dictionary of meta attributes related to ``attr_name``.
+ Dictionary keys are the name of the meta attribute. Dictionary values
+ attributes objects (like the content of ``AttrType``). For each entry of the
+ metadata dictionary a ``<attr_name>_<key> = <value>`` attribute is
+ automaticaly added to the EntityType. see `Metadata`_ section for details
+ about valid key.
+
+
+ ---
+
+While building your schema
+
+* it is possible to use the attribute `meta` to flag an entity type as a `meta`
+ (e.g. used to describe/categorize other entities)
+
+.. XXX the paragraph below needs clarification and / or moving out in
+.. another place
+
+*Note*: if you end up with an `if` in the definition of your entity, this probably
+means that you need two separate entities that implement the `ITree` interface and
+get the result from `.children()` which ever entity is concerned.
+
+.. Inheritance
+.. ```````````
+.. XXX feed me
+
+
+Definition of relations
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. XXX add note about defining relation type / definition
+
+A relation is defined by a Python class heriting `RelationType`. The name
+of the class corresponds to the name of the type. The class then contains
+a description of the properties of this type of relation, and could as well
+contain a string for the subject and a string for the object. This allows to create
+new definition of associated relations, (so that the class can have the
+definition properties from the relation) for example ::
+
+ class locked_by(RelationType):
+ """relation on all entities indicating that they are locked"""
+ inlined = True
+ cardinality = '?*'
+ subject = '*'
+ object = 'CWUser'
+
+If provided, the `subject` and `object` attributes denote the subject
+and object of the various relation definitions related to the relation
+type. Allowed values for these attributes are:
+
+* a string corresponding to an entity type
+* a tuple of string corresponding to multiple entity types
+* the '*' special string, meaning all types of entities
+
+When a relation is not inlined and not symmetrical, and it does not require
+specific permissions, it can be defined using a `SubjectRelation`
+attribute in the EntityType class. The first argument of `SubjectRelation` gives
+the entity type for the object of the relation.
+
+:Naming convention:
+
+ Although this way of defining relations uses a Python class, the
+ naming convention defined earlier prevails over the PEP8 conventions
+ used in the framework: relation type class names use
+ ``underscore_separated_words``.
+
+:Historical note:
+
+ It has been historically possible to use `ObjectRelation` which
+ defines a relation in the opposite direction. This feature is
+ deprecated and therefore should not be used in newly written code.
+
+:Future deprecation note:
+
+ In an even more remote future, it is quite possible that the
+ SubjectRelation shortcut will become deprecated, in favor of the
+ RelationType declaration which offers some advantages in the context
+ of reusable cubes.
+
+
+
+
+Handling schema changes
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Also, it should be clear that to properly handle data migration, an
+instance's schema is stored in the database, so the python schema file
+used to defined it is only read when the instance is created or
+upgraded.
+
+.. XXX complete me
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/datamodel/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,12 @@
+Data model
+==========
+
+This chapter describes how you define a schema and how to make it evolves as the time goes.
+
+.. toctree::
+ :maxdepth: 1
+
+ definition
+ metadata
+ baseschema
+ define-workflows
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/datamodel/metadata.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,37 @@
+
+Metadata
+--------
+
+.. index::
+ schema: meta-data;
+ schema: eid; creation_date; modification_data; cwuri
+ schema: created_by; owned_by; is; is_instance;
+
+Each entity type in |cubicweb| has at least the following meta-data attributes and relations:
+
+`eid`
+ entity's identifier which is unique in an instance. We usually call this identifier `eid` for historical reason.
+
+`creation_date`
+ Date and time of the creation of the entity.
+
+`modification_date`
+ Date and time of the latest modification of an entity.
+
+`cwuri`
+ Reference URL of the entity, which is not expected to change.
+
+`created_by`
+ Relation to the :ref:`users <CWUser>` who has created the entity
+
+`owned_by`
+ Relation to :ref:`users <CWUser>` whom the entity belongs; usually the creator but not
+ necessary, and it could have multiple owners notably for permission control
+
+`is`
+ Relation to the :ref:`entity type <CWEType>` of which type the entity is.
+
+`is_instance`
+ Relation to the :ref:`entity types <CWEType>` of which type the
+ entity is an instance of.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/devcore/dbapi.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,133 @@
+.. _dbapi:
+
+Python/RQL API
+~~~~~~~~~~~~~~
+
+The Python API developped to interface with RQL is inspired from the standard db-api,
+with a Connection object having the methods cursor, rollback and commit essentially.
+The most important method is the `execute` method of a cursor.
+
+.. sourcecode:: python
+
+ execute(rqlstring, args=None, build_descr=True)
+
+:rqlstring: the RQL query to execute (unicode)
+:args: if the query contains substitutions, a dictionary containing the values to use
+
+The `Connection` object owns the methods `commit` and `rollback`. You
+*should never need to use them* during the development of the web
+interface based on the *CubicWeb* framework as it determines the end
+of the transaction depending on the query execution success. They are
+however useful in other contexts such as tests or custom controllers.
+
+.. note::
+
+ If a query generates an error related to security (:exc:`Unauthorized`) or to
+ integrity (:exc:`ValidationError`), the transaction can still continue but you
+ won't be able to commit it, a rollback will be necessary to start a new
+ transaction.
+
+ Also, a rollback is automatically done if an error occurs during commit.
+
+.. note::
+
+ A :exc:`ValidationError` has a `entity` attribute. In CubicWeb,
+ this atttribute is set to the entity's eid (not a reference to the
+ entity itself).
+
+Executing RQL queries from a view or a hook
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you're within code of the web interface, the db-api like connexion is
+handled by the request object. You should not have to access it directly, but
+use the `execute` method directly available on the request, eg:
+
+.. sourcecode:: python
+
+ rset = self._cw.execute(rqlstring, kwargs)
+
+Similarly, on the server side (eg in hooks), there is no db-api connexion (since
+you're directly inside the data-server), so you'll have to use the execute method
+of the session object.
+
+
+Proper usage of `.execute`
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's say you want to get T which is in configuration C, this translates to:
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
+
+But it must be written in a syntax that will benefit from the use
+of a cache on the RQL server side:
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
+
+The syntax tree is built once for the "generic" RQL and can be re-used
+with a number of different eids. There rql IN operator is an exception
+to this rule.
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
+ % ','.join(['foo', 'bar']))
+
+Alternativelly, some of the common data related to an entity can be
+obtained from the `entity.related()` method (which is used under the
+hood by the orm when you use attribute access notation on an entity to
+get a relation. The initial request would then be translated to:
+
+.. sourcecode:: python
+
+ entity.related('in_conf', 'object')
+
+Additionnaly this benefits from the fetch_attrs policy (see
+:ref:`FetchAttrs`) eventually defined on the class element, which says
+which attributes must be also loaded when the entity is loaded through
+the orm.
+
+
+.. _resultset:
+
+The `ResultSet` API
+~~~~~~~~~~~~~~~~~~~
+
+ResultSet instances are a very commonly manipulated object. They have
+a rich API as seen below, but we would like to highlight a bunch of
+methods that are quite useful in day-to-day practice:
+
+* `__str__()` (applied by `print`) gives a very useful overview of both
+ the underlying RQL expression and the data inside; unavoidable for
+ debugging purposes
+
+* `printable_rql()` produces back a well formed RQL expression as a
+ string; it is very useful to build views
+
+* `entities()` returns a generator on all entities of the result set
+
+* `get_entity(row, col)` gets the entity at row, col coordinates; one
+ of the most used result set method
+
+.. autoclass:: cubicweb.rset.ResultSet
+ :members:
+
+
+The `Cursor` and `Connection` API
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The whole cursor API is developped below.
+
+.. note::
+
+ In practice you'll usually use the `.execute` method on the _cw object of
+ appobjects. Usage of other methods is quite rare.
+
+.. autoclass:: cubicweb.dbapi.Cursor
+ :members:
+
+.. autoclass:: cubicweb.dbapi.Connection
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/devcore/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,8 @@
+Core APIs
+=========
+
+.. toctree::
+ :maxdepth: 1
+
+ reqbase.rst
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/devcore/reqbase.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,40 @@
+Request and ResultSet methods
+-----------------------------
+
+Those are methods you'll find on both request objects and on
+repository session.
+
+Request methods
+~~~~~~~~~~~~~~~
+
+`URL handling`:
+
+* `build_url(*args, **kwargs)`, returns an absolute URL based on the
+ given arguments. The *controller* supposed to handle the response,
+ can be specified through the first positional parameter (the
+ connection is theoretically done automatically :).
+
+`Data formatting`:
+
+* `format_date(date, date_format=None, time=False)` returns a string for a
+ date time according to instance's configuration
+
+* `format_time(time)` returns a string for a date time according to
+ instance's configuration
+
+`And more...`:
+
+* `tal_render(template, variables)`, renders a precompiled page template with
+ variables in the given dictionary as context
+
+
+Result set methods
+~~~~~~~~~~~~~~~~~~
+
+* `get_entity(row, col)`, returns the entity corresponding to the data position
+ in the *result set*
+
+* `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but
+ also call the method `complete()` on the entity before returning it
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/entityclasses/adapters.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,167 @@
+.. _adapters:
+
+Interfaces and Adapters
+-----------------------
+
+Interfaces are the same thing as object-oriented programming `interfaces`_.
+Adapter refers to a well-known `adapter`_ design pattern that helps separating
+concerns in object oriented applications.
+
+.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
+.. _`adapter`: http://en.wikipedia.org/wiki/Adapter_pattern
+
+In |cubicweb| adapters provide logical functionalities to entity types.
+
+Definition of an adapter is quite trivial. An excerpt from cubicweb
+itself (found in :mod:`cubicweb.entities.adapters`):
+
+.. sourcecode:: python
+
+
+ class ITreeAdapter(EntityAdapter):
+ """This adapter has to be overriden to be configured using the
+ tree_relation, child_role and parent_role class attributes to
+ benefit from this default implementation
+ """
+ __regid__ = 'ITree'
+
+ child_role = 'subject'
+ parent_role = 'object'
+
+ def children_rql(self):
+ """returns RQL to get children """
+ return self.entity.cw_related_rql(self.tree_relation, self.parent_role)
+
+The adapter object has ``self.entity`` attribute which represents the
+entity being adapted.
+
+.. Note::
+
+ Adapters came with the notion of service identified by the registry identifier
+ of an adapters, hence dropping the need for explicit interface and the
+ :class:`cubicweb.predicates.implements` selector. You should instead use
+ :class:`cubicweb.predicates.is_instance` when you want to select on an entity
+ type, or :class:`cubicweb.predicates.adaptable` when you want to select on a
+ service.
+
+
+Specializing and binding an adapter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. sourcecode:: python
+
+ from cubicweb.entities.adapters import ITreeAdapter
+
+ class MyEntityITreeAdapter(ITreeAdapter):
+ __select__ = is_instance('MyEntity')
+ tree_relation = 'filed_under'
+
+The ITreeAdapter here provides a default implementation. The
+tree_relation class attribute is actually used by this implementation
+to help implement correct behaviour.
+
+Here we provide a specific implementation which will be bound for
+``MyEntity`` entity type (the `adaptee`).
+
+
+.. _interfaces_to_adapters:
+
+Converting code from Interfaces/Mixins to Adapters
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we go with a small example. Before:
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import implements
+ from cubicweb.interfaces import ITree
+ from cubicweb.mixins import ITreeMixIn
+
+ class MyEntity(ITreeMixIn, AnyEntity):
+ __implements__ = AnyEntity.__implements__ + (ITree,)
+
+
+ class ITreeView(EntityView):
+ __select__ = implements('ITree')
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ children = entity.children()
+
+After:
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import adaptable, is_instance
+ from cubicweb.entities.adapters import ITreeAdapter
+
+ class MyEntityITreeAdapter(ITreeAdapter):
+ __select__ = is_instance('MyEntity')
+
+ class ITreeView(EntityView):
+ __select__ = adaptable('ITree')
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ itree = entity.cw_adapt_to('ITree')
+ children = itree.children()
+
+As we can see, the interface/mixin duality disappears and the entity
+class itself is completely freed from these concerns. When you want
+to use the ITree interface of an entity, call its `cw_adapt_to` method
+to get an adapter for this interface, then access to members of the
+interface on the adapter
+
+Let's look at an example where we defined everything ourselves. We
+start from:
+
+.. sourcecode:: python
+
+ class IFoo(Interface):
+ def bar(self, *args):
+ raise NotImplementedError
+
+ class MyEntity(AnyEntity):
+ __regid__ = 'MyEntity'
+ __implements__ = AnyEntity.__implements__ + (IFoo,)
+
+ def bar(self, *args):
+ return sum(captain.age for captain in self.captains)
+
+ class FooView(EntityView):
+ __regid__ = 'mycube.fooview'
+ __select__ = implements('IFoo')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w('bar: %s' % entity.bar())
+
+Converting to:
+
+.. sourcecode:: python
+
+ class IFooAdapter(EntityAdapter):
+ __regid__ = 'IFoo'
+ __select__ = is_instance('MyEntity')
+
+ def bar(self, *args):
+ return sum(captain.age for captain in self.entity.captains)
+
+ class FooView(EntityView):
+ __regid__ = 'mycube.fooview'
+ __select__ = adaptable('IFoo')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w('bar: %s' % entity.cw_adapt_to('IFoo').bar())
+
+.. note::
+
+ When migrating an entity method to an adapter, the code can be moved as is
+ except for the `self` of the entity class, which in the adapter must become `self.entity`.
+
+Adapters defined in the library
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: cubicweb.entities.adapters
+ :members:
+
+More are defined in web/views.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/entityclasses/application-logic.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,177 @@
+How to use entities objects and adapters
+----------------------------------------
+
+The previous chapters detailed the classes and methods available to
+the developer at the so-called `ORM`_ level. However they say little
+about the common patterns of usage of these objects.
+
+.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
+
+Entities objects (and their adapters) are used in the repository and
+web sides of CubicWeb. On the repository side of things, one should
+manipulate them in Hooks and Operations.
+
+Hooks and Operations provide support for the implementation of rules
+such as computed attributes, coherency invariants, etc (they play the
+same role as database triggers, but in a way that is independent of
+the actual data sources).
+
+So a lot of an application's business rules will be written in Hooks
+(or Operations).
+
+On the web side, views also typically operate using entity
+objects. Obvious entity methods for use in views are the Dublin Core
+methods like ``dc_title``. For separation of concerns reasons, one
+should ensure no ui logic pervades the entities level, and also no
+business logic should creep into the views.
+
+In the duration of a transaction, entities objects can be instantiated
+many times, in views and hooks, even for the same database entity. For
+instance, in a classic CubicWeb deployment setup, the repository and
+the web front-end are separated process communicating over the
+wire. There is no way state can be shared between these processes
+(there is a specific API for that). Hence, it is not possible to use
+entity objects as messengers between these components of an
+application. It means that an attribute set as in ``obj.x = 42``,
+whether or not x is actually an entity schema attribute, has a short
+life span, limited to the hook, operation or view within which the
+object was built.
+
+Setting an attribute or relation value can be done in the context of a
+Hook/Operation, using the ``obj.cw_set(x=42)`` notation or a plain
+RQL ``SET`` expression.
+
+In views, it would be preferable to encapsulate the necessary logic in
+a method of an adapter for the concerned entity class(es). But of
+course, this advice is also reasonable for Hooks/Operations, though
+the separation of concerns here is less stringent than in the case of
+views.
+
+This leads to the practical role of objects adapters: it's where an
+important part of the application logic lies (the other part being
+located in the Hook/Operations).
+
+Anatomy of an entity class
+--------------------------
+
+We can look now at a real life example coming from the `tracker`_
+cube. Let us begin to study the ``entities/project.py`` content.
+
+.. sourcecode:: python
+
+ from cubicweb.entities.adapters import ITreeAdapter
+
+ class ProjectAdapter(ITreeAdapter):
+ __select__ = is_instance('Project')
+ tree_relation = 'subproject_of'
+
+ class Project(AnyEntity):
+ __regid__ = 'Project'
+ fetch_attrs, cw_fetch_order = fetch_config(('name', 'description',
+ 'description_format', 'summary'))
+
+ TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")'
+
+ def dc_title(self):
+ return self.name
+
+The fact that the `Project` entity type implements an ``ITree``
+interface is materialized by the ``ProjectAdapter`` class (inheriting
+the pre-defined ``ITreeAdapter`` whose ``__regid__`` is of course
+``ITree``), which will be selected on `Project` entity types because
+of its selector. On this adapter, we redefine the ``tree_relation``
+attribute of the ``ITreeAdapter`` class.
+
+This is typically used in views concerned with the representation of
+tree-like structures (CubicWeb provides several such views).
+
+It is important that the views themselves try not to implement this
+logic, not only because such views would be hardly applyable to other
+tree-like relations, but also because it is perfectly fine and useful
+to use such an interface in Hooks.
+
+In fact, Tree nature is a property of the data model that cannot be
+fully and portably expressed at the level of database entities (think
+about the transitive closure of the child relation). This is a further
+argument to implement it at entity class level.
+
+``fetch_attrs`` configures which attributes should be pre-fetched when using ORM
+methods retrieving entity of this type. In a same manner, the ``cw_fetch_order`` is
+a class method allowing to control sort order. More on this in :ref:`FetchAttrs`.
+
+We can observe the big ``TICKET_DEFAULT_STATE_RESTR`` is a pure
+application domain piece of data. There is, of course, no limitation
+to the amount of class attributes of this kind.
+
+The ``dc_title`` method provides a (unicode string) value likely to be
+consumed by views, but note that here we do not care about output
+encodings. We care about providing data in the most universal format
+possible, because the data could be used by a web view (which would be
+responsible of ensuring XHTML compliance), or a console or file
+oriented output (which would have the necessary context about the
+needed byte stream encoding).
+
+.. note::
+
+ The Dublin Core `dc_xxx` methods are not moved to an adapter as they
+ are extremely prevalent in CubicWeb and assorted cubes and should be
+ available for all entity types.
+
+Let us now dig into more substantial pieces of code, continuing the
+Project class.
+
+.. sourcecode:: python
+
+ def latest_version(self, states=('published',), reverse=None):
+ """returns the latest version(s) for the project in one of the given
+ states.
+
+ when no states specified, returns the latest published version.
+ """
+ order = 'DESC'
+ if reverse is not None:
+ warn('reverse argument is deprecated',
+ DeprecationWarning, stacklevel=1)
+ if reverse:
+ order = 'ASC'
+ rset = self.versions_in_state(states, order, True)
+ if rset:
+ return rset.get_entity(0, 0)
+ return None
+
+ def versions_in_state(self, states, order='ASC', limit=False):
+ """returns version(s) for the project in one of the given states, sorted
+ by version number.
+
+ If limit is true, limit result to one version.
+ If reverse, versions are returned from the smallest to the greatest.
+ """
+ if limit:
+ order += ' LIMIT 1'
+ rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \
+ 'WHERE V num N, V in_state S, S name IN (%s), ' \
+ 'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states))
+ return self._cw.execute(rql, {'p': self.eid})
+
+.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/
+
+These few lines exhibit the important properties we want to outline:
+
+* entity code is concerned with the application domain
+
+* it is NOT concerned with database consistency (this is the realm of
+ Hooks/Operations); in other words, it assumes a consistent world
+
+* it is NOT (directly) concerned with end-user interfaces
+
+* however it can be used in both contexts
+
+* it does not create or manipulate the internal object's state
+
+* it plays freely with RQL expression as needed
+
+* it is not concerned with internationalization
+
+* it does not raise exceptions
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/entityclasses/data-as-objects.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,142 @@
+Access to persistent data
+--------------------------
+
+Python-level access to persistent data is provided by the
+:class:`Entity <cubicweb.entity>` class.
+
+.. XXX this part is not clear. refactor it.
+
+An entity class is bound to a schema entity type. Descriptors are added when
+classes are registered in order to initialize the class according to its schema:
+
+* the attributes defined in the schema appear as attributes of these classes
+
+* the relations defined in the schema appear as attributes of these classes,
+ but are lists of instances
+
+`Formatting and output generation`:
+
+* :meth:`view(__vid, __registry='views', **kwargs)`, applies the given view to the entity
+ (and returns a unicode string)
+
+* :meth:`absolute_url(*args, **kwargs)`, returns an absolute URL including the base-url
+
+* :meth:`rest_path()`, returns a relative REST URL to get the entity
+
+* :meth:`printable_value(attr, value=_marker, attrtype=None, format='text/html', displaytime=True)`,
+ returns a string enabling the display of an attribute value in a given format
+ (the value is automatically recovered if necessary)
+
+`Data handling`:
+
+* :meth:`as_rset()`, converts the entity into an equivalent result set simulating the
+ request `Any X WHERE X eid _eid_`
+
+* :meth:`complete(skip_bytes=True)`, executes a request that recovers at
+ once all the missing attributes of an entity
+
+* :meth:`get_value(name)`, returns the value associated to the attribute name given
+ in parameter
+
+* :meth:`related(rtype, role='subject', limit=None, entities=False)`,
+ returns a list of entities related to the current entity by the
+ relation given in parameter
+
+* :meth:`unrelated(rtype, targettype, role='subject', limit=None)`,
+ returns a result set corresponding to the entities not (yet)
+ related to the current entity by the relation given in parameter
+ and satisfying its constraints
+
+* :meth:`cw_set(**kwargs)`, updates entity's attributes and/or relation with the
+ corresponding values given named parameters. To set a relation where this
+ entity is the object of the relation, use `reverse_<relation>` as argument
+ name. Values may be an entity, a list of entities, or None (meaning that all
+ relations of the given type from or to this object should be deleted).
+
+* :meth:`copy_relations(ceid)`, copies the relations of the entities having the eid
+ given in the parameters on the current entity
+
+* :meth:`cw_delete()` allows to delete the entity
+
+
+The :class:`AnyEntity` class
+----------------------------
+
+To provide a specific behavior for each entity, we can define a class
+inheriting from `cubicweb.entities.AnyEntity`. In general, we define this class
+in `mycube.entities` module (or in a submodule if we want to split code among
+multiple files) so that it will be available on both server and client side.
+
+The class `AnyEntity` is a sub-class of Entity that add methods to it,
+and helps specializing (by further subclassing) the handling of a
+given entity type.
+
+Most methods defined for `AnyEntity`, in addition to `Entity`, add
+support for the `Dublin Core`_ metadata.
+
+.. _`Dublin Core`: http://dublincore.org/
+
+`Standard meta-data (Dublin Core)`:
+
+* :meth:`dc_title()`, returns a unicode string corresponding to the
+ meta-data `Title` (used by default is the first non-meta attribute
+ of the entity schema)
+
+* :meth:`dc_long_title()`, same as dc_title but can return a more
+ detailed title
+
+* :meth:`dc_description(format='text/plain')`, returns a unicode string
+ corresponding to the meta-data `Description` (looks for a
+ description attribute by default)
+
+* :meth:`dc_authors()`, returns a unicode string corresponding to the meta-data
+ `Authors` (owners by default)
+
+* :meth:`dc_creator()`, returns a unicode string corresponding to the
+ creator of the entity
+
+* :meth:`dc_date(date_format=None)`, returns a unicode string corresponding to
+ the meta-data `Date` (update date by default)
+
+* :meth:`dc_type(form='')`, returns a string to display the entity type by
+ specifying the preferred form (`plural` for a plural form)
+
+* :meth:`dc_language()`, returns the language used by the entity
+
+Inheritance
+-----------
+
+When describing a data model, entities can inherit from other entities as is
+common in object-oriented programming.
+
+You have the possibility to redefine whatever pleases you, as follow:
+
+.. sourcecode:: python
+
+ from cubes.OTHER_CUBE import entities
+
+ class EntityExample(entities.EntityExample):
+
+ def dc_long_title(self):
+ return '%s (%s)' % (self.name, self.description)
+
+The most specific entity definition will always the one used by the
+ORM. For instance, the new EntityExample above in mycube replaces the
+one in OTHER_CUBE. These types are stored in the `etype` section of
+the `vregistry`.
+
+Notice this is different than yams schema inheritance, which is an
+experimental undocumented feature.
+
+
+Application logic
+-----------------
+
+While a lot of custom behaviour and application logic can be
+implemented using entity classes, the programmer must be aware that
+adding new attributes and method on an entity class adds may shadow
+schema-level attribute or relation definitions.
+
+To keep entities clean (mostly data structures plus a few universal
+methods such as listed above), one should use `adapters` (see
+:ref:`adapters`).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/entityclasses/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,13 @@
+Data as objects
+===============
+
+In this chapter, we will introduce the objects that are used to handle
+the logic associated to the data stored in the database.
+
+.. toctree::
+ :maxdepth: 1
+
+ data-as-objects
+ load-sort
+ adapters
+ application-logic
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/entityclasses/load-sort.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,40 @@
+
+.. _FetchAttrs:
+
+Loaded attributes and default sorting management
+````````````````````````````````````````````````
+
+* The class attribute `fetch_attrs` allows to define in an entity class a list of
+ names of attributes that should be automatically loaded when entities of this
+ type are fetched from the database using ORM methods retrieving entity of this
+ type (such as :meth:`related` and :meth:`unrelated`). You can also put relation
+ names in there, but we are limited to *subject relations of cardinality `?` or
+ `1`*.
+
+* The :meth:`cw_fetch_order` and :meth:`cw_fetch_unrelated_order` class methods
+ are respectively responsible to control how entities will be sorted when:
+
+ - retrieving all entities of a given type, or entities related to another
+
+ - retrieving a list of entities for use in drop-down lists enabling relations
+ creation in the editing view of an entity
+
+By default entities will be listed on their modification date descending,
+i.e. you'll get entities recently modified first. While this is usually a good
+default in drop-down list, you'll probably want to change `cw_fetch_order`.
+
+This may easily be done using the :func:`~cubicweb.entities.fetch_config`
+function, which simplifies the definition of attributes to load and sorting by
+returning a list of attributes to pre-load (considering automatically the
+attributes of `AnyEntity`) and a sorting function as described below:
+
+.. autofunction:: cubicweb.entities.fetch_config
+
+In you want something else (such as sorting on the result of a registered
+procedure), here is the prototype of those methods:
+
+
+.. automethod:: cubicweb.entity.Entity.cw_fetch_order
+
+.. automethod:: cubicweb.entity.Entity.cw_fetch_unrelated_order
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/fti.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,159 @@
+.. _fti:
+
+Full Text Indexing in CubicWeb
+------------------------------
+
+When an attribute is tagged as *fulltext-indexable* in the datamodel,
+CubicWeb will automatically trigger hooks to update the internal
+fulltext index (i.e the ``appears`` SQL table) each time this attribute
+is modified.
+
+CubicWeb also provides a ``db-rebuild-fti`` command to rebuild the whole
+fulltext on demand:
+
+.. sourcecode:: bash
+
+ cubicweb@esope~$ cubicweb db-rebuild-fti my_tracker_instance
+
+You can also rebuild the fulltext index for a given set of entity types:
+
+.. sourcecode:: bash
+
+ cubicweb@esope~$ cubicweb db-rebuild-fti my_tracker_instance Ticket Version
+
+In the above example, only fulltext index of entity types ``Ticket`` and ``Version``
+will be rebuilt.
+
+
+Standard FTI process
+~~~~~~~~~~~~~~~~~~~~
+
+Considering an entity type ``ET``, the default *fti* process is to :
+
+1. fetch all entities of type ``ET``
+
+2. for each entity, adapt it to ``IFTIndexable`` (see
+ :class:`~cubicweb.entities.adapters.IFTIndexableAdapter`)
+
+3. call
+ :meth:`~cubicweb.entities.adapters.IFTIndexableAdapter.get_words` on
+ the adapter which is supposed to return a dictionary *weight* ->
+ *list of words* as expected by
+ :meth:`~logilab.database.fti.FTIndexerMixIn.index_object`. The
+ tokenization of each attribute value is done by
+ :meth:`~logilab.database.fti.tokenize`.
+
+
+See :class:`~cubicweb.entities.adapters.IFTIndexableAdapter` for more documentation.
+
+
+Yams and ``fulltext_container``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is possible in the datamodel to indicate that fulltext-indexed
+attributes defined for an entity type will be used to index not the
+entity itself but a related entity. This is especially useful for
+composite entities. Let's take a look at (a simplified version of)
+the base schema defined in CubicWeb (see :mod:`cubicweb.schemas.base`):
+
+.. sourcecode:: python
+
+ class CWUser(WorkflowableEntityType):
+ login = String(required=True, unique=True, maxsize=64)
+ upassword = Password(required=True)
+
+ class EmailAddress(EntityType):
+ address = String(required=True, fulltextindexed=True,
+ indexed=True, unique=True, maxsize=128)
+
+
+ class use_email_relation(RelationDefinition):
+ name = 'use_email'
+ subject = 'CWUser'
+ object = 'EmailAddress'
+ cardinality = '*?'
+ composite = 'subject'
+
+
+The schema above states that there is a relation between ``CWUser`` and ``EmailAddress``
+and that the ``address`` field of ``EmailAddress`` is fulltext indexed. Therefore,
+in your application, if you use fulltext search to look for an email address, CubicWeb
+will return the ``EmailAddress`` itself. But the objects we'd like to index
+are more likely to be the associated ``CWUser`` than the ``EmailAddress`` itself.
+
+The simplest way to achieve that is to tag the ``use_email`` relation in
+the datamodel:
+
+.. sourcecode:: python
+
+ class use_email(RelationType):
+ fulltext_container = 'subject'
+
+
+Customizing how entities are fetched during ``db-rebuild-fti``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+``db-rebuild-fti`` will call the
+:meth:`~cubicweb.entities.AnyEntity.cw_fti_index_rql_queries` class
+method on your entity type.
+
+.. automethod:: cubicweb.entities.AnyEntity.cw_fti_index_rql_queries
+
+Now, suppose you've got a _huge_ table to index, you probably don't want to
+get all entities at once. So here's a simple customized example that will
+process block of 10000 entities:
+
+.. sourcecode:: python
+
+
+ class MyEntityClass(AnyEntity):
+ __regid__ = 'MyEntityClass'
+
+ @classmethod
+ def cw_fti_index_rql_queries(cls, req):
+ # get the default RQL method and insert LIMIT / OFFSET instructions
+ base_rql = super(SearchIndex, cls).cw_fti_index_rql_queries(req)[0]
+ selected, restrictions = base_rql.split(' WHERE ')
+ rql_template = '%s ORDERBY X LIMIT %%(limit)s OFFSET %%(offset)s WHERE %s' % (
+ selected, restrictions)
+ # count how many entities you'll have to index
+ count = req.execute('Any COUNT(X) WHERE X is MyEntityClass')[0][0]
+ # iterate by blocks of 10000 entities
+ chunksize = 10000
+ for offset in xrange(0, count, chunksize):
+ print 'SENDING', rql_template % {'limit': chunksize, 'offset': offset}
+ yield rql_template % {'limit': chunksize, 'offset': offset}
+
+Since you have access to ``req``, you can more or less fetch whatever you want.
+
+
+Customizing :meth:`~cubicweb.entities.adapters.IFTIndexableAdapter.get_words`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can also customize the FTI process by providing your own ``get_words()``
+implementation:
+
+.. sourcecode:: python
+
+ from cubicweb.entities.adapters import IFTIndexableAdapter
+
+ class SearchIndexAdapter(IFTIndexableAdapter):
+ __regid__ = 'IFTIndexable'
+ __select__ = is_instance('MyEntityClass')
+
+ def fti_containers(self, _done=None):
+ """this should yield any entity that must be considered to
+ fulltext-index self.entity
+
+ CubicWeb's default implementation will look for yams'
+ ``fulltex_container`` property.
+ """
+ yield self.entity
+ yield self.entity.some_related_entity
+
+
+ def get_words(self):
+ # implement any logic here
+ # see http://www.postgresql.org/docs/9.1/static/textsearch-controls.html
+ # for the actual signification of 'C'
+ return {'C': ['any', 'word', 'I', 'want']}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,25 @@
+.. _Part2:
+
+----------------------
+Repository development
+----------------------
+
+This part is about developing applications with the *CubicWeb*
+framework. It is not concerned with the web system, which is a
+separate layer and has its own whole chapter.
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ cubes/index
+ vreg.rst
+ datamodel/index
+ entityclasses/index
+ devcore/index
+ repo/index
+ testing.rst
+ migration.rst
+ profiling.rst
+ fti.rst
+ dataimport
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/migration.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,250 @@
+.. -*- coding: utf-8 -*-
+
+.. _migration:
+
+Migration
+=========
+
+One of the main design goals of *CubicWeb* was to support iterative and agile
+development. For this purpose, multiple actions are provided to facilitate the
+improvement of an instance, and in particular to handle the changes to be
+applied to the data model, without loosing existing data.
+
+The current version of a cube (and of cubicweb itself) is provided in the file
+`__pkginfo__.py` as a tuple of 3 integers.
+
+Migration scripts management
+----------------------------
+
+Migration scripts has to be located in the directory `migration` of your
+cube and named accordingly:
+
+::
+
+ <version n° X.Y.Z>[_<description>]_<mode>.py
+
+in which :
+
+* X.Y.Z is the model version number to which the script enables to migrate.
+
+* *mode* (between the last "_" and the extension ".py") is used for
+ distributed installation. It indicates to which part
+ of the application (RQL server, web server) the script applies.
+ Its value could be :
+
+ * `common`, applies to the RQL server as well as the web server and updates
+ files on the hard drive (configuration files migration for example).
+
+ * `web`, applies only to the web server and updates files on the hard drive.
+
+ * `repository`, applies only to the RQL server and updates files on the
+ hard drive.
+
+ * `Any`, applies only to the RQL server and updates data in the database
+ (schema and data migration for example).
+
+Again in the directory `migration`, the file `depends.map` allows to indicate
+that for the migration to a particular model version, you always have to first
+migrate to a particular *CubicWeb* version. This file can contain comments (lines
+starting with `#`) and a dependency is listed as follows: ::
+
+ <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
+
+For example: ::
+
+ 0.12.0: 2.26.0
+ 0.13.0: 2.27.0
+ # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
+ 0.15.0: 2.28.0
+
+Base context
+------------
+
+The following identifiers are pre-defined in migration scripts:
+
+* `config`, instance configuration
+
+* `interactive_mode`, boolean indicating that the script is executed in
+ an interactive mode or not
+
+* `versions_map`, dictionary of migrated versions (key are cubes
+ names, including 'cubicweb', values are (from version, to version)
+
+* `confirm(question)`, function asking the user and returning true
+ if the user answers yes, false otherwise (always returns true in
+ non-interactive mode)
+
+* `_()` is equivalent to `unicode` allowing to flag the strings to
+ internationalize in the migration scripts.
+
+In the `repository` scripts, the following identifiers are also defined:
+
+* `commit(ask_confirm=True)`, request confirming and executing a "commit"
+
+* `schema`, instance schema (readen from the database)
+
+* `fsschema`, installed schema on the file system (e.g. schema of
+ the updated model and cubicweb)
+
+* `repo`, repository object
+
+* `session`, repository session object
+
+
+New cube dependencies
+---------------------
+
+If your code depends on some new cubes, you have to add them in a migration
+script by using:
+
+* `add_cube(cube, update_database=True)`, add a cube.
+* `add_cubes(cubes, update_database=True)`, add a list of cubes.
+
+The `update_database` parameter is telling if the database schema
+should be updated or if only the relevant persistent property should be
+inserted (for the case where a new cube has been extracted from an
+existing one, so the new cube schema is actually already in there).
+
+If some of the added cubes are already used by an instance, they'll simply be
+silently skipped.
+
+
+Schema migration
+----------------
+The following functions for schema migration are available in `repository`
+scripts:
+
+* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
+ attribute to an existing entity type. If the attribute type is not specified,
+ then it is extracted from the updated schema.
+
+* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
+ existing entity type.
+
+* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
+
+* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
+ If `auto` is True, all the relations using this entity type and having a known
+ entity type on the other hand will automatically be added.
+
+* `drop_entity_type(etype, commit=True)`, removes an entity type and all the
+ relations using it.
+
+* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
+
+* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
+ type. If `addrdef` is True, all the relations definitions of this type will
+ be added.
+
+* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
+ definitions of this type.
+
+* `rename_relation_type(oldname, newname, commit=True)`, renames a relation type.
+
+* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
+ relation definition.
+
+* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
+ a relation definition.
+
+* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
+ synchronizes properties and/or permissions on:
+ - the whole schema if ertype is None
+ - an entity or relation type schema if ertype is a string
+ - a relation definition if ertype is a 3-uple (subject, relation, object)
+
+* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
+ properties of a relation definition by using the named parameters of the properties
+ to change.
+
+* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
+ relation <rtype> of entity type <etype>.
+
+* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
+ for the relation <rtype> of entity type <etype>.
+
+Data migration
+--------------
+The following functions for data migration are available in `repository` scripts:
+
+* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
+ query, either to interrogate or update. A result set object is returned.
+
+* `add_entity(etype, *args, **kwargs)`, adds a new entity of the given type.
+ The attribute and relation values are specified as named positional
+ arguments.
+
+Workflow creation
+-----------------
+
+The following functions for workflow creation are available in `repository`
+scripts:
+
+* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
+ for a given type(s)
+
+You can find more details about workflows in the chapter :ref:`Workflow` .
+
+Configuration migration
+-----------------------
+
+The following functions for configuration migration are available in all
+scripts:
+
+* `option_renamed(oldname, newname)`, indicates that an option has been renamed
+
+* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
+ belong anymore to the same group.
+
+* `option_added(oldname, newname)`, indicates that an option has been added.
+
+* `option_removed(oldname, newname)`, indicates that an option has been deleted.
+
+The `config` variable is an object which can be used to access the
+configuration values, for reading and updating, with a dictionary-like
+syntax.
+
+Example 1: migration script changing the variable 'sender-addr' in
+all-in-one.conf. The script also checks that in that the instance is
+configured with a known value for that variable, and only updates the
+value in that case.
+
+.. sourcecode:: python
+
+ wrong_addr = 'cubicweb@loiglab.fr' # known wrong address
+ fixed_addr = 'cubicweb@logilab.fr'
+ configured_addr = config.get('sender-addr')
+ # check that the address has not been hand fixed by a sysadmin
+ if configured_addr == wrong_addr:
+ config['sender-addr'] = fixed-addr
+ config.save()
+
+Example 2: checking the value of the database backend driver, which
+can be useful in case you need to issue backend-dependent raw SQL
+queries in a migration script.
+
+.. sourcecode:: python
+
+ dbdriver = config.sources()['system']['db-driver']
+ if dbdriver == "sqlserver2005":
+ # this is now correctly handled by CW :-)
+ sql('ALTER TABLE cw_Xxxx ALTER COLUMN cw_name varchar(64) NOT NULL;')
+ commit()
+ else: # postgresql
+ sync_schema_props_perms(ertype=('Xxxx', 'name', 'String'),
+ syncperms=False)
+
+
+Others migration functions
+--------------------------
+Those functions are only used for low level operations that could not be
+accomplished otherwise or to repair damaged databases during interactive
+session. They are available in `repository` scripts:
+
+* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
+* `add_entity_type_table(etype, commit=True)`
+* `add_relation_type_table(rtype, commit=True)`
+* `uninline_relation(rtype, commit=True)`
+
+
+[FIXME] Add explanation on how to use cubicweb-ctl shell
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/profiling.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,57 @@
+.. _PROFILING:
+
+Profiling and performance
+=========================
+
+If you feel that one of your pages takes more time than it should to be
+generated, chances are that you're making too many RQL queries. Obviously,
+there are other reasons but experience tends to show this is the first thing to
+track down. Luckily, CubicWeb provides a configuration option to log RQL
+queries. In your ``all-in-one.conf`` file, set the **query-log-file** option::
+
+ # web application query log file
+ query-log-file=/home/user/myapp-rql.log
+
+Then restart your application, reload your page and stop your application.
+The file ``myapp-rql.log`` now contains the list of RQL queries that were
+executed during your test. It's a simple text file containing lines such as::
+
+ Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec)
+ Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec)
+
+The structure of each line is::
+
+ <RQL QUERY> <QUERY ARGS IF ANY> -- <TIME SPENT>
+
+CubicWeb also provides the **exlog** command to examine and summarize data found
+in such a file:
+
+.. sourcecode:: sh
+
+ $ cubicweb-ctl exlog /home/user/myapp-rql.log
+ 0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
+ 0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
+ 0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
+ 0.01 1 Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s {, }
+ 0.01 1 Any B,T,P ORDERBY lower(T) WHERE B is Bookmark,B title T, B path P, B bookmarked_by U, U eid %(x)s {}
+ 0.01 1 Any A,B,C,D WHERE A eid %(x)s,A name B,A creation_date C,A modification_date D {}
+
+This command sorts and uniquifies queries so that it's easy to see where
+is the hot spot that needs optimization.
+
+Do not neglect to set the **fetch_attrs** attribute you can define in your
+entity classes because it can greatly reduce the number of queries executed (see
+:ref:`FetchAttrs`).
+
+You should also know about the **profile** option in the ``all-in-on.conf``. If
+set, this option will make your application run in an `hotshot`_ session and
+store the results in the specified file.
+
+.. _hotshot: http://docs.python.org/library/hotshot.html#module-hotshot
+
+Last but no least, if you're using the PostgreSQL database backend, VACUUMing
+your database can significantly improve the performance of the queries (by
+updating the statistics used by the query optimizer). Nowadays, this is done
+automatically from time to time, but if you've just imported a large amount of
+data in your db, you will want to vacuum it (with the analyse option on). Read
+the documentation of your database for more information.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/repo/hooks.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,279 @@
+.. -*- coding: utf-8 -*-
+.. _hooks:
+
+Hooks and Operations
+====================
+
+.. autodocstring:: cubicweb.server.hook
+
+
+Example using dataflow hooks
+----------------------------
+
+We will use a very simple example to show hooks usage. Let us start with the
+following schema.
+
+.. sourcecode:: python
+
+ class Person(EntityType):
+ age = Int(required=True)
+
+We would like to add a range constraint over a person's age. Let's write an hook
+(supposing yams can not handle this nativly, which is wrong). It shall be placed
+into `mycube/hooks.py`. If this file were to grow too much, we can easily have a
+`mycube/hooks/... package` containing hooks in various modules.
+
+.. sourcecode:: python
+
+ from cubicweb import ValidationError
+ from cubicweb.predicates import is_instance
+ from cubicweb.server.hook import Hook
+
+ class PersonAgeRange(Hook):
+ __regid__ = 'person_age_range'
+ __select__ = Hook.__select__ & is_instance('Person')
+ events = ('before_add_entity', 'before_update_entity')
+
+ def __call__(self):
+ if 'age' in self.entity.cw_edited:
+ if 0 <= self.entity.age <= 120:
+ return
+ msg = self._cw._('age must be between 0 and 120')
+ raise ValidationError(self.entity.eid, {'age': msg})
+
+In our example the base `__select__` is augmented with an `is_instance` selector
+matching the desired entity type.
+
+The `events` tuple is used specify that our hook should be called before the
+entity is added or updated.
+
+Then in the hook's `__call__` method, we:
+
+* check if the 'age' attribute is edited
+* if so, check the value is in the range
+* if not, raise a validation error properly
+
+Now Let's augment our schema with new `Company` entity type with some relation to
+`Person` (in 'mycube/schema.py').
+
+.. sourcecode:: python
+
+ class Company(EntityType):
+ name = String(required=True)
+ boss = SubjectRelation('Person', cardinality='1*')
+ subsidiary_of = SubjectRelation('Company', cardinality='*?')
+
+
+We would like to constrain the company's bosses to have a minimum (legal)
+age. Let's write an hook for this, which will be fired when the `boss` relation
+is established (still supposing we could not specify that kind of thing in the
+schema).
+
+.. sourcecode:: python
+
+ class CompanyBossLegalAge(Hook):
+ __regid__ = 'company_boss_legal_age'
+ __select__ = Hook.__select__ & match_rtype('boss')
+ events = ('before_add_relation',)
+
+ def __call__(self):
+ boss = self._cw.entity_from_eid(self.eidto)
+ if boss.age < 18:
+ msg = self._cw._('the minimum age for a boss is 18')
+ raise ValidationError(self.eidfrom, {'boss': msg})
+
+.. Note::
+
+ We use the :class:`~cubicweb.server.hook.match_rtype` selector to select the
+ proper relation type.
+
+ The essential difference with respect to an entity hook is that there is no
+ self.entity, but `self.eidfrom` and `self.eidto` hook attributes which
+ represent the subject and object **eid** of the relation.
+
+Suppose we want to check that there is no cycle by the `subsidiary_of`
+relation. This is best achieved in an operation since all relations are likely to
+be set at commit time.
+
+.. sourcecode:: python
+
+ from cubicweb.server.hook import Hook, DataOperationMixIn, Operation, match_rtype
+
+ def check_cycle(self, session, eid, rtype, role='subject'):
+ parents = set([eid])
+ parent = session.entity_from_eid(eid)
+ while parent.related(rtype, role):
+ parent = parent.related(rtype, role)[0]
+ if parent.eid in parents:
+ msg = session._('detected %s cycle' % rtype)
+ raise ValidationError(eid, {rtype: msg})
+ parents.add(parent.eid)
+
+
+ class CheckSubsidiaryCycleOp(Operation):
+
+ def precommit_event(self):
+ check_cycle(self.session, self.eidto, 'subsidiary_of')
+
+
+ class CheckSubsidiaryCycleHook(Hook):
+ __regid__ = 'check_no_subsidiary_cycle'
+ __select__ = Hook.__select__ & match_rtype('subsidiary_of')
+ events = ('after_add_relation',)
+
+ def __call__(self):
+ CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
+
+
+Like in hooks, :exc:`~cubicweb.ValidationError` can be raised in operations. Other
+exceptions are usually programming errors.
+
+In the above example, our hook will instantiate an operation each time the hook
+is called, i.e. each time the `subsidiary_of` relation is set. There is an
+alternative method to schedule an operation from a hook, using the
+:func:`get_instance` class method.
+
+.. sourcecode:: python
+
+ from cubicweb.server.hook import set_operation
+
+ class CheckSubsidiaryCycleHook(Hook):
+ __regid__ = 'check_no_subsidiary_cycle'
+ events = ('after_add_relation',)
+ __select__ = Hook.__select__ & match_rtype('subsidiary_of')
+
+ def __call__(self):
+ CheckSubsidiaryCycleOp.get_instance(self._cw).add_data(self.eidto)
+
+ class CheckSubsidiaryCycleOp(DataOperationMixIn, Operation):
+
+ def precommit_event(self):
+ for eid in self.get_data():
+ check_cycle(self.session, eid, self.rtype)
+
+
+Here, we call :func:`set_operation` so that we will simply accumulate eids of
+entities to check at the end in a single `CheckSubsidiaryCycleOp`
+operation. Value are stored in a set associated to the
+'subsidiary_cycle_detection' transaction data key. The set initialization and
+operation creation are handled nicely by :func:`set_operation`.
+
+A more realistic example can be found in the advanced tutorial chapter
+:ref:`adv_tuto_security_propagation`.
+
+
+Inter-instance communication
+----------------------------
+
+If your application consists of several instances, you may need some means to
+communicate between them. Cubicweb provides a publish/subscribe mechanism
+using ØMQ_. In order to use it, use
+:meth:`~cubicweb.server.cwzmq.ZMQComm.add_subscription` on the
+`repo.app_instances_bus` object. The `callback` will get the message (as a
+list). A message can be sent by calling
+:meth:`~cubicweb.server.cwzmq.ZMQComm.publish` on `repo.app_instances_bus`.
+The first element of the message is the topic which is used for filtering and
+dispatching messages.
+
+.. _ØMQ: http://www.zeromq.org/
+
+.. sourcecode:: python
+
+ class FooHook(hook.Hook):
+ events = ('server_startup',)
+ __regid__ = 'foo_startup'
+
+ def __call__(self):
+ def callback(msg):
+ self.info('received message: %s', ' '.join(msg))
+ self.repo.app_instances_bus.add_subscription('hello', callback)
+
+.. sourcecode:: python
+
+ def do_foo(self):
+ actually_do_foo()
+ self._cw.repo.app_instances_bus.publish(['hello', 'world'])
+
+The `zmq-address-pub` configuration variable contains the address used
+by the instance for sending messages, e.g. `tcp://*:1234`. The
+`zmq-address-sub` variable contains a comma-separated list of addresses
+to listen on, e.g. `tcp://localhost:1234, tcp://192.168.1.1:2345`.
+
+
+Hooks writing tips
+------------------
+
+Reminder
+~~~~~~~~
+
+You should never use the `entity.foo = 42` notation to update an entity. It will
+not do what you expect (updating the database). Instead, use the
+:meth:`~cubicweb.entity.Entity.cw_set` method or direct access to entity's
+:attr:`cw_edited` attribute if you're writing a hook for 'before_add_entity' or
+'before_update_entity' event.
+
+
+How to choose between a before and an after event ?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`before_*` hooks give you access to the old attribute (or relation)
+values. You can also intercept and update edited values in the case of
+entity modification before they reach the database.
+
+Else the question is: should I need to do things before or after the actual
+modification ? If the answer is "it doesn't matter", use an 'after' event.
+
+
+Validation Errors
+~~~~~~~~~~~~~~~~~
+
+When a hook which is responsible to maintain the consistency of the
+data model detects an error, it must use a specific exception named
+:exc:`~cubicweb.ValidationError`. Raising anything but a (subclass of)
+:exc:`~cubicweb.ValidationError` is a programming error. Raising it
+entails aborting the current transaction.
+
+This exception is used to convey enough information up to the user
+interface. Hence its constructor is different from the default Exception
+constructor. It accepts, positionally:
+
+* an entity eid (**not the entity itself**),
+
+* a dict whose keys represent attribute (or relation) names and values
+ an end-user facing message (hence properly translated) relating the
+ problem.
+
+.. sourcecode:: python
+
+ raise ValidationError(earth.eid, {'sea_level': self._cw._('too high'),
+ 'temperature': self._cw._('too hot')})
+
+
+Checking for object created/deleted in the current transaction
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In hooks, you can use the
+:meth:`~cubicweb.server.session.Session.added_in_transaction` or
+:meth:`~cubicweb.server.session.Session.deleted_in_transaction` of the session
+object to check if an eid has been created or deleted during the hook's
+transaction.
+
+This is useful to enable or disable some stuff if some entity is being added or
+deleted.
+
+.. sourcecode:: python
+
+ if self._cw.deleted_in_transaction(self.eidto):
+ return
+
+
+Peculiarities of inlined relations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Relations which are defined in the schema as `inlined` (see :ref:`RelationType`
+for details) are inserted in the database at the same time as entity attributes.
+
+This may have some side effect, for instance when creating an entity
+and setting an inlined relation in the same rql query, then at
+`before_add_relation` time, the relation will already exist in the
+database (it is otherwise not the case).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/repo/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,13 @@
+.. -*- coding: utf-8 -*-
+
+Repository customization
+++++++++++++++++++++++++
+.. toctree::
+ :maxdepth: 1
+
+ sessions
+ hooks
+ notifications
+ tasks
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/repo/notifications.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,29 @@
+.. -*- coding: utf-8 -*-
+
+Notifications management
+========================
+
+CubicWeb provides a machinery to ease notifications handling. To use it for a
+notification:
+
+* write a view inheriting from
+ :class:`~cubicweb.sobjects.notification.NotificationView`. The usual view api
+ is used to generated the email (plain text) content, and additional
+ :meth:`~cubicweb.sobjects.notification.NotificationView.subject` and
+ :meth:`~cubicweb.sobjects.notification.NotificationView.recipients` methods
+ are used to build the email's subject and
+ recipients. :class:`NotificationView` provides default implementation for both
+ methods.
+
+* write a hook for event that should trigger this notification, select the view
+ (without rendering it), and give it to
+ :func:`cubicweb.hooks.notification.notify_on_commit` so that the notification
+ will be sent if the transaction succeed.
+
+
+.. XXX explain recipient finder and provide example
+
+API details
+~~~~~~~~~~~
+.. autoclass:: cubicweb.sobjects.notification.NotificationView
+.. autofunction:: cubicweb.hooks.notification.notify_on_commit
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/repo/sessions.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,318 @@
+.. -*- coding: utf-8 -*-
+
+Sessions
+========
+
+Sessions are objects linked to an authenticated user. The `Session.new_cnx`
+method returns a new Connection linked to that session.
+
+Connections
+===========
+
+Connections provide the `.execute` method to query the data sources, along with
+`.commit` and `.rollback` methods for transaction management.
+
+Kinds of connections
+--------------------
+
+There are two kinds of connections.
+
+* `normal connections` are the most common: they are related to users and
+ carry security checks coming with user credentials
+
+* `internal connections` have all the powers; they are also used in only a
+ few situations where you don't already have an adequate session at
+ hand, like: user authentication, data synchronisation in
+ multi-source contexts
+
+Normal connections are typically named `_cw` in most appobjects or
+sometimes just `session`.
+
+Internal connections are available from the `Repository` object and are
+to be used like this:
+
+.. sourcecode:: python
+
+ with self.repo.internal_cnx() as cnx:
+ do_stuff_with(cnx)
+ cnx.commit()
+
+Connections should always be used as context managers, to avoid leaks.
+
+
+Python/RQL API
+~~~~~~~~~~~~~~
+
+The Python API developped to interface with RQL is inspired from the standard db-api,
+but since `execute` returns its results directly, there is no `cursor` concept.
+
+.. sourcecode:: python
+
+ execute(rqlstring, args=None, build_descr=True)
+
+:rqlstring: the RQL query to execute (unicode)
+:args: if the query contains substitutions, a dictionary containing the values to use
+
+The `Connection` object owns the methods `commit` and `rollback`. You
+*should never need to use them* during the development of the web
+interface based on the *CubicWeb* framework as it determines the end
+of the transaction depending on the query execution success. They are
+however useful in other contexts such as tests or custom controllers.
+
+.. note::
+
+ If a query generates an error related to security (:exc:`Unauthorized`) or to
+ integrity (:exc:`ValidationError`), the transaction can still continue but you
+ won't be able to commit it, a rollback will be necessary to start a new
+ transaction.
+
+ Also, a rollback is automatically done if an error occurs during commit.
+
+.. note::
+
+ A :exc:`ValidationError` has a `entity` attribute. In CubicWeb,
+ this atttribute is set to the entity's eid (not a reference to the
+ entity itself).
+
+Executing RQL queries from a view or a hook
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When you're within code of the web interface, the Connection is handled by the
+request object. You should not have to access it directly, but use the
+`execute` method directly available on the request, eg:
+
+.. sourcecode:: python
+
+ rset = self._cw.execute(rqlstring, kwargs)
+
+Similarly, on the server side (eg in hooks), there is no request object (since
+you're directly inside the data-server), so you'll have to use the execute method
+of the Connection object.
+
+Proper usage of `.execute`
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's say you want to get T which is in configuration C, this translates to:
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
+
+But it must be written in a syntax that will benefit from the use
+of a cache on the RQL server side:
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
+
+The syntax tree is built once for the "generic" RQL and can be re-used
+with a number of different eids. The rql IN operator is an exception
+to this rule.
+
+.. sourcecode:: python
+
+ self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
+ % ','.join(['foo', 'bar']))
+
+Alternatively, some of the common data related to an entity can be
+obtained from the `entity.related()` method (which is used under the
+hood by the ORM when you use attribute access notation on an entity to
+get a relation. The initial request would then be translated to:
+
+.. sourcecode:: python
+
+ entity.related('in_conf', 'object')
+
+Additionally this benefits from the fetch_attrs policy (see :ref:`FetchAttrs`)
+optionally defined on the class element, which says which attributes must be
+also loaded when the entity is loaded through the ORM.
+
+.. _resultset:
+
+The `ResultSet` API
+~~~~~~~~~~~~~~~~~~~
+
+ResultSet instances are a very commonly manipulated object. They have
+a rich API as seen below, but we would like to highlight a bunch of
+methods that are quite useful in day-to-day practice:
+
+* `__str__()` (applied by `print`) gives a very useful overview of both
+ the underlying RQL expression and the data inside; unavoidable for
+ debugging purposes
+
+* `printable_rql()` returns a well formed RQL expression as a
+ string; it is very useful to build views
+
+* `entities()` returns a generator on all entities of the result set
+
+* `get_entity(row, col)` gets the entity at row, col coordinates; one
+ of the most used result set methods
+
+.. autoclass:: cubicweb.rset.ResultSet
+ :members:
+
+
+Authentication and management of sessions
+-----------------------------------------
+
+The authentication process is a ballet involving a few dancers:
+
+* through its `get_session` method the top-level application object (the
+ `CubicWebPublisher`) will open a session whenever a web request
+ comes in; it asks the `session manager` to open a session (giving
+ the web request object as context) using `open_session`
+
+ * the session manager asks its authentication manager (which is a
+ `component`) to authenticate the request (using `authenticate`)
+
+ * the authentication manager asks, in order, to its authentication
+ information retrievers, a login and an opaque object containing
+ other credentials elements (calling `authentication_information`),
+ giving the request object each time
+
+ * the default retriever (named `LoginPasswordRetriever`)
+ will in turn defer login and password fetching to the request
+ object (which, depending on the authentication mode (`cookie`
+ or `http`), will do the appropriate things and return a login
+ and a password)
+
+ * the authentication manager, on success, asks the `Repository`
+ object to connect with the found credentials (using `connect`)
+
+ * the repository object asks authentication to all of its
+ sources which support the `CWUser` entity with the given
+ credentials; when successful it can build the cwuser entity,
+ from which a regular `Session` object is made; it returns the
+ session id
+
+ * the source in turn will delegate work to an authentifier
+ class that defines the ultimate `authenticate` method (for
+ instance the native source will query the database against
+ the provided credentials)
+
+ * the authentication manager, on success, will call back _all_
+ retrievers with `authenticated` and return its authentication
+ data (on failure, it will try the anonymous login or, if the
+ configuration forbids it, raise an `AuthenticationError`)
+
+Writing authentication plugins
+------------------------------
+
+Sometimes CubicWeb's out-of-the-box authentication schemes (cookie and
+http) are not sufficient. Nowadays there is a plethora of such schemes
+and the framework cannot provide them all, but as the sequence above
+shows, it is extensible.
+
+Two levels have to be considered when writing an authentication
+plugin: the web client and the repository.
+
+We invented a scenario where it makes sense to have a new plugin in
+each side: some middleware will do pre-authentication and under the
+right circumstances add a new HTTP `x-foo-user` header to the query
+before it reaches the CubicWeb instance. For a concrete example of
+this, see the `trustedauth`_ cube.
+
+.. _`trustedauth`: http://www.cubicweb.org/project/cubicweb-trustedauth
+
+Repository authentication plugins
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On the repository side, it is possible to register a source
+authentifier using the following kind of code:
+
+.. sourcecode:: python
+
+ from cubicweb.server.sources import native
+
+ class FooAuthentifier(native.LoginPasswordAuthentifier):
+ """ a source authentifier plugin
+ if 'foo' in authentication information, no need to check
+ password
+ """
+ auth_rql = 'Any X WHERE X is CWUser, X login %(login)s'
+
+ def authenticate(self, session, login, **kwargs):
+ """return CWUser eid for the given login
+ if this account is defined in this source,
+ else raise `AuthenticationError`
+ """
+ session.debug('authentication by %s', self.__class__.__name__)
+ if 'foo' not in kwargs:
+ return super(FooAuthentifier, self).authenticate(session, login, **kwargs)
+ try:
+ rset = session.execute(self.auth_rql, {'login': login})
+ return rset[0][0]
+ except Exception, exc:
+ session.debug('authentication failure (%s)', exc)
+ raise AuthenticationError('foo user is unknown to us')
+
+Since repository authentifiers are not appobjects, we have to register
+them through a `server_startup` hook.
+
+.. sourcecode:: python
+
+ class ServerStartupHook(hook.Hook):
+ """ register the foo authenticator """
+ __regid__ = 'fooauthenticatorregisterer'
+ events = ('server_startup',)
+
+ def __call__(self):
+ self.debug('registering foo authentifier')
+ self.repo.system_source.add_authentifier(FooAuthentifier())
+
+Web authentication plugins
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. sourcecode:: python
+
+ class XFooUserRetriever(authentication.LoginPasswordRetriever):
+ """ authenticate by the x-foo-user http header
+ or just do normal login/password authentication
+ """
+ __regid__ = 'x-foo-user'
+ order = 0
+
+ def authentication_information(self, req):
+ """retrieve authentication information from the given request, raise
+ NoAuthInfo if expected information is not found
+ """
+ self.debug('web authenticator building auth info')
+ try:
+ login = req.get_header('x-foo-user')
+ if login:
+ return login, {'foo': True}
+ else:
+ return super(XFooUserRetriever, self).authentication_information(self, req)
+ except Exception, exc:
+ self.debug('web authenticator failed (%s)', exc)
+ raise authentication.NoAuthInfo()
+
+ def authenticated(self, retriever, req, cnx, login, authinfo):
+ """callback when return authentication information have opened a
+ repository connection successfully. Take care req has no session
+ attached yet, hence req.execute isn't available.
+
+ Here we set a flag on the request to indicate that the user is
+ foo-authenticated. Can be used by a selector
+ """
+ self.debug('web authenticator running post authentication callback')
+ cnx.foo_user = authinfo.get('foo')
+
+In the `authenticated` method we add (in an admitedly slightly hackish
+way) an attribute to the connection object. This, in turn, can be used
+to build a selector dispatching on the fact that the user was
+preauthenticated or not.
+
+.. sourcecode:: python
+
+ @objectify_selector
+ def foo_authenticated(cls, req, rset=None, **kwargs):
+ if hasattr(req.cnx, 'foo_user') and req.foo_user:
+ return 1
+ return 0
+
+Full Session and Connection API
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: cubicweb.server.session.Session
+.. autoclass:: cubicweb.server.session.Connection
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/repo/tasks.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,9 @@
+.. -*- coding: utf-8 -*-
+
+Tasks
+=========
+
+[WRITE ME]
+
+* repository tasks
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/testing.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,559 @@
+.. -*- coding: utf-8 -*-
+
+Tests
+=====
+
+Unit tests
+----------
+
+The *CubicWeb* framework provides the
+:class:`cubicweb.devtools.testlib.CubicWebTC` test base class .
+
+Tests shall be put into the mycube/test directory. Additional test
+data shall go into mycube/test/data.
+
+It is much advised to write tests concerning entities methods,
+actions, hooks and operations, security. The
+:class:`~cubicweb.devtools.testlib.CubicWebTC` base class has
+convenience methods to help test all of this.
+
+In the realm of views, automatic tests check that views are valid
+XHTML. See :ref:`automatic_views_tests` for details.
+
+Most unit tests need a live database to work against. This is achieved
+by CubicWeb using automatically sqlite (bundled with Python, see
+http://docs.python.org/library/sqlite3.html) as a backend.
+
+The database is stored in the mycube/test/tmpdb,
+mycube/test/tmpdb-template files. If it does not (yet) exist, it will
+be built automatically when the test suite starts.
+
+.. warning::
+
+ Whenever the schema changes (new entities, attributes, relations)
+ one must delete these two files. Changes concerned only with entity
+ or relation type properties (constraints, cardinalities,
+ permissions) and generally dealt with using the
+ `sync_schema_props_perms()` function of the migration environment do
+ not need a database regeneration step.
+
+.. _hook_test:
+
+Unit test by example
+````````````````````
+
+We start with an example extracted from the keyword cube (available
+from http://www.cubicweb.org/project/cubicweb-keyword).
+
+.. sourcecode:: python
+
+ from cubicweb.devtools.testlib import CubicWebTC
+ from cubicweb import ValidationError
+
+ class ClassificationHooksTC(CubicWebTC):
+
+ def setup_database(self):
+ with self.admin_access.repo_cnx() as cnx:
+ group_etype = cnx.find('CWEType', name='CWGroup').one()
+ c1 = cnx.create_entity('Classification', name=u'classif1',
+ classifies=group_etype)
+ user_etype = cnx.find('CWEType', name='CWUser').one()
+ c2 = cnx.create_entity('Classification', name=u'classif2',
+ classifies=user_etype)
+ self.kw1eid = cnx.create_entity('Keyword', name=u'kwgroup', included_in=c1).eid
+ cnx.commit()
+
+ def test_cannot_create_cycles(self):
+ with self.admin_access.repo_cnx() as cnx:
+ kw1 = cnx.entity_from_eid(self.kw1eid)
+ # direct obvious cycle
+ with self.assertRaises(ValidationError):
+ kw1.cw_set(subkeyword_of=kw1)
+ cnx.rollback()
+ # testing indirect cycles
+ kw3 = cnx.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
+ 'SK subkeyword_of K WHERE C name "classif1", K eid %(k)s'
+ {'k': kw1}).get_entity(0,0)
+ kw3.cw_set(reverse_subkeyword_of=kw1)
+ self.assertRaises(ValidationError, cnx.commit)
+
+The test class defines a :meth:`setup_database` method which populates the
+database with initial data. Each test of the class runs with this
+pre-populated database.
+
+The test case itself checks that an Operation does its job of
+preventing cycles amongst Keyword entities.
+
+The `create_entity` method of connection (or request) objects allows
+to create an entity. You can link this entity to other entities, by
+specifying as argument, the relation name, and the entity to link, as
+value. In the above example, the `Classification` entity is linked to
+a `CWEtype` via the relation `classifies`. Conversely, if you are
+creating a `CWEtype` entity, you can link it to a `Classification`
+entity, by adding `reverse_classifies` as argument.
+
+.. note::
+
+ the :meth:`commit` method is not called automatically. You have to
+ call it explicitly if needed (notably to test operations). It is a
+ good practice to regenerate entities with :meth:`entity_from_eid`
+ after a commit to avoid request cache effects.
+
+You can see an example of security tests in the
+:ref:`adv_tuto_security`.
+
+It is possible to have these tests run continuously using `apycot`_.
+
+.. _apycot: http://www.cubicweb.org/project/apycot
+
+.. _securitytest:
+
+Managing connections or users
++++++++++++++++++++++++++++++
+
+Since unit tests are done with the SQLITE backend and this does not
+support multiple connections at a time, you must be careful when
+simulating security, changing users.
+
+By default, tests run with a user with admin privileges. Connections
+using these credentials are accessible through the `admin_access` object
+of the test classes.
+
+The `repo_cnx()` method returns a connection object that can be used as a
+context manager:
+
+.. sourcecode:: python
+
+ # admin_access is a pre-cooked session wrapping object
+ # it is built with:
+ # self.admin_access = self.new_access('admin')
+ with self.admin_access.repo_cnx() as cnx:
+ cnx.execute(...)
+ self.create_user(cnx, login='user1')
+ cnx.commit()
+
+ user1access = self.new_access('user1')
+ with user1access.web_request() as req:
+ req.execute(...)
+ req.cnx.commit()
+
+On exit of the context manager, a rollback is issued, which releases
+the connection. Don't forget to issue the `cnx.commit()` calls!
+
+.. warning::
+
+ Do not use references kept to the entities created with a
+ connection from another one!
+
+Email notifications tests
+`````````````````````````
+
+When running tests, potentially generated e-mails are not really sent
+but are found in the list `MAILBOX` of module
+:mod:`cubicweb.devtools.testlib`.
+
+You can test your notifications by analyzing the contents of this list, which
+contains objects with two attributes:
+
+* `recipients`, the list of recipients
+* `msg`, email.Message object
+
+Let us look at a simple example from the ``blog`` cube.
+
+.. sourcecode:: python
+
+ from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
+
+ class BlogTestsCubicWebTC(CubicWebTC):
+ """test blog specific behaviours"""
+
+ def test_notifications(self):
+ with self.admin_access.web_request() as req:
+ cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
+ description=u'cubicweb is beautiful')
+ blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
+ content=u'cubicweb hop')
+ blog_entry_1.cw_set(entry_of=cubicweb_blog)
+ blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
+ content=u'cubicweb yes')
+ blog_entry_2.cw_set(entry_of=cubicweb_blog)
+ self.assertEqual(len(MAILBOX), 0)
+ req.cnx.commit()
+ self.assertEqual(len(MAILBOX), 2)
+ mail = MAILBOX[0]
+ self.assertEqual(mail.subject, '[data] hop')
+ mail = MAILBOX[1]
+ self.assertEqual(mail.subject, '[data] yes')
+
+Visible actions tests
+`````````````````````
+
+It is easy to write unit tests to test actions which are visible to
+a user or to a category of users. Let's take an example in the
+`conference cube`_.
+
+.. _`conference cube`: http://www.cubicweb.org/project/cubicweb-conference
+.. sourcecode:: python
+
+ class ConferenceActionsTC(CubicWebTC):
+
+ def setup_database(self):
+ with self.admin_access.repo_cnx() as cnx:
+ self.confeid = cnx.create_entity('Conference',
+ title=u'my conf',
+ url_id=u'conf',
+ start_on=date(2010, 1, 27),
+ end_on = date(2010, 1, 29),
+ call_open=True,
+ reverse_is_chair_at=chair,
+ reverse_is_reviewer_at=reviewer).eid
+
+ def test_admin(self):
+ with self.admin_access.web_request() as req:
+ rset = req.find('Conference').one()
+ self.assertListEqual(self.pactions(req, rset),
+ [('workflow', workflow.WorkflowActions),
+ ('edit', confactions.ModifyAction),
+ ('managepermission', actions.ManagePermissionsAction),
+ ('addrelated', actions.AddRelatedActions),
+ ('delete', actions.DeleteAction),
+ ('generate_badge_action', badges.GenerateBadgeAction),
+ ('addtalkinconf', confactions.AddTalkInConferenceAction)
+ ])
+ self.assertListEqual(self.action_submenu(req, rset, 'addrelated'),
+ [(u'add Track in_conf Conference object',
+ u'http://testing.fr/cubicweb/add/Track'
+ u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&'
+ u'__redirectpath=conference%%2Fconf&'
+ u'__redirectvid=' % {'conf': self.confeid}),
+ ])
+
+You just have to execute a rql query corresponding to the view you want to test,
+and to compare the result of
+:meth:`~cubicweb.devtools.testlib.CubicWebTC.pactions` with the list of actions
+that must be visible in the interface. This is a list of tuples. The first
+element is the action's `__regid__`, the second the action's class.
+
+To test actions in a submenu, you just have to test the result of
+:meth:`~cubicweb.devtools.testlib.CubicWebTC.action_submenu` method. The last
+parameter of the method is the action's category. The result is a list of
+tuples. The first element is the action's title, and the second element the
+action's url.
+
+
+.. _automatic_views_tests:
+
+Automatic views testing
+-----------------------
+
+This is done automatically with the :class:`cubicweb.devtools.testlib.AutomaticWebTest`
+class. At cube creation time, the mycube/test/test_mycube.py file
+contains such a test. The code here has to be uncommented to be
+usable, without further modification.
+
+The ``auto_populate`` method uses a smart algorithm to create
+pseudo-random data in the database, thus enabling the views to be
+invoked and tested.
+
+Depending on the schema, hooks and operations constraints, it is not
+always possible for the automatic auto_populate to proceed.
+
+It is possible of course to completely redefine auto_populate. A
+lighter solution is to give hints (fill some class attributes) about
+what entities and relations have to be skipped by the auto_populate
+mechanism. These are:
+
+* `no_auto_populate`, may contain a list of entity types to skip
+* `ignored_relations`, may contain a list of relation types to skip
+* `application_rql`, may contain a list of rql expressions that
+ auto_populate cannot guess by itself; these must yield resultsets
+ against which views may be selected.
+
+.. warning::
+
+ Take care to not let the imported `AutomaticWebTest` in your test module
+ namespace, else both your subclass *and* this parent class will be run.
+
+Cache heavy database setup
+-------------------------------
+
+Some test suites require a complex setup of the database that takes
+seconds (or even minutes) to complete. Doing the whole setup for each
+individual test makes the whole run very slow. The ``CubicWebTC``
+class offer a simple way to prepare a specific database once for
+multiple tests. The `test_db_id` class attribute of your
+``CubicWebTC`` subclass must be set to a unique identifier and the
+:meth:`pre_setup_database` class method must build the cached content. As
+the :meth:`pre_setup_database` method is not garanteed to be called
+every time a test method is run, you must not set any class attribute
+to be used during test *there*. Databases for each `test_db_id` are
+automatically created if not already in cache. Clearing the cache is
+up to the user. Cache files are found in the :file:`data/database`
+subdirectory of your test directory.
+
+.. warning::
+
+ Take care to always have the same :meth:`pre_setup_database`
+ function for all classes with a given `test_db_id` otherwise your
+ tests will have unpredictable results depending on the first
+ encountered one.
+
+
+Testing on a real-life database
+-------------------------------
+
+The ``CubicWebTC`` class uses the `cubicweb.devtools.ApptestConfiguration`
+configuration class to setup its testing environment (database driver,
+user password, application home, and so on). The `cubicweb.devtools`
+module also provides a `RealDatabaseConfiguration`
+class that will read a regular cubicweb sources file to fetch all
+this information but will also prevent the database to be initalized
+and reset between tests.
+
+For a test class to use a specific configuration, you have to set
+the `_config` class attribute on the class as in:
+
+.. sourcecode:: python
+
+ from cubicweb.devtools import RealDatabaseConfiguration
+ from cubicweb.devtools.testlib import CubicWebTC
+
+ class BlogRealDatabaseTC(CubicWebTC):
+ _config = RealDatabaseConfiguration('blog',
+ sourcefile='/path/to/realdb_sources')
+
+ def test_blog_rss(self):
+ with self.admin_access.web_request() as req:
+ rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, '
+ 'B created_by U, U login "logilab", B creation_date D')
+ self.view('rss', rset, req=req)
+
+
+Testing with other cubes
+------------------------
+
+Sometimes a small component cannot be tested all by itself, so one
+needs to specify other cubes to be used as part of the the unit test
+suite. This is handled by the ``bootstrap_cubes`` file located under
+``mycube/test/data``. One example from the `preview` cube::
+
+ card, file, preview
+
+The format is:
+
+* possibly several empy lines or lines starting with ``#`` (comment lines)
+* one line containing a comma-separated list of cube names.
+
+It is also possible to add a ``schema.py`` file in
+``mycube/test/data``, which will be used by the testing framework,
+therefore making new entity types and relations available to the
+tests.
+
+Literate programming
+--------------------
+
+CubicWeb provides some literate programming capabilities. The :ref:`cubicweb-ctl`
+`shell` command accepts different file formats. If your file ends with `.txt`
+or `.rst`, the file will be parsed by :mod:`doctest.testfile` with CubicWeb's
+:ref:`migration` API enabled in it.
+
+Create a `scenario.txt` file in the `test/` directory and fill with some content.
+Refer to the :mod:`doctest.testfile` `documentation`_.
+
+.. _documentation: http://docs.python.org/library/doctest.html
+
+Then, you can run it directly by::
+
+ $ cubicweb-ctl shell <cube_instance> test/scenario.txt
+
+When your scenario file is ready, put it in a new test case to be able to run
+it automatically.
+
+.. sourcecode:: python
+
+ from os.path import dirname, join
+ from logilab.common.testlib import unittest_main
+ from cubicweb.devtools.testlib import CubicWebTC
+
+ class AcceptanceTC(CubicWebTC):
+
+ def test_scenario(self):
+ self.assertDocTestFile(join(dirname(__file__), 'scenario.txt'))
+
+ if __name__ == '__main__':
+ unittest_main()
+
+Skipping a scenario
+```````````````````
+
+If you want to set up initial conditions that you can't put in your unit test
+case, you have to use a :exc:`KeyboardInterrupt` exception only because of the
+way :mod:`doctest` module will catch all the exceptions internally.
+
+ >>> if condition_not_met:
+ ... raise KeyboardInterrupt('please, check your fixture.')
+
+Passing paramaters
+``````````````````
+Using extra arguments to parametrize your scenario is possible by prepending them
+by double dashes.
+
+Please refer to the `cubicweb-ctl shell --help` usage.
+
+.. important::
+ Your scenario file must be utf-8 encoded.
+
+Test APIS
+---------
+
+Using Pytest
+````````````
+
+The `pytest` utility (shipping with `logilab-common`_, which is a
+mandatory dependency of CubicWeb) extends the Python unittest
+functionality and is the preferred way to run the CubicWeb test
+suites. Bare unittests also work the usual way.
+
+.. _logilab-common: http://www.logilab.org/project/logilab-common
+
+To use it, you may:
+
+* just launch `pytest` in your cube to execute all tests (it will
+ discover them automatically)
+* launch `pytest unittest_foo.py` to execute one test file
+* launch `pytest unittest_foo.py bar` to execute all test methods and
+ all test cases whose name contains `bar`
+
+Additionally, the `-x` option tells pytest to exit at the first error
+or failure. The `-i` option tells pytest to drop into pdb whenever an
+exception occurs in a test.
+
+When the `-x` option has been used and the run stopped on a test, it
+is possible, after having fixed the test, to relaunch pytest with the
+`-R` option to tell it to start testing again from where it previously
+failed.
+
+Using the `TestCase` base class
+```````````````````````````````
+
+The base class of CubicWebTC is logilab.common.testlib.TestCase, which
+provides a lot of convenient assertion methods.
+
+.. autoclass:: logilab.common.testlib.TestCase
+ :members:
+
+CubicWebTC API
+``````````````
+.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
+ :members:
+
+
+What you need to know about request and session
+-----------------------------------------------
+
+.. image:: ../images/request_session.png
+
+First, remember to think that some code run on a client side, some
+other on the repository side. More precisely:
+
+* client side: web interface, raw repoapi connection (cubicweb-ctl shell for
+ instance);
+
+* repository side: RQL query execution, that may trigger hooks and operation.
+
+The client interacts with the repository through a repoapi connection.
+
+
+.. note::
+
+ These distinctions are going to disappear in cubicweb 3.21 (if not
+ before).
+
+A repoapi connection is tied to a session in the repository. The connection and
+request objects are inaccessible from repository code / the session object is
+inaccessible from client code (theoretically at least).
+
+The web interface provides a request class. That `request` object provides
+access to all cubicweb resources, eg:
+
+* the registry (which itself provides access to the schema and the
+ configuration);
+
+* an underlying repoapi connection (when using req.execute, you actually call the
+ repoapi);
+
+* other specific resources depending on the client type (url generation according
+ to base url, form parameters, etc.).
+
+
+A `session` provides an api similar to a request regarding RQL execution and
+access to global resources (registry and all), but also has the following
+responsibilities:
+
+* handle transaction data, that will live during the time of a single
+ transaction. This includes the database connections that will be used to
+ execute RQL queries.
+
+* handle persistent data that may be used across different (web) requests
+
+* security and hooks control (not possible through a request)
+
+
+The `_cw` attribute
+```````````````````
+The `_cw` attribute available on every application object provides access to all
+cubicweb resources, i.e.:
+
+- For code running on the client side (eg web interface view), `_cw` is a request
+ instance.
+
+- For code running on the repository side (hooks and operation), `_cw` is a
+ Connection or Session instance.
+
+
+Beware some views may be called with a session (e.g. notifications) or with a
+request.
+
+
+Request, session and transaction
+````````````````````````````````
+
+In the web interface, an HTTP request is handled by a single request, which will
+be thrown away once the response is sent.
+
+The web publisher handles the transaction:
+
+* commit / rollback is done automatically
+
+* you should not commit / rollback explicitly, except if you really
+ need it
+
+Let's detail the process:
+
+1. an incoming RQL query comes from a client to the web stack
+
+2. the web stack opens an authenticated database connection for the
+ request, which is associated to a user session
+
+3. the query is executed (through the repository connection)
+
+4. this query may trigger hooks. Hooks and operations may execute some rql queries
+ through `cnx.execute`.
+
+5. the repository gets the result of the query in 1. If it was a RQL read query,
+ the database connection is released. If it was a write query, the connection
+ is then tied to the session until the transaction is commited or rolled back.
+
+6. results are sent back to the client
+
+This implies several things:
+
+* when using a request, or code executed in hooks, this database
+ connection handling is totally transparent
+
+* however, take care when writing tests: you are usually faking /
+ testing both the server and the client side, so you have to decide
+ when to use RepoAccess.client_cnx or RepoAccess.repo_cnx. Ask
+ yourself "where will the code I want to test be running, client or
+ repository side?". The response is usually: use a repo (since the
+ "client connection" concept is going away in a couple of releases).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devrepo/vreg.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,119 @@
+The Registry, selectors and application objects
+===============================================
+
+This chapter deals with some of the core concepts of the |cubicweb| framework
+which make it different from other frameworks (and maybe not easy to
+grasp at a first glance). To be able to do advanced development with
+|cubicweb| you need a good understanding of what is explained below.
+
+This chapter goes deep into details. You don't have to remember them
+all but keep it in mind so you can go back there later.
+
+An overview of AppObjects, the VRegistry and Selectors is given in the
+:ref:`VRegistryIntro` chapter.
+
+.. autodocstring:: cubicweb.cwvreg
+.. autodocstring:: cubicweb.predicates
+.. automodule:: cubicweb.appobject
+
+Base predicates
+---------------
+
+Predicates are scoring functions that are called by the registry to tell whenever
+an appobject can be selected in a given context. Predicates may be chained
+together using operators to build a selector. A selector is the glue that tie
+views to the data model or whatever input context. Using them appropriately is an
+essential part of the construction of well behaved cubes.
+
+Of course you may have to write your own set of predicates as your needs grows
+and you get familiar with the framework (see :ref:`CustomPredicates`).
+
+Here is a description of generic predicates provided by CubicWeb that should suit
+most of your needs.
+
+Bare predicates
+~~~~~~~~~~~~~~~
+Those predicates are somewhat dumb, which doesn't mean they're not (very) useful.
+
+.. autoclass:: cubicweb.appobject.yes
+.. autoclass:: cubicweb.predicates.match_kwargs
+.. autoclass:: cubicweb.predicates.appobject_selectable
+.. autoclass:: cubicweb.predicates.adaptable
+.. autoclass:: cubicweb.predicates.configuration_values
+
+
+Result set predicates
+~~~~~~~~~~~~~~~~~~~~~
+Those predicates are looking for a result set in the context ('rset' argument or
+the input context) and match or not according to its shape. Some of these
+predicates have different behaviour if a particular cell of the result set is
+specified using 'row' and 'col' arguments of the input context or not.
+
+.. autoclass:: cubicweb.predicates.none_rset
+.. autoclass:: cubicweb.predicates.any_rset
+.. autoclass:: cubicweb.predicates.nonempty_rset
+.. autoclass:: cubicweb.predicates.empty_rset
+.. autoclass:: cubicweb.predicates.one_line_rset
+.. autoclass:: cubicweb.predicates.multi_lines_rset
+.. autoclass:: cubicweb.predicates.multi_columns_rset
+.. autoclass:: cubicweb.predicates.paginated_rset
+.. autoclass:: cubicweb.predicates.sorted_rset
+.. autoclass:: cubicweb.predicates.one_etype_rset
+.. autoclass:: cubicweb.predicates.multi_etypes_rset
+
+
+Entity predicates
+~~~~~~~~~~~~~~~~~
+Those predicates are looking for either an `entity` argument in the input context,
+or entity found in the result set ('rset' argument or the input context) and
+match or not according to entity's (instance or class) properties.
+
+.. autoclass:: cubicweb.predicates.non_final_entity
+.. autoclass:: cubicweb.predicates.is_instance
+.. autoclass:: cubicweb.predicates.score_entity
+.. autoclass:: cubicweb.predicates.rql_condition
+.. autoclass:: cubicweb.predicates.relation_possible
+.. autoclass:: cubicweb.predicates.partial_relation_possible
+.. autoclass:: cubicweb.predicates.has_related_entities
+.. autoclass:: cubicweb.predicates.partial_has_related_entities
+.. autoclass:: cubicweb.predicates.has_permission
+.. autoclass:: cubicweb.predicates.has_add_permission
+.. autoclass:: cubicweb.predicates.has_mimetype
+.. autoclass:: cubicweb.predicates.is_in_state
+.. autofunction:: cubicweb.predicates.on_fire_transition
+
+
+Logged user predicates
+~~~~~~~~~~~~~~~~~~~~~~
+Those predicates are looking for properties of the user issuing the request.
+
+.. autoclass:: cubicweb.predicates.match_user_groups
+
+
+Web request predicates
+~~~~~~~~~~~~~~~~~~~~~~
+Those predicates are looking for properties of *web* request, they can not be
+used on the data repository side.
+
+.. autoclass:: cubicweb.predicates.no_cnx
+.. autoclass:: cubicweb.predicates.anonymous_user
+.. autoclass:: cubicweb.predicates.authenticated_user
+.. autoclass:: cubicweb.predicates.match_form_params
+.. autoclass:: cubicweb.predicates.match_search_state
+.. autoclass:: cubicweb.predicates.match_context_prop
+.. autoclass:: cubicweb.predicates.match_context
+.. autoclass:: cubicweb.predicates.match_view
+.. autoclass:: cubicweb.predicates.primary_view
+.. autoclass:: cubicweb.predicates.contextual
+.. autoclass:: cubicweb.predicates.specified_etype_implements
+.. autoclass:: cubicweb.predicates.attribute_edited
+.. autoclass:: cubicweb.predicates.match_transition
+
+
+Other predicates
+~~~~~~~~~~~~~~~~
+.. autoclass:: cubicweb.predicates.match_exception
+.. autoclass:: cubicweb.predicates.debug_mode
+
+You'll also find some other (very) specific predicates hidden in other modules
+than :mod:`cubicweb.predicates`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/ajax.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,12 @@
+.. _ajax:
+
+Ajax
+----
+
+CubicWeb provides a few helpers to facilitate *javascript <-> python* communications.
+
+You can, for instance, register some python functions that will become
+callable from javascript through ajax calls. All the ajax URLs are handled
+by the :class:`cubicweb.web.views.ajaxcontroller.AjaxController` controller.
+
+.. automodule:: cubicweb.web.views.ajaxcontroller
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/controllers.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,93 @@
+.. _controllers:
+
+Controllers
+-----------
+
+Overview
+++++++++
+
+Controllers are responsible for taking action upon user requests
+(loosely following the terminology of the MVC meta pattern).
+
+The following controllers are provided out-of-the box in CubicWeb. We
+list them by category. They are all defined in
+(:mod:`cubicweb.web.views.basecontrollers`).
+
+`Browsing`:
+
+* the View controller is associated with most browsing actions within a
+ CubicWeb application: it always instantiates a
+ :ref:`the_main_template_layout` and lets the ResultSet/Views dispatch system
+ build up the whole content; it handles :exc:`ObjectNotFound` and
+ :exc:`NoSelectableObject` errors that may bubble up to its entry point, in an
+ end-user-friendly way (but other programming errors will slip through)
+
+* the JSonpController is a wrapper around the ``ViewController`` that
+ provides jsonp_ services. Padding can be specified with the
+ ``callback`` request parameter. Only *jsonexport* / *ejsonexport*
+ views can be used. If another ``vid`` is specified, it will be
+ ignored and replaced by *jsonexport*. Request is anonymized
+ to avoid returning sensitive data and reduce the risks of CSRF attacks;
+
+* the Login/Logout controllers make effective user login or logout
+ requests
+
+
+.. _jsonp: http://en.wikipedia.org/wiki/JSONP
+
+`Edition`:
+
+* the Edit controller (see :ref:`edit_controller`) handles CRUD
+ operations in response to a form being submitted; it works in close
+ association with the Forms, to which it delegates some of the work
+
+* the ``Form validator controller`` provides form validation from Ajax
+ context, using the Edit controller, to implement the classic form
+ handling loop (user edits, hits `submit/apply`, validation occurs
+ server-side by way of the Form validator controller, and the UI is
+ decorated with failure information, either global or per-field ,
+ until it is valid)
+
+`Other`:
+
+* the ``SendMail controller`` (web/views/basecontrollers.py) is reponsible
+ for outgoing email notifications
+
+* the MailBugReport controller (web/views/basecontrollers.py) allows
+ to quickly have a `reportbug` feature in one's application
+
+* the :class:`cubicweb.web.views.ajaxcontroller.AjaxController`
+ (:mod:`cubicweb.web.views.ajaxcontroller`) provides
+ services for Ajax calls, typically using JSON as a serialization format
+ for input, and sometimes using either JSON or XML for output. See
+ :ref:`ajax` chapter for more information.
+
+
+Registration
+++++++++++++
+
+All controllers (should) live in the 'controllers' namespace within
+the global registry.
+
+Concrete controllers
+++++++++++++++++++++
+
+Most API details should be resolved by source code inspection, as the
+various controllers have differing goals. See for instance the
+:ref:`edit_controller` chapter.
+
+:mod:`cubicweb.web.controller` contains the top-level abstract
+Controller class and its unimplemented entry point
+`publish(rset=None)` method.
+
+A handful of helpers are also provided there:
+
+* process_rql builds a result set from an rql query typically issued
+ from the browser (and available through _cw.form['rql'])
+
+* validate_cache will force cache validation handling with respect to
+ the HTTP Cache directives (that were typically originally issued
+ from a previous server -> client response); concrete Controller
+ implementations dealing with HTTP (thus, for instance, not the
+ SendMail controller) may very well call this in their publication
+ process.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/css.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,30 @@
+.. -*- coding: utf-8 -*-
+
+CSS Stylesheet
+---------------
+Conventions
+~~~~~~~~~~~
+
+.. XXX external_resources variable
+.. naming convention
+.. request.add_css
+
+
+Extending / overriding existing styles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We cannot modify the order in which the application is reading the CSS. In
+the case we want to create new CSS style, the best is to define it a in a new
+CSS located under ``myapp/data/`` and use those new styles while writing
+customized views and templates.
+
+If you want to modify an existing CSS styling property, you will have to use
+``!important`` declaration to override the existing property. The application
+apply a higher priority on the default CSS and you can not change that.
+Customized CSS will not be read first.
+
+
+CubicWeb stylesheets
+~~~~~~~~~~~~~~~~~~~~
+
+.. XXX explain diffenrent files and main classes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/edition/dissection.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,316 @@
+
+.. _form_dissection:
+
+Dissection of an entity form
+----------------------------
+
+This is done (again) with a vanilla instance of the `tracker`_
+cube. We will populate the database with a bunch of entities and see
+what kind of job the automatic entity form does.
+
+.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker
+
+Populating the database
+~~~~~~~~~~~~~~~~~~~~~~~
+
+We should start by setting up a bit of context: a project with two
+unpublished versions, and a ticket linked to the project and the first
+version.
+
+.. sourcecode:: python
+
+ >>> p = rql('INSERT Project P: P name "cubicweb"')
+ >>> for num in ('0.1.0', '0.2.0'):
+ ... rql('INSERT Version V: V num "%s", V version_of P WHERE P eid %%(p)s' % num, {'p': p[0][0]})
+ ...
+ <resultset 'INSERT Version V: V num "0.1.0", V version_of P WHERE P eid %(p)s' (1 rows): [765L] (('Version',))>
+ <resultset 'INSERT Version V: V num "0.2.0", V version_of P WHERE P eid %(p)s' (1 rows): [766L] (('Version',))>
+ >>> t = rql('INSERT Ticket T: T title "let us write more doc", T done_in V, '
+ 'T concerns P WHERE V num "0.1.0"', P eid %(p)s', {'p': p[0][0]})
+ >>> commit()
+
+Now let's see what the edition form builds for us.
+
+.. sourcecode:: python
+
+ >>> cnx.use_web_compatible_requests('http://fakeurl.com')
+ >>> req = cnx.request()
+ >>> form = req.vreg['forms'].select('edition', req, rset=rql('Ticket T'))
+ >>> html = form.render()
+
+.. note::
+
+ In order to play interactively with web side application objects, we have to
+ cheat a bit to have request object that will looks like HTTP request object, by
+ calling :meth:`use_web_compatible_requests()` on the connection.
+
+This creates an automatic entity form. The ``.render()`` call yields
+an html (unicode) string. The html output is shown below (with
+internal fieldset omitted).
+
+Looking at the html output
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The form enveloppe
+''''''''''''''''''
+
+.. sourcecode:: html
+
+ <div class="iformTitle"><span>main informations</span></div>
+ <div class="formBody">
+ <form action="http://crater:9999/validateform" method="post" enctype="application/x-www-form-urlencoded"
+ id="entityForm" onsubmit="return freezeFormButtons('entityForm');"
+ class="entityForm" target="eformframe">
+ <div id="progress">validating...</div>
+ <fieldset>
+ <input name="__form_id" type="hidden" value="edition" />
+ <input name="__errorurl" type="hidden" value="http://perdu.com#entityForm" />
+ <input name="__domid" type="hidden" value="entityForm" />
+ <input name="__type:763" type="hidden" value="Ticket" />
+ <input name="eid" type="hidden" value="763" />
+ <input name="__maineid" type="hidden" value="763" />
+ <input name="_cw_edited_fields:763" type="hidden"
+ value="concerns-subject,done_in-subject,priority-subject,type-subject,title-subject,description-subject,__type,_cw_generic_field" />
+ ...
+ </fieldset>
+ <iframe width="0px" height="0px" name="eformframe" id="eformframe" src="javascript: void(0);"></iframe>
+ </form>
+ </div>
+
+The main fieldset encloses a set of hidden fields containing various
+metadata, that will be used by the `edit controller` to process it
+back correctly.
+
+The `freezeFormButtons(...)` javascript callback defined on the
+``onlick`` event of the form element prevents accidental multiple
+clicks in a row.
+
+The ``action`` of the form is mapped to the ``validateform`` controller
+(situated in :mod:`cubicweb.web.views.basecontrollers`).
+
+A full explanation of the validation loop is given in
+:ref:`validation_process`.
+
+.. _attributes_section:
+
+The attributes section
+''''''''''''''''''''''
+
+We can have a look at some of the inner nodes of the form. Some fields
+are omitted as they are redundant for our purposes.
+
+.. sourcecode:: html
+
+ <fieldset class="default">
+ <table class="attributeForm">
+ <tr class="title_subject_row">
+ <th class="labelCol"><label class="required" for="title-subject:763">title</label></th>
+ <td>
+ <input id="title-subject:763" maxlength="128" name="title-subject:763" size="45"
+ tabindex="1" type="text" value="let us write more doc" />
+ </td>
+ </tr>
+ ... (description field omitted) ...
+ <tr class="priority_subject_row">
+ <th class="labelCol"><label class="required" for="priority-subject:763">priority</label></th>
+ <td>
+ <select id="priority-subject:763" name="priority-subject:763" size="1" tabindex="4">
+ <option value="important">important</option>
+ <option selected="selected" value="normal">normal</option>
+ <option value="minor">minor</option>
+ </select>
+ <div class="helper">importance</div>
+ </td>
+ </tr>
+ ... (type field omitted) ...
+ <tr class="concerns_subject_row">
+ <th class="labelCol"><label class="required" for="concerns-subject:763">concerns</label></th>
+ <td>
+ <select id="concerns-subject:763" name="concerns-subject:763" size="1" tabindex="6">
+ <option selected="selected" value="760">Foo</option>
+ </select>
+ </td>
+ </tr>
+ <tr class="done_in_subject_row">
+ <th class="labelCol"><label for="done_in-subject:763">done in</label></th>
+ <td>
+ <select id="done_in-subject:763" name="done_in-subject:763" size="1" tabindex="7">
+ <option value="__cubicweb_internal_field__"></option>
+ <option selected="selected" value="761">Foo 0.1.0</option>
+ <option value="762">Foo 0.2.0</option>
+ </select>
+ <div class="helper">version in which this ticket will be / has been done</div>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+
+Note that the whole form layout has been computed by the form
+renderer. It is the renderer which produces the table
+structure. Otherwise, the fields html structure is emitted by their
+associated widget.
+
+While it is called the `attributes` section of the form, it actually
+contains attributes and *mandatory relations*. For each field, we
+observe:
+
+* a dedicated row with a specific class, such as ``title_subject_row``
+ (responsability of the form renderer)
+
+* an html widget (input, select, ...) with:
+
+ * an id built from the ``rtype-role:eid`` pattern
+
+ * a name built from the same pattern
+
+ * possible values or preselected options
+
+The relations section
+'''''''''''''''''''''
+
+.. sourcecode:: html
+
+ <fieldset class="This ticket :">
+ <legend>This ticket :</legend>
+ <table class="attributeForm">
+ <tr class="_cw_generic_field_None_row">
+ <td colspan="2">
+ <table id="relatedEntities">
+ <tr><th> </th><td> </td></tr>
+ <tr id="relationSelectorRow_763" class="separator">
+ <th class="labelCol">
+ <select id="relationSelector_763" tabindex="8"
+ onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,763);">
+ <option value="">select a relation</option>
+ <option value="appeared_in_subject">appeared in</option>
+ <option value="custom_workflow_subject">custom workflow</option>
+ <option value="depends_on_object">dependency of</option>
+ <option value="depends_on_subject">depends on</option>
+ <option value="identical_to_subject">identical to</option>
+ <option value="see_also_subject">see also</option>
+ </select>
+ </th>
+ <td id="unrelatedDivs_763"></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+The optional relations are grouped into a drop-down combo
+box. Selection of an item triggers a javascript function which will:
+
+* show already related entities in the div of id `relatedentities`
+ using a two-colown layout, with an action to allow deletion of
+ individual relations (there are none in this example)
+
+* provide a relation selector in the div of id `relationSelector_EID`
+ to allow the user to set up relations and trigger dynamic action on
+ the last div
+
+* fill the div of id `unrelatedDivs_EID` with a dynamically computed
+ selection widget allowing direct selection of an unrelated (but
+ relatable) entity or a switch towards the `search mode` of
+ |cubicweb| which allows full browsing and selection of an entity
+ using a dedicated action situated in the left column boxes.
+
+
+The buttons zone
+''''''''''''''''
+
+Finally comes the buttons zone.
+
+.. sourcecode:: html
+
+ <table width="100%">
+ <tbody>
+ <tr>
+ <td align="center">
+ <button class="validateButton" tabindex="9" type="submit" value="validate">
+ <img alt="OK_ICON" src="http://myapp/datafd8b5d92771209ede1018a8d5da46a37/ok.png" />
+ validate
+ </button>
+ </td>
+ <td style="align: right; width: 50%;">
+ <button class="validateButton"
+ onclick="postForm('__action_apply', 'button_apply', 'entityForm')"
+ tabindex="10" type="button" value="apply">
+ <img alt="APPLY_ICON" src="http://myapp/datafd8b5d92771209ede1018a8d5da46a37/plus.png" />
+ apply
+ </button>
+ <button class="validateButton"
+ onclick="postForm('__action_cancel', 'button_cancel', 'entityForm')"
+ tabindex="11" type="button" value="cancel">
+ <img alt="CANCEL_ICON" src="http://myapp/datafd8b5d92771209ede1018a8d5da46a37/cancel.png" />
+ cancel
+ </button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+The most notable artifacts here are the ``postForm(...)`` calls
+defined on click events on these buttons. This function basically
+submits the form.
+
+.. _validation_process:
+
+The form validation process
+---------------------------
+
+Validation loop
+~~~~~~~~~~~~~~~
+
+On form submission, the form.action is invoked. Basically, the
+``validateform`` controller is called and its output lands in the
+specified ``target``, an invisible ``<iframe>`` at the end of the
+form.
+
+Hence, the main page is not replaced, only the iframe contents. The
+``validateform`` controller only outputs a tiny javascript fragment
+which is then immediately executed.
+
+.. sourcecode:: html
+
+ <iframe width="0px" height="0px" name="eformframe" id="eformframe" src="javascript: void(0);">
+ <script type="text/javascript">
+ window.parent.handleFormValidationResponse('entityForm', null, null,
+ [false, [2164, {"name-subject": "required field"}], null],
+ null);
+ </script>
+ </iframe>
+
+The ``window.parent`` part ensures the javascript function is called
+on the right context (that is: the form element). We will describe its
+parameters:
+
+* first comes the form id (`entityForm`)
+
+* then two optional callbacks for the success and failure case
+
+* an array containing:
+
+ * a boolean which indicates status (success or failure), and then, on error:
+
+ * an array structured as ``[eid, {'rtype-role': 'error msg'}, ...]``
+
+ * on success:
+
+ * a url (string) representing the next thing to jump to
+
+Given the array structure described above, it is quite simple to
+manipulate the DOM to show the errors at appropriate places.
+
+Explanation
+~~~~~~~~~~~
+
+This mecanism may seem a bit overcomplicated but we have to deal with
+two realities:
+
+* in the (strict) XHTML world, there are no iframes (hence the dynamic
+ inclusion, tolerated by Firefox)
+
+* no (or not all) browser(s) support file input field handling through
+ ajax.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/edition/editcontroller.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,113 @@
+.. _edit_controller:
+
+The `edit controller`
+---------------------
+
+It can be found in (:mod:`cubicweb.web.views.editcontroller`). This
+controller processes data received from an html form to create or
+update entities.
+
+Edition handling
+~~~~~~~~~~~~~~~~
+
+The parameters related to entities to edit are specified as follows
+(first seen in :ref:`attributes_section`)::
+
+ <rtype-role>:<entity eid>
+
+where entity eid could be a letter in case of an entity to create. We
+name those parameters as *qualified*.
+
+* Retrieval of entities to edit is done by using the forms parameters
+ `eid` and `__type`
+
+* For all the attributes and the relations of an entity to edit
+ (attributes and relations are handled a bit differently but these
+ details are not much relevant here) :
+
+ * using the ``rtype``, ``role`` and ``__type`` information, fetch
+ an appropriate field instance
+
+ * check if the field has been modified (if not, proceed to the next
+ relation)
+
+ * build an rql expression to update the entity
+
+At the end, all rql expressions are executed.
+
+* For each entity to edit:
+
+ * if a qualified parameter `__linkto` is specified, its value has
+ to be a string (or a list of strings) such as: ::
+
+ <relation type>:<eids>:<target>
+
+ where <target> is either `subject` or `object` and each eid could
+ be separated from the others by a `_`. Target specifies if the
+ *edited entity* is subject or object of the relation and each
+ relation specified will be inserted.
+
+ * if a qualified parameter `__clone_eid` is specified for an entity, the
+ relations of the specified entity passed as value of this parameter are
+ copied on the edited entity.
+
+ * if a qualified parameter `__delete` is specified, its value must be
+ a string or a list of string such as follows: ::
+
+ <subjects eids>:<relation type>:<objects eids>
+
+ where each eid subject or object can be seperated from the other
+ by `_`. Each specified relation will be deleted.
+
+
+* If no entity is edited but the form contains the parameters `__linkto`
+ and `eid`, this one is interpreted by using the value specified for `eid`
+ to designate the entity on which to add the relations.
+
+.. note::
+
+ * if the parameter `__action_delete` is found, all the entities specified
+ as to be edited will be deleted.
+
+ * if the parameter `__action_cancel` is found, no action is completed.
+
+ * if the parameter `__action_apply` is found, the editing is
+ applied normally but the redirection is done on the form (see
+ :ref:`RedirectionControl`).
+
+ * if no entity is found to be edited and if there is no parameter
+ `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or
+ `__insert`, an error is raised.
+
+ * using the parameter `__message` in the form will allow to use its value
+ as a message to provide the user once the editing is completed.
+
+
+.. _RedirectionControl:
+
+Redirection control
+~~~~~~~~~~~~~~~~~~~
+Once editing is completed, there is still an issue left: where should we go
+now? If nothing is specified, the controller will do his job but it does not
+mean we will be happy with the result. We can control that by using the
+following parameters:
+
+* `__redirectpath`: path of the URL (relative to the root URL of the site,
+ no form parameters
+
+* `__redirectparams`: forms parameters to add to the path
+
+* `__redirectrql`: redirection RQL request
+
+* `__redirectvid`: redirection view identifier
+
+* `__errorurl`: initial form URL, used for redirecting in case a validation
+ error is raised during editing. If this one is not specified, an error page
+ is displayed instead of going back to the form (which is, if necessary,
+ responsible for displaying the errors)
+
+* `__form_id`: initial view form identifier, used if `__action_apply` is
+ found
+
+In general we use either `__redirectpath` and `__redirectparams` or
+`__redirectrql` and `__redirectvid`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/edition/examples.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,232 @@
+Examples
+--------
+
+(Automatic) Entity form
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Looking at some cubes available on the `cubicweb forge`_ we find some
+with form manipulation. The following example comes from the the
+`conference`_ cube. It extends the change state form for the case
+where a ``Talk`` entity is getting into ``submitted`` state. The goal
+is to select reviewers for the submitted talk.
+
+.. _`cubicweb forge`: http://www.cubicweb.org/view?rql=Any+P+ORDERBY+N+WHERE+P+name+LIKE+%22cubicweb-%25%22%2C+P+is+Project%2C+P+name+N
+.. _`conference`: http://www.cubicweb.org/project/cubicweb-conference
+
+.. sourcecode:: python
+
+ from cubicweb.web import formfields as ff, formwidgets as fwdgs
+ class SendToReviewerStatusChangeView(ChangeStateFormView):
+ __select__ = (ChangeStateFormView.__select__ &
+ is_instance('Talk') &
+ rql_condition('X in_state S, S name "submitted"'))
+
+ def get_form(self, entity, transition, **kwargs):
+ form = super(SendToReviewerStatusChangeView, self).get_form(entity, transition, **kwargs)
+ relation = ff.RelationField(name='reviews', role='object',
+ eidparam=True,
+ label=_('select reviewers'),
+ widget=fwdgs.Select(multiple=True))
+ form.append_field(relation)
+ return form
+
+Simple extension of a form can be done from within the `FormView`
+wrapping the form. FormView instances have a handy ``get_form`` method
+that returns the form to be rendered. Here we add a ``RelationField``
+to the base state change form.
+
+One notable point is the ``eidparam`` argument: it tells both the
+field and the ``edit controller`` that the field is linked to a
+specific entity.
+
+It is hence entirely possible to add ad-hoc fields that will be
+processed by some specialized instance of the edit controller.
+
+
+Ad-hoc fields form
+~~~~~~~~~~~~~~~~~~
+
+We want to define a form doing something else than editing an entity. The idea is
+to propose a form to send an email to entities in a resultset which implements
+:class:`IEmailable`. Let's take a simplified version of what you'll find in
+:mod:`cubicweb.web.views.massmailing`.
+
+Here is the source code:
+
+.. sourcecode:: python
+
+ def sender_value(form, field):
+ return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
+
+ def recipient_choices(form, field):
+ return [(e.get_email(), e.eid)
+ for e in form.cw_rset.entities()
+ if e.get_email()]
+
+ def recipient_value(form, field):
+ return [e.eid for e in form.cw_rset.entities()
+ if e.get_email()]
+
+ class MassMailingForm(forms.FieldsForm):
+ __regid__ = 'massmailing'
+
+ needs_js = ('cubicweb.widgets.js',)
+ domid = 'sendmail'
+ action = 'sendmail'
+
+ sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
+ label=_('From:'),
+ value=sender_value)
+
+ recipient = ff.StringField(widget=CheckBox(),
+ label=_('Recipients:'),
+ choices=recipient_choices,
+ value=recipients_value)
+
+ subject = ff.StringField(label=_('Subject:'), max_length=256)
+
+ mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
+ inputid='mailbody'))
+
+ form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
+ _('send email'), 'SEND_EMAIL_ICON'),
+ ImgButton('cancelbutton', "javascript: history.back()",
+ stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
+
+Let's detail what's going on up there. Our form will hold four fields:
+
+* a sender field, which is disabled and will simply contains the user's name and
+ email
+
+* a recipients field, which will be displayed as a list of users in the context
+ result set with checkboxes so user can still choose who will receive his mailing
+ by checking or not the checkboxes. By default all of them will be checked since
+ field's value return a list containing same eids as those returned by the
+ vocabulary function.
+
+* a subject field, limited to 256 characters (hence we know a
+ :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
+ :class:`~cubicweb.web.formfields.StringField`)
+
+* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
+ and whose definition won't be shown here. Notice though that we tell this form
+ need this javascript file by using `needs_js`
+
+Last but not least, we add two buttons control: one to post the form using
+javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
+set to 'sendmail', which is our form DOM id as specified by its `domid`
+attribute), another to cancel the form which will go back to the previous page
+using another javascript call. Also we specify an image to use as button icon as a
+resource identifier (see :ref:`uiprops`) given as last argument to
+:class:`cubicweb.web.formwidgets.ImgButton`.
+
+To see this form, we still have to wrap it in a view. This is pretty simple:
+
+.. sourcecode:: python
+
+ class MassMailingFormView(form.FormViewMixIn, EntityView):
+ __regid__ = 'massmailing'
+ __select__ = is_instance(IEmailable) & authenticated_user()
+
+ def call(self):
+ form = self._cw.vreg['forms'].select('massmailing', self._cw,
+ rset=self.cw_rset)
+ form.render(w=self.w)
+
+As you see, we simply define a view with proper selector so it only apply to a
+result set containing :class:`IEmailable` entities, and so that only users in the
+managers or users group can use it. Then in the `call()` method for this view we
+simply select the above form and call its `.render()` method with our output
+stream as argument.
+
+When this form is submitted, a controller with id 'sendmail' will be called (as
+specified using `action`). This controller will be responsible to actually send
+the mail to specified recipients.
+
+Here is what it looks like:
+
+.. sourcecode:: python
+
+ class SendMailController(Controller):
+ __regid__ = 'sendmail'
+ __select__ = (authenticated_user() &
+ match_form_params('recipient', 'mailbody', 'subject'))
+
+ def publish(self, rset=None):
+ body = self._cw.form['mailbody']
+ subject = self._cw.form['subject']
+ eids = self._cw.form['recipient']
+ # eids may be a string if only one recipient was specified
+ if isinstance(eids, basestring):
+ rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
+ else:
+ rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
+ recipients = list(rset.entities())
+ msg = format_mail({'email' : self._cw.user.get_email(),
+ 'name' : self._cw.user.dc_title()},
+ recipients, body, subject)
+ if not self._cw.vreg.config.sendmails([(msg, recipients)]):
+ msg = self._cw._('could not connect to the SMTP server')
+ else:
+ msg = self._cw._('emails successfully sent')
+ raise Redirect(self._cw.build_url(__message=msg))
+
+
+The entry point of a controller is the publish method. In that case we simply get
+back post values in request's `form` attribute, get user instances according
+to eids found in the 'recipient' form value, and send email after calling
+:func:`format_mail` to get a proper email message. If we can't send email or
+if we successfully sent email, we redirect to the index page with proper message
+to inform the user.
+
+Also notice that our controller has a selector that deny access to it
+to anonymous users (we don't want our instance to be used as a spam
+relay), but also checks if the expected parameters are specified in
+forms. That avoids later defensive programming (though it's not enough
+to handle all possible error cases).
+
+To conclude our example, suppose we wish a different form layout and that existent
+renderers are not satisfying (we would check that first of course :). We would then
+have to define our own renderer:
+
+.. sourcecode:: python
+
+ class MassMailingFormRenderer(formrenderers.FormRenderer):
+ __regid__ = 'massmailing'
+
+ def _render_fields(self, fields, w, form):
+ w(u'<table class="headersform">')
+ for field in fields:
+ if field.name == 'mailbody':
+ w(u'</table>')
+ w(u'<div id="toolbar">')
+ w(u'<ul>')
+ for button in form.form_buttons:
+ w(u'<li>%s</li>' % button.render(form))
+ w(u'</ul>')
+ w(u'</div>')
+ w(u'<div>')
+ w(field.render(form, self))
+ w(u'</div>')
+ else:
+ w(u'<tr>')
+ w(u'<td class="hlabel">%s</td>' %
+ self.render_label(form, field))
+ w(u'<td class="hvalue">')
+ w(field.render(form, self))
+ w(u'</td></tr>')
+
+ def render_buttons(self, w, form):
+ pass
+
+We simply override the `_render_fields` and `render_buttons` method of the base form renderer
+to arrange fields as we desire it: here we'll have first a two columns table with label and
+value of the sender, recipients and subject field (form order respected), then form controls,
+then a div containing the textarea for the email's content.
+
+To bind this renderer to our form, we should add to our form definition above:
+
+.. sourcecode:: python
+
+ form_renderer_id = 'massmailing'
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/edition/form.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,377 @@
+.. _webform:
+
+HTML form construction
+----------------------
+
+CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
+to provide generic building blocks which will greatly help you in building forms
+properly integrated with CubicWeb (coherent display, error handling, etc...),
+while keeping things as flexible as possible.
+
+A ``form`` basically only holds a set of ``fields``, and has te be bound to a
+``renderer`` which is responsible to layout them. Each field is bound to a
+``widget`` that will be used to fill in value(s) for that field (at form
+generation time) and 'decode' (fetch and give a proper Python type to) values
+sent back by the browser.
+
+The ``field`` should be used according to the type of what you want to edit.
+E.g. if you want to edit some date, you'll have to use the
+:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple
+widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a
+bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
+calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
+calendar). You can of course also write your own widget.
+
+Exploring the available forms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A small excursion into a |cubicweb| shell is the quickest way to
+discover available forms (or application objects in general).
+
+.. sourcecode:: python
+
+ >>> from pprint import pprint
+ >>> pprint( session.vreg['forms'] )
+ {'base': [<class 'cubicweb.web.views.forms.FieldsForm'>,
+ <class 'cubicweb.web.views.forms.EntityFieldsForm'>],
+ 'changestate': [<class 'cubicweb.web.views.workflow.ChangeStateForm'>,
+ <class 'cubes.tracker.views.forms.VersionChangeStateForm'>],
+ 'composite': [<class 'cubicweb.web.views.forms.CompositeForm'>,
+ <class 'cubicweb.web.views.forms.CompositeEntityForm'>],
+ 'deleteconf': [<class 'cubicweb.web.views.editforms.DeleteConfForm'>],
+ 'edition': [<class 'cubicweb.web.views.autoform.AutomaticEntityForm'>,
+ <class 'cubicweb.web.views.workflow.TransitionEditionForm'>,
+ <class 'cubicweb.web.views.workflow.StateEditionForm'>],
+ 'logform': [<class 'cubicweb.web.views.basetemplates.LogForm'>],
+ 'massmailing': [<class 'cubicweb.web.views.massmailing.MassMailingForm'>],
+ 'muledit': [<class 'cubicweb.web.views.editforms.TableEditForm'>],
+ 'sparql': [<class 'cubicweb.web.views.sparql.SparqlForm'>]}
+
+
+The two most important form families here (for all practical purposes) are `base`
+and `edition`. Most of the time one wants alterations of the
+:class:`AutomaticEntityForm` to generate custom forms to handle edition of an
+entity.
+
+The Automatic Entity Form
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: cubicweb.web.views.autoform
+
+Anatomy of a choices function
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Let's have a look at the `ticket_done_in_choices` function given to
+the `choices` parameter of the relation tag that is applied to the
+('Ticket', 'done_in', '*') relation definition, as it is both typical
+and sophisticated enough. This is a code snippet from the `tracker`_
+cube.
+
+.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker
+
+The ``Ticket`` entity type can be related to a ``Project`` and a
+``Version``, respectively through the ``concerns`` and ``done_in``
+relations. When a user is about to edit a ticket, we want to fill the
+combo box for the ``done_in`` relation with values pertinent with
+respect to the context. The important context here is:
+
+* creation or modification (we cannot fetch values the same way in
+ either case)
+
+* ``__linkto`` url parameter given in a creation context
+
+.. sourcecode:: python
+
+ from cubicweb.web import formfields
+
+ def ticket_done_in_choices(form, field):
+ entity = form.edited_entity
+ # first see if its specified by __linkto form parameters
+ linkedto = form.linked_to[('done_in', 'subject')]
+ if linkedto:
+ return linkedto
+ # it isn't, get initial values
+ vocab = field.relvoc_init(form)
+ veid = None
+ # try to fetch the (already or pending) related version and project
+ if not entity.has_eid():
+ peids = form.linked_to[('concerns', 'subject')]
+ peid = peids and peids[0]
+ else:
+ peid = entity.project.eid
+ veid = entity.done_in and entity.done_in[0].eid
+ if peid:
+ # we can complete the vocabulary with relevant values
+ rschema = form._cw.vreg.schema['done_in'].rdef('Ticket', 'Version')
+ rset = form._cw.execute(
+ 'Any V, VN ORDERBY version_sort_value(VN) '
+ 'WHERE V version_of P, P eid %(p)s, V num VN, '
+ 'V in_state ST, NOT ST name "published"', {'p': peid}, 'p')
+ vocab += [(v.view('combobox'), v.eid) for v in rset.entities()
+ if rschema.has_perm(form._cw, 'add', toeid=v.eid)
+ and v.eid != veid]
+ return vocab
+
+The first thing we have to do is fetch potential values from the ``__linkto`` url
+parameter that is often found in entity creation contexts (the creation action
+provides such a parameter with a predetermined value; for instance in this case,
+ticket creation could occur in the context of a `Version` entity). The
+:class:`~cubicweb.web.formfields.RelationField` field class provides a
+:meth:`~cubicweb.web.formfields.RelationField.relvoc_linkedto` method that gets a
+list suitably filled with vocabulary values.
+
+.. sourcecode:: python
+
+ linkedto = field.relvoc_linkedto(form)
+ if linkedto:
+ return linkedto
+
+Then, if no ``__linkto`` argument was given, we must prepare the vocabulary with
+an initial empty value (because `done_in` is not mandatory, we must allow the
+user to not select a verson) and already linked values. This is done with the
+:meth:`~cubicweb.web.formfields.RelationField.relvoc_init` method.
+
+.. sourcecode:: python
+
+ vocab = field.relvoc_init(form)
+
+But then, we have to give more: if the ticket is related to a project,
+we should provide all the non published versions of this project
+(`Version` and `Project` can be related through the `version_of`
+relation). Conversely, if we do not know yet the project, it would not
+make sense to propose all existing versions as it could potentially
+lead to incoherences. Even if these will be caught by some
+RQLConstraint, it is wise not to tempt the user with error-inducing
+candidate values.
+
+The "ticket is related to a project" part must be decomposed as:
+
+* this is a new ticket which is created is the context of a project
+
+* this is an already existing ticket, linked to a project (through the
+ `concerns` relation)
+
+* there is no related project (quite unlikely given the cardinality of
+ the `concerns` relation, so it can only mean that we are creating a
+ new ticket, and a project is about to be selected but there is no
+ ``__linkto`` argument)
+
+.. note::
+
+ the last situation could happen in several ways, but of course in a
+ polished application, the paths to ticket creation should be
+ controlled so as to avoid a suboptimal end-user experience
+
+Hence, we try to fetch the related project.
+
+.. sourcecode:: python
+
+ veid = None
+ if not entity.has_eid():
+ peids = form.linked_to[('concerns', 'subject')]
+ peid = peids and peids[0]
+ else:
+ peid = entity.project.eid
+ veid = entity.done_in and entity.done_in[0].eid
+
+We distinguish between entity creation and entity modification using
+the ``Entity.has_eid()`` method, which returns `False` on creation. At
+creation time the only way to get a project is through the
+``__linkto`` parameter. Notice that we fetch the version in which the
+ticket is `done_in` if any, for later.
+
+.. note::
+
+ the implementation above assumes that if there is a ``__linkto``
+ parameter, it is only about a project. While it makes sense most of
+ the time, it is not an absolute. Depending on how an entity creation
+ action action url is built, several outcomes could be possible
+ there
+
+If the ticket is already linked to a project, fetching it is
+trivial. Then we add the relevant version to the initial vocabulary.
+
+.. sourcecode:: python
+
+ if peid:
+ rschema = form._cw.vreg.schema['done_in'].rdef('Ticket', 'Version')
+ rset = form._cw.execute(
+ 'Any V, VN ORDERBY version_sort_value(VN) '
+ 'WHERE V version_of P, P eid %(p)s, V num VN, '
+ 'V in_state ST, NOT ST name "published"', {'p': peid})
+ vocab += [(v.view('combobox'), v.eid) for v in rset.entities()
+ if rschema.has_perm(form._cw, 'add', toeid=v.eid)
+ and v.eid != veid]
+
+.. warning::
+
+ we have to defend ourselves against lack of a project eid. Given
+ the cardinality of the `concerns` relation, there *must* be a
+ project, but this rule can only be enforced at validation time,
+ which will happen of course only after form subsmission
+
+Here, given a project eid, we complete the vocabulary with all
+unpublished versions defined in the project (sorted by number) for
+which the current user is allowed to establish the relation.
+
+
+Building self-posted form with custom fields/widgets
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes you want a form that is not related to entity edition. For those,
+you'll have to handle form posting by yourself. Here is a complete example on how
+to achieve this (and more).
+
+Imagine you want a form that selects a month period. There are no proper
+field/widget to handle this in CubicWeb, so let's start by defining them:
+
+.. sourcecode:: python
+
+ # let's have the whole import list at the beginning, even those necessary for
+ # subsequent snippets
+ from logilab.common import date
+ from logilab.mtconverter import xml_escape
+ from cubicweb.view import View
+ from cubicweb.predicates import match_kwargs
+ from cubicweb.web import RequestError, ProcessFormError
+ from cubicweb.web import formfields as fields, formwidgets as wdgs
+ from cubicweb.web.views import forms, calendar
+
+ class MonthSelect(wdgs.Select):
+ """Custom widget to display month and year. Expect value to be given as a
+ date instance.
+ """
+
+ def format_value(self, form, field, value):
+ return u'%s/%s' % (value.year, value.month)
+
+ def process_field_data(self, form, field):
+ val = super(MonthSelect, self).process_field_data(form, field)
+ try:
+ year, month = val.split('/')
+ year = int(year)
+ month = int(month)
+ return date.date(year, month, 1)
+ except ValueError:
+ raise ProcessFormError(
+ form._cw._('badly formated date string %s') % val)
+
+
+ class MonthPeriodField(fields.CompoundField):
+ """custom field composed of two subfields, 'begin_month' and 'end_month'.
+
+ It expects to be used on form that has 'mindate' and 'maxdate' in its
+ extra arguments, telling the range of month to display.
+ """
+
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('widget', wdgs.IntervalWidget())
+ super(MonthPeriodField, self).__init__(
+ [fields.StringField(name='begin_month',
+ choices=self.get_range, sort=False,
+ value=self.get_mindate,
+ widget=MonthSelect()),
+ fields.StringField(name='end_month',
+ choices=self.get_range, sort=False,
+ value=self.get_maxdate,
+ widget=MonthSelect())], *args, **kwargs)
+
+ @staticmethod
+ def get_range(form, field):
+ mindate = date.todate(form.cw_extra_kwargs['mindate'])
+ maxdate = date.todate(form.cw_extra_kwargs['maxdate'])
+ assert mindate <= maxdate
+ _ = form._cw._
+ months = []
+ while mindate <= maxdate:
+ label = '%s %s' % (_(calendar.MONTHNAMES[mindate.month - 1]),
+ mindate.year)
+ value = field.widget.format_value(form, field, mindate)
+ months.append( (label, value) )
+ mindate = date.next_month(mindate)
+ return months
+
+ @staticmethod
+ def get_mindate(form, field):
+ return form.cw_extra_kwargs['mindate']
+
+ @staticmethod
+ def get_maxdate(form, field):
+ return form.cw_extra_kwargs['maxdate']
+
+ def process_posted(self, form):
+ for field, value in super(MonthPeriodField, self).process_posted(form):
+ if field.name == 'end_month':
+ value = date.last_day(value)
+ yield field, value
+
+
+Here we first define a widget that will be used to select the beginning and the
+end of the period, displaying months like '<month> YYYY' but using 'YYYY/mm' as
+actual value.
+
+We then define a field that will actually hold two fields, one for the beginning
+and another for the end of the period. Each subfield uses the widget we defined
+earlier, and the outer field itself uses the standard
+:class:`IntervalWidget`. The field adds some logic:
+
+* a vocabulary generation function `get_range`, used to populate each sub-field
+
+* two 'value' functions `get_mindate` and `get_maxdate`, used to tell to
+ subfields which value they should consider on form initialization
+
+* overriding of `process_posted`, called when the form is being posted, so that
+ the end of the period is properly set to the last day of the month.
+
+Now, we can define a very simple form:
+
+.. sourcecode:: python
+
+ class MonthPeriodSelectorForm(forms.FieldsForm):
+ __regid__ = 'myform'
+ __select__ = match_kwargs('mindate', 'maxdate')
+
+ form_buttons = [wdgs.SubmitButton()]
+ form_renderer_id = 'onerowtable'
+ period = MonthPeriodField()
+
+
+where we simply add our field, set a submit button and use a very simple renderer
+(try others!). Also we specify a selector that ensures form will have arguments
+necessary to our field.
+
+Now, we need a view that will wrap the form and handle post when it occurs,
+simply displaying posted values in the page:
+
+.. sourcecode:: python
+
+ class SelfPostingForm(View):
+ __regid__ = 'myformview'
+
+ def call(self):
+ mindate, maxdate = date.date(2010, 1, 1), date.date(2012, 1, 1)
+ form = self._cw.vreg['forms'].select(
+ 'myform', self._cw, mindate=mindate, maxdate=maxdate, action='')
+ try:
+ posted = form.process_posted()
+ self.w(u'<p>posted values %s</p>' % xml_escape(repr(posted)))
+ except RequestError: # no specified period asked
+ pass
+ form.render(w=self.w, formvalues=self._cw.form)
+
+
+Notice usage of the :meth:`process_posted` method, that will return a dictionary
+of typed values (because they have been processed by the field). In our case, when
+the form is posted you should see a dictionary with 'begin_month' and 'end_month'
+as keys with the selected dates as value (as a python `date` object).
+
+
+APIs
+~~~~
+
+.. automodule:: cubicweb.web.formfields
+.. automodule:: cubicweb.web.formwidgets
+.. automodule:: cubicweb.web.views.forms
+.. automodule:: cubicweb.web.views.formrenderers
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/edition/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,15 @@
+Edition control
+===============
+
+This chapter covers the editing capabilities of |cubicweb|. It
+explains html Form construction, the Edit Controller and their
+interactions.
+
+
+.. toctree::
+ :maxdepth: 2
+
+ form
+ dissection
+ editcontroller
+ examples
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/facets.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,23 @@
+The facets system
+-----------------
+
+Facets allow to restrict searches according to some user friendly criterias.
+CubicWeb has a builtin `facet`_ system to define restrictions `filters`_ really
+as easily as possible.
+
+Here is an exemple of the facets rendering picked from our
+http://www.cubicweb.org web site:
+
+.. image:: ../images/facet_overview.png
+
+Facets will appear on each page presenting more than one entity that may be
+filtered according to some known criteria.
+
+Base classes for facets
+~~~~~~~~~~~~~~~~~~~~~~~
+.. automodule:: cubicweb.web.facet
+
+
+.. _facet: http://en.wikipedia.org/wiki/Faceted_browser
+.. _filters: http://www.cubicweb.org/blogentry/154152
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/httpcaching.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,21 @@
+HTTP cache management
+=====================
+
+.. automodule:: cubicweb.web.httpcache
+
+Cache policies
+--------------
+.. autoclass:: cubicweb.web.httpcache.NoHTTPCacheManager
+.. autoclass:: cubicweb.web.httpcache.MaxAgeHTTPCacheManager
+.. autoclass:: cubicweb.web.httpcache.EtagHTTPCacheManager
+.. autoclass:: cubicweb.web.httpcache.EntityHTTPCacheManager
+
+Exception
+---------
+.. autoexception:: cubicweb.web.httpcache.NoEtag
+
+Helper functions
+----------------
+.. autofunction:: cubicweb.web.httpcache.set_http_cache_headers
+
+.. NOT YET AVAILABLE IN STABLE autofunction:: cubicweb.web.httpcache.lastmodified
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,24 @@
+Web side development
+====================
+
+In this chapter, we will describe the core APIs for web development in
+the *CubicWeb* framework.
+
+.. toctree::
+ :maxdepth: 2
+
+ publisher
+ controllers
+ request
+ searchbar
+ views/index
+ rtags
+ ajax
+ js
+ css
+ edition/index
+ facets
+ internationalization
+ property
+ httpcaching
+ resource
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/internationalization.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,229 @@
+.. -*- coding: utf-8 -*-
+
+.. _internationalization:
+
+Internationalization
+---------------------
+
+Cubicweb fully supports the internalization of its content and interface.
+
+Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
+
+.. _`GNU gettext`: http://www.gnu.org/software/gettext/
+
+Cubicweb' internalization involves two steps:
+
+* in your Python code and cubicweb-tal templates : mark translatable strings
+
+* in your instance : handle the translation catalog, edit translations
+
+String internationalization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+User defined string
+```````````````````
+
+In the Python code and cubicweb-tal templates translatable strings can be
+marked in one of the following ways :
+
+ * by using the *built-in* function `_`:
+
+ .. sourcecode:: python
+
+ class PrimaryView(EntityView):
+ """the full view of an non final entity"""
+ __regid__ = 'primary'
+ title = _('primary')
+
+ OR
+
+ * by using the equivalent request's method:
+
+ .. sourcecode:: python
+
+ class NoResultView(View):
+ """default view when no result has been found"""
+ __regid__ = 'noresult'
+
+ def call(self, **kwargs):
+ self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
+ % self._cw._('No result matching query'))
+
+The goal of the *built-in* function `_` is only **to mark the
+translatable strings**, it will only return the string to translate
+itself, but not its translation (it's actually another name for the
+`unicode` builtin).
+
+In the other hand the request's method `self._cw._` is also meant to
+retrieve the proper translation of translation strings in the
+requested language.
+
+Finally you can also use the `__` attribute of request object to get a
+translation for a string *which should not itself added to the catalog*,
+usually in case where the actual msgid is created by string interpolation ::
+
+ self._cw.__('This %s' % etype)
+
+In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
+messages catalogs.
+
+Translations in cubicweb-tal template can also be done with TAL tags
+`i18n:content` and `i18n:replace`.
+
+If you need to add messages on top of those that can be found in the source,
+you can create a file named `i18n/static-messages.pot`.
+
+You could put there messages not found in the python sources or
+overrides for some messages of used cubes.
+
+Generated string
+````````````````
+
+We do not need to mark the translation strings of entities/relations used by a
+particular instance's schema as they are generated automatically. String for
+various actions are also generated.
+
+For exemple the following schema:
+
+.. sourcecode:: python
+
+
+ class EntityA(EntityType):
+ relation_a2b = SubjectRelation('EntityB')
+
+ class EntityB(EntityType):
+ pass
+
+May generate the following message ::
+
+ add EntityA relation_a2b EntityB subject
+
+This message will be used in views of ``EntityA`` for creation of a new
+``EntityB`` with a preset relation ``relation_a2b`` between the current
+``EntityA`` and the new ``EntityB``. The opposite message ::
+
+ add EntityA relation_a2b EntityB object
+
+Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
+title of they respective creation form will be ::
+
+ creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
+
+ creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
+
+In the translated string you can use ``%(linkto)s`` for reference to the source
+``entity``.
+
+Handling the translation catalog
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Once the internationalization is done in your code, you need to populate and
+update the translation catalog. Cubicweb provides the following commands for this
+purpose:
+
+
+* `i18ncubicweb` updates Cubicweb framework's translation
+ catalogs. Unless you actually work on the framework itself, you
+ don't need to use this command.
+
+* `i18ncube` updates the translation catalogs of *one particular cube*
+ (or of all cubes). After this command is executed you must update
+ the translation files *.po* in the "i18n" directory of your
+ cube. This command will of course not remove existing translations
+ still in use. It will mark unused translation but not remove them.
+
+* `i18ninstance` recompiles the translation catalogs of *one particular
+ instance* (or of all instances) after the translation catalogs of
+ its cubes have been updated. This command is automatically
+ called every time you create or update your instance. The compiled
+ catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
+ instance where `lang` is the language identifier ('en' or 'fr'
+ for exemple).
+
+
+Example
+```````
+
+You have added and/or modified some translation strings in your cube
+(after creating a new view or modifying the cube's schema for exemple).
+To update the translation catalogs you need to do:
+
+1. `cubicweb-ctl i18ncube <cube>`
+2. Edit the <cube>/i18n/xxx.po files and add missing translations (empty `msgstr`)
+3. `hg ci -m "updated i18n catalogs"`
+4. `cubicweb-ctl i18ninstance <myinstance>`
+
+Editing po files
+~~~~~~~~~~~~~~~~
+
+Using a PO aware editor
+````````````````````````
+
+Many tools exist to help maintain .po (PO) files. Common editors or
+development environment provides modes for these. One can also find
+dedicated PO files editor, such as `poedit`_.
+
+.. _`poedit`: http://www.poedit.net/
+
+While usage of such a tool is commendable, PO files are perfectly
+editable with a (unicode aware) plain text editor. It is also useful
+to know their structure for troubleshooting purposes.
+
+Structure of a PO file
+``````````````````````
+
+In this section, we selectively quote passages of the `GNU gettext`_
+manual chapter on PO files, available there::
+
+ http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
+
+One PO file entry has the following schematic structure::
+
+ white-space
+ # translator-comments
+ #. extracted-comments
+ #: reference...
+ #, flag...
+ #| msgid previous-untranslated-string
+ msgid untranslated-string
+ msgstr translated-string
+
+
+A simple entry can look like this::
+
+ #: lib/error.c:116
+ msgid "Unknown system error"
+ msgstr "Error desconegut del sistema"
+
+It is also possible to have entries with a context specifier. They
+look like this::
+
+ white-space
+ # translator-comments
+ #. extracted-comments
+ #: reference...
+ #, flag...
+ #| msgctxt previous-context
+ #| msgid previous-untranslated-string
+ msgctxt context
+ msgid untranslated-string
+ msgstr translated-string
+
+
+The context serves to disambiguate messages with the same
+untranslated-string. It is possible to have several entries with the
+same untranslated-string in a PO file, provided that they each have a
+different context. Note that an empty context string and an absent
+msgctxt line do not mean the same thing.
+
+Contexts and CubicWeb
+`````````````````````
+
+CubicWeb PO files have both non-contextual and contextual msgids.
+
+Contextual entries are automatically used in some cases. For instance,
+entity.dc_type(), eschema.display_name(req) or display_name(etype,
+req, form, context) methods/function calls will use them.
+
+It is also possible to explicitly use the with _cw.pgettext(context,
+msgid).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/js.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,394 @@
+.. -*- coding: utf-8 -*-
+
+Javascript
+----------
+
+*CubicWeb* uses quite a bit of javascript in its user interface and
+ships with jquery (1.3.x) and parts of the jquery UI library, plus a
+number of homegrown files and also other third party libraries.
+
+All javascript files are stored in cubicweb/web/data/. There are
+around thirty js files there. In a cube it goes to data/.
+
+Obviously one does not want javascript pieces to be loaded all at
+once, hence the framework provides a number of mechanisms and
+conventions to deal with javascript resources.
+
+Conventions
+~~~~~~~~~~~
+
+It is good practice to name cube specific js files after the name of
+the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
+
+.. XXX external_resources variable (which needs love)
+
+Server-side Javascript API
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Javascript resources are typically loaded on demand, from views. The
+request object (available as self._cw from most application objects,
+for instance views and entities objects) has a few methods to do that:
+
+* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
+ javascript files and writes proper entries into the HTML header
+ section. The localfile parameter allows to declare resources which
+ are not from web/data (for instance, residing on a content delivery
+ network).
+
+* `add_onload(self, jscode)` which adds one raw javascript code
+ snippet inline in the html headers. This is quite useful for setting
+ up early jQuery(document).ready(...) initialisations.
+
+Javascript events
+~~~~~~~~~~~~~~~~~
+
+* ``server-response``: this event is triggered on HTTP responses (both
+ standard and ajax). The two following extra parameters are passed
+ to callbacks :
+
+ - ``ajax``: a boolean that says if the reponse was issued by an
+ ajax request
+
+ - ``node``: the DOM node returned by the server in case of an
+ ajax request, otherwise the document itself for standard HTTP
+ requests.
+
+Important javascript AJAX APIS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* `asyncRemoteExec` and `remoteExec` are the base building blocks for
+ doing arbitrary async (resp. sync) communications with the server
+
+* `reloadComponent` is a convenience function to replace a DOM node
+ with server supplied content coming from a specific registry (this
+ is quite handy to refresh the content of some boxes for instances)
+
+* `jQuery.fn.loadxhtml` is an important extension to jQuery which
+ allows proper loading and in-place DOM update of xhtml views. It is
+ suitably augmented to trigger necessary events, and process CubicWeb
+ specific elements such as the facet system, fckeditor, etc.
+
+
+A simple example with asyncRemoteExec
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On the python side, we have to define an
+:class:`cubicweb.web.views.ajaxcontroller.AjaxFunction` object. The
+simplest way to do that is to use the
+:func:`cubicweb.web.views.ajaxcontroller.ajaxfunc` decorator (for more
+details on this, refer to :ref:`ajax`).
+
+.. sourcecode: python
+
+ from cubicweb.web.views.ajaxcontroller import ajaxfunc
+
+ # serialize output to json to get it back easily on the javascript side
+ @ajaxfunc(output_type='json')
+ def js_say_hello(self, name):
+ return u'hello %s' % name
+
+On the javascript side, we do the asynchronous call. Notice how it
+creates a `deferred` object. Proper treatment of the return value or
+error handling has to be done through the addCallback and addErrback
+methods.
+
+.. sourcecode: javascript
+
+ function asyncHello(name) {
+ var deferred = asyncRemoteExec('say_hello', name);
+ deferred.addCallback(function (response) {
+ alert(response);
+ });
+ deferred.addErrback(function (error) {
+ alert('something fishy happened');
+ });
+ }
+
+ function syncHello(name) {
+ alert( remoteExec('say_hello', name) );
+ }
+
+Anatomy of a reloadComponent call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`reloadComponent` allows to dynamically replace some DOM node with new
+elements. It has the following signature:
+
+* `compid` (mandatory) is the name of the component to be reloaded
+
+* `rql` (optional) will be used to generate a result set given as
+ argument to the selected component
+
+* `registry` (optional) defaults to 'components' but can be any other
+ valid registry name
+
+* `nodeid` (optional) defaults to compid + 'Component' but can be any
+ explicitly specified DOM node id
+
+* `extraargs` (optional) should be a dictionary of values that will be
+ given to the cell_call method of the component
+
+A simple reloadComponent example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The server side implementation of `reloadComponent` is the
+:func:`cubicweb.web.views.ajaxcontroller.component` *AjaxFunction* appobject.
+
+The following function implements a two-steps method to delete a
+standard bookmark and refresh the UI, while keeping the UI responsive.
+
+.. sourcecode:: javascript
+
+ function removeBookmark(beid) {
+ d = asyncRemoteExec('delete_bookmark', beid);
+ d.addCallback(function(boxcontent) {
+ reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
+ document.location.hash = '#header';
+ updateMessage(_("bookmark has been removed"));
+ });
+ }
+
+`reloadComponent` is called with the id of the bookmark box as
+argument, no rql expression (because the bookmarks display is actually
+independant of any dataset context), a reference to the 'boxes'
+registry (which hosts all left, right and contextual boxes) and
+finally an explicit 'bookmarks_box' nodeid argument that stipulates
+the target DOM node.
+
+Anatomy of a loadxhtml call
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
+proper loading and in-place DOM update of xhtml views. The existing
+`jQuery.load`_ function does not handle xhtml, hence the addition. The
+API of loadxhtml is roughly similar to that of `jQuery.load`_.
+
+.. _`jQuery.load`: http://api.jquery.com/load/
+
+
+* `url` (mandatory) should be a complete url (typically referencing
+ the :class:`cubicweb.web.views.ajaxcontroller.AjaxController`,
+ but this is not strictly mandatory)
+
+* `data` (optional) is a dictionary of values given to the
+ controller specified through an `url` argument; some keys may have a
+ special meaning depending on the choosen controller (such as `fname`
+ for the JSonController); the `callback` key, if present, must refer
+ to a function to be called at the end of loadxhtml (more on this
+ below)
+
+* `reqtype` (optional) specifies the request method to be used (get or
+ post); if the argument is 'post', then the post method is used,
+ otherwise the get method is used
+
+* `mode` (optional) is one of `replace` (the default) which means the
+ loaded node will replace the current node content, `swap` to replace
+ the current node with the loaded node, and `append` which will
+ append the loaded node to the current node content
+
+About the `callback` option:
+
+* it is called with two parameters: the current node, and a list
+ containing the loaded (and post-processed node)
+
+* whenever it returns another function, this function is called in
+ turn with the same parameters as above
+
+This mechanism allows callback chaining.
+
+
+A simple example with loadxhtml
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here we are concerned with the retrieval of a specific view to be
+injected in the live DOM. The view will be of course selected
+server-side using an entity eid provided by the client side.
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.ajaxcontroller import ajaxfunc
+
+ @ajaxfunc(output_type='xhtml')
+ def frob_status(self, eid, frobname):
+ entity = self._cw.entity_from_eid(eid)
+ return entity.view('frob', name=frobname)
+
+.. sourcecode:: javascript
+
+ function updateSomeDiv(divid, eid, frobname) {
+ var params = {fname:'frob_status', eid: eid, frobname:frobname};
+ jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
+ }
+
+In this example, the url argument is the base json url of a cube
+instance (it should contain something like
+`http://myinstance/ajax?`). The actual AjaxController method name is
+encoded in the `params` dictionary using the `fname` key.
+
+A more real-life example
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+A frequent need of Web 2 applications is the delayed (or demand
+driven) loading of pieces of the DOM. This is typically achieved using
+some preparation of the initial DOM nodes, jQuery event handling and
+proper use of loadxhtml.
+
+We present here a skeletal version of the mecanism used in CubicWeb
+and available in web/views/tabs.py, in the `LazyViewMixin` class.
+
+.. sourcecode:: python
+
+ def lazyview(self, vid, rql=None):
+ """ a lazy version of wview """
+ w = self.w
+ self._cw.add_js('cubicweb.lazy.js')
+ urlparams = {'vid' : vid, 'fname' : 'view'}
+ if rql is not None:
+ urlparams['rql'] = rql
+ w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
+ vid, xml_escape(self._cw.build_url('json', **urlparams))))
+ w(u'</div>')
+ self._cw.add_onload(u"""
+ jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
+ loadNow('#lazy-%(vid)s');});"""
+ % {'event': 'load_%s' % vid, 'vid': vid})
+
+This creates a `div` with a specific event associated to it.
+
+The full version deals with:
+
+* optional parameters such as an entity eid, an rset
+
+* the ability to further reload the fragment
+
+* the ability to display a spinning wheel while the fragment is still
+ not loaded
+
+* handling of browsers that do not support ajax (search engines,
+ text-based browsers such as lynx, etc.)
+
+The javascript side is quite simple, due to loadxhtml awesomeness.
+
+.. sourcecode:: javascript
+
+ function loadNow(eltsel) {
+ var lazydiv = jQuery(eltsel);
+ lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
+ }
+
+This is all significantly different of the previous `simple example`
+(albeit this example actually comes from real-life code).
+
+Notice how the `cubicweb:loadurl` is used to convey the url
+information. The base of this url is similar to the global javascript
+JSON_BASE_URL. According to the pattern described earlier,
+the `fname` parameter refers to the standard `js_view` method of the
+JSonController. This method renders an arbitrary view provided a view
+id (or `vid`) is provided, and most likely an rql expression yielding
+a result set against which a proper view instance will be selected.
+
+The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML
+in a specific cubicweb namespace. It is a means to pass information
+without breaking HTML nor XHTML compliance and without resorting to
+ungodly hacks.
+
+Given all this, it is easy to add a small nevertheless useful feature
+to force the loading of a lazy view (for instance, a very
+computation-intensive web page could be scinded into one fast-loading
+part and a delayed part).
+
+On the server side, a simple call to a javascript function is
+sufficient.
+
+.. sourcecode:: python
+
+ def forceview(self, vid):
+ """trigger an event that will force immediate loading of the view
+ on dom readyness
+ """
+ self._cw.add_onload("triggerLoad('%s');" % vid)
+
+The browser-side definition follows.
+
+.. sourcecode:: javascript
+
+ function triggerLoad(divid) {
+ jQuery('#lazy-' + divd).trigger('load_' + divid);
+ }
+
+
+Javascript library: overview
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* jquery.* : jquery and jquery UI library
+
+* cubicweb.ajax.js : concentrates all ajax related facilities (it
+ extends jQuery with the loahxhtml function, provides a handfull of
+ high-level ajaxy operations like asyncRemoteExec, reloadComponent,
+ replacePageChunk, getDomFromResponse)
+
+* cubicweb.python.js : adds a number of practical extension to stdanrd
+ javascript objects (on Date, Array, String, some list and dictionary
+ operations), and a pythonesque way to build classes. Defines a
+ CubicWeb namespace.
+
+* cubicweb.htmlhelpers.js : a small bag of convenience functions used
+ in various other cubicweb javascript resources (baseuri, progress
+ cursor handling, popup login box, html2dom function, etc.)
+
+* cubicweb.widgets.js : provides a widget namespace and constructors
+ and helpers for various widgets (mainly facets and timeline)
+
+* cubicweb.edition.js : used by edition forms
+
+* cubicweb.preferences.js : used by the preference form
+
+* cubicweb.facets.js : used by the facets mechanism
+
+There is also javascript support for massmailing, gmap (google maps),
+fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
+AppEngine), flot (charts drawing), tabs and bookmarks.
+
+API
+~~~
+
+.. toctree::
+ :maxdepth: 1
+
+ js_api/index
+
+
+Testing javascript
+~~~~~~~~~~~~~~~~~~
+
+You with the ``cubicweb.qunit.QUnitTestCase`` can include standard Qunit tests
+inside the python unittest run . You simply have to define a new class that
+inherit from ``QUnitTestCase`` and register your javascript test file in the
+``all_js_tests`` lclass attribut. This ``all_js_tests`` is a sequence a
+3-tuple (<test_file, [<dependencies> ,] [<data_files>]):
+
+The <test_file> should contains the qunit test. <dependencies> defines the list
+of javascript file that must be imported before the test script. Dependencies
+are included their definition order. <data_files> are additional files copied in the
+test directory. both <dependencies> and <data_files> are optionnal.
+``jquery.js`` is preincluded in for all test.
+
+.. sourcecode:: python
+
+ from cubicweb.qunit import QUnitTestCase
+
+ class MyQUnitTest(QUnitTestCase):
+
+ all_js_tests = (
+ ("relative/path/to/my_simple_testcase.js",)
+ ("relative/path/to/my_qunit_testcase.js",(
+ "rel/path/to/dependency_1.js",
+ "rel/path/to/dependency_2.js",)),
+ ("relative/path/to/my_complexe_qunit_testcase.js",(
+ "rel/path/to/dependency_1.js",
+ "rel/path/to/dependency_2.js",
+ ),(
+ "rel/path/file_dependency.html",
+ "path/file_dependency.json")
+ ),
+ )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/property.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,15 @@
+.. _cwprops:
+
+The property mecanism
+---------------------
+
+.. XXX CWProperty and co
+
+
+Property API
+~~~~~~~~~~~~
+.. XXX feed me
+
+Registering and using your own property
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.. XXX feed me
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/publisher.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,65 @@
+.. _publisher:
+
+Publisher
+---------
+
+What happens when an HTTP request is issued ?
+
+The story begins with the ``CubicWebPublisher.main_publish``
+method. We do not get upper in the bootstrap process because it is
+dependant on the used HTTP library. With `twisted`_ however,
+``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the
+real entry point.
+
+.. _`twisted`: http://twistedmatrix.com/trac/
+
+What main_publish does:
+
+* get a controller id and a result set from the path (this is actually
+ delegated to the `urlpublisher` component)
+
+* the controller is then selected (if not, this is considered an
+ authorization failure and signaled as such) and called
+
+* then either a proper result is returned, in which case the
+ request/connection object issues a ``commit`` and returns the result
+
+* or error handling must happen:
+
+ * ``ValidationErrors`` pop up there and may lead to a redirect to a
+ previously arranged url or standard error handling applies
+ * an HTTP 500 error (`Internal Server Error`) is issued
+
+
+Now, let's turn to the controller. There are many of them in
+:mod:`cubicweb.web.views.basecontrollers`. We can just follow the
+default `view` controller that is selected on a `view` path. See the
+:ref:`controllers` chapter for more information on controllers.
+
+The `View` controller's entry point is the `publish` method. It does
+the following:
+
+* compute the `main` view to be applied, using either the given result
+ set or building one from a user provided rql string (`rql` and `vid`
+ can be forced from the url GET parameters), that is:
+
+ * compute the `vid` using the result set and the schema (see
+ `cubicweb.web.views.vid_from_rset`)
+ * handle all error cases that could happen in this phase
+
+* do some cache management chores
+
+* select a main template (typically `TheMainTemplate`, see chapter
+ :ref:`templates`)
+
+* call it with the result set and the computed view.
+
+What happens next actually depends on the template and the view, but
+in general this is the rendering phase.
+
+
+CubicWebPublisher API
+`````````````````````
+
+.. autoclass:: cubicweb.web.application.CubicWebPublisher
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/request.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,131 @@
+The `Request` class (`cubicweb.web.request`)
+--------------------------------------------
+
+Overview
+````````
+
+A request instance is created when an HTTP request is sent to the web
+server. It contains informations such as form parameters,
+authenticated user, etc. It is a very prevalent object and is used
+throughout all of the framework and applications, as you'll access to
+almost every resources through it.
+
+**A request represents a user query, either through HTTP or not (we
+also talk about RQL queries on the server side for example).**
+
+Here is a non-exhaustive list of attributes and methods available on
+request objects (grouped by category):
+
+* `Browser control`:
+
+ * `ie_browser`: tells if the browser belong to the Internet Explorer
+ family
+
+* `User and identification`:
+
+ * `user`, instance of `cubicweb.entities.authobjs.CWUser` corresponding to the
+ authenticated user
+
+* `Session data handling`
+
+ * `session.data` is the dictionary of the session data; it can be
+ manipulated like an ordinary Python dictionary
+
+* `Edition` (utilities for edition control):
+
+ * `cancel_edition`: resets error url and cleans up pending operations
+ * `create_entity`: utility to create an entity (from an etype,
+ attributes and relation values)
+ * `datadir_url`: returns the url to the merged external resources
+ (|cubicweb|'s `web/data` directory plus all `data` directories of
+ used cubes)
+ * `edited_eids`: returns the list of eids of entities that are
+ edited under the current http request
+ * `eid_rset(eid)`: utility which returns a result set from an eid
+ * `entity_from_eid(eid)`: returns an entity instance from the given eid
+ * `encoding`: returns the encoding of the current HTTP request
+ * `ensure_ro_rql(rql)`: ensure some rql query is a data request
+ * etype_rset
+ * `form`, dictionary containing the values of a web form
+ * `encoding`, character encoding to use in the response
+ * `next_tabindex()`: returns a monotonically growing integer used to
+ build the html tab index of forms
+
+* `HTTP`
+
+ * `authmode`: returns a string describing the authentication mode
+ (http, cookie, ...)
+ * `lang`: returns the user agents/browser's language as carried by
+ the http request
+ * `demote_to_html()`: in the context of an XHTML compliant browser,
+ this will force emission of the response as an HTML document
+ (using the http content negociation)
+
+* `Cookies handling`
+
+ * `get_cookie()`, returns a dictionary containing the value of the header
+ HTTP 'Cookie'
+ * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
+ with a minimal 5 minutes length of duration by default (`maxage` = None
+ returns a *session* cookie which will expire when the user closes the browser
+ window)
+ * `remove_cookie(cookie, key)`, forces a value to expire
+
+* `URL handling`
+
+ * `build_url(__vid, *args, **kwargs)`: return an absolute URL using
+ params dictionary key/values as URL parameters. Values are
+ automatically URL quoted, and the publishing method to use may be
+ specified or will be guessed.
+ * `build_url_params(**kwargs)`: returns a properly prepared (quoted,
+ separators, ...) string from the given parameters
+ * `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
+
+* `Web resource (.css, .js files, etc.) handling`:
+
+ * `add_css(cssfiles)`: adds the given list of css resources to the current
+ html headers
+ * `add_js(jsfiles)`: adds the given list of javascript resources to the
+ current html headers
+ * `add_onload(jscode)`: inject the given jscode fragment (a unicode
+ string) into the current html headers, wrapped inside a
+ document.ready(...) or another ajax-friendly one-time trigger event
+ * `add_header(header, values)`: adds the header/value pair to the
+ current html headers
+ * `status_out`: control the HTTP status of the response
+
+* `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
+ * `execute(*args, **kwargs)`, executes an RQL query and return the result set
+ * `property_value(key)`, properties management (`CWProperty`)
+ * dictionary `data` to store data to share informations between components
+ *while a request is executed*
+
+Please note that this class is abstract and that a concrete implementation
+will be provided by the *frontend* web used (in particular *twisted* as of
+today). For the views or others that are executed on the server side,
+most of the interface of `Request` is defined in the session associated
+to the client.
+
+API
+```
+
+The elements we gave in overview for above are built in three layers,
+from ``cubicweb.req.RequestSessionBase``, ``cubicweb.repoapi.Connection`` and
+``cubicweb.web.ConnectionCubicWebRequestBase``.
+
+.. autoclass:: cubicweb.req.RequestSessionBase
+ :members:
+
+.. autoclass:: cubicweb.repoapi.Connection
+ :members:
+
+.. autoclass:: cubicweb.web.request.ConnectionCubicWebRequestBase
+ :members:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/resource.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,18 @@
+.. _resources:
+
+Locate resources
+----------------
+
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_resource
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_doc_file
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_all_files
+
+Static files handling
+---------------------
+
+.. autoattribute:: cubicweb.web.webconfig.WebConfiguration.static_directory
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_exists
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_open
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_add
+.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_del
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/rtags.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,27 @@
+Configuring the user interface
+------------------------------
+
+.. _relation_tags:
+
+Relation tags
+~~~~~~~~~~~~~
+.. automodule:: cubicweb.rtags
+
+.. _uicfg:
+
+The uicfg module
+~~~~~~~~~~~~~~~~
+
+.. note::
+
+ The part of uicfg that deals with primary views is in the
+ :ref:`primary_view_configuration` chapter.
+
+.. automodule:: cubicweb.web.views.uicfg
+
+
+The uihelper module
+~~~~~~~~~~~~~~~~~~~
+
+.. automodule:: cubicweb.web.uihelper
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/searchbar.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,41 @@
+.. _searchbar:
+
+RQL search bar
+--------------
+
+The RQL search bar is a visual component, hidden by default, the tiny *search*
+input being enough for common use cases.
+
+An autocompletion helper is provided to help you type valid queries, both
+in terms of syntax and in terms of schema validity.
+
+.. autoclass:: cubicweb.web.views.magicsearch.RQLSuggestionsBuilder
+
+
+How search is performed
++++++++++++++++++++++++
+
+You can use the *rql search bar* to either type RQL queries, plain text queries
+or standard shortcuts such as *<EntityType>* or *<EntityType> <attrname> <value>*.
+
+Ultimately, all queries are translated to rql since it's the only
+language understood on the server (data) side. To transform the user
+query into RQL, CubicWeb uses the so-called *magicsearch component*,
+defined in :mod:`cubicweb.web.views.magicsearch`, which in turn
+delegates to a number of query preprocessor that are responsible of
+interpreting the user query and generating corresponding RQL.
+
+The code of the main processor loop is easy to understand:
+
+.. sourcecode:: python
+
+ for proc in self.processors:
+ try:
+ return proc.process_query(uquery, req)
+ except (RQLSyntaxError, BadRQLQuery):
+ pass
+
+The idea is simple: for each query processor, try to translate the
+query. If it fails, try with the next processor, if it succeeds,
+we're done and the RQL query will be executed.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/basetemplates.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,161 @@
+.. -*- coding: utf-8 -*-
+
+.. _templates:
+
+Templates
+=========
+
+Templates are the entry point for the |cubicweb| view system. As seen
+in :ref:`views_base_class`, there are two kinds of views: the
+templatable and non-templatable.
+
+
+Non-templatable views
+---------------------
+
+Non-templatable views are standalone. They are responsible for all the details
+such as setting a proper content type (or mime type), the proper document
+headers, namespaces, etc. Examples are pure xml views such as RSS or Semantic Web
+views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked Data`_, etc.), and views which generate
+binary files (pdf, excel files, etc.)
+
+.. _`SIOC`: http://sioc-project.org/
+.. _`DOAP`: http://trac.usefulinc.com/doap
+.. _`FOAF`: http://www.foaf-project.org/
+.. _`Linked Data`: http://linkeddata.org/
+
+
+To notice that a view is not templatable, you just have to set the
+view's class attribute `templatable` to `False`. In this case, it
+should set the `content_type` class attribute to the correct MIME
+type. By default, it is text/xhtml. Additionally, if your view
+generate a binary file, you have to set the view's class attribute
+`binary` to `True` too.
+
+
+Templatable views
+-----------------
+
+Templatable views are not concerned with such pesky details. They
+leave it to the template. Conversely, the template's main job is to:
+
+* set up the proper document header and content type
+* define the general layout of a document
+* invoke adequate views in the various sections of the document
+
+
+Look at :mod:`cubicweb.web.views.basetemplates` and you will find the base
+templates used to generate (X)HTML for your application. The most important
+template there is :class:`~cubicweb.web.views.basetemplates.TheMainTemplate`.
+
+.. _the_main_template_layout:
+
+TheMainTemplate
+~~~~~~~~~~~~~~~
+
+.. _the_main_template_sections:
+
+Layout and sections
+```````````````````
+
+A page is composed as indicated on the schema below :
+
+.. image:: ../../images/main_template.png
+
+The sections dispatches specific views:
+
+* `header`: the rendering of the header is delegated to the
+ `htmlheader` view, whose default implementation can be found in
+ ``basetemplates.py`` and which does the following things:
+
+ * inject the favicon if there is one
+ * inject the global style sheets and javascript resources
+ * call and display a link to an rss component if there is one available
+
+ it also sets up the page title, and fills the actual
+ `header` section with top-level components, using the `header` view, which:
+
+ * tries to display a logo, the name of the application and the `breadcrumbs`
+ * provides a login status area
+ * provides a login box (hiden by default)
+
+* `left column`: this is filled with all selectable boxes matching the
+ `left` context (there is also a right column but nowadays it is
+ seldom used due to bad usability)
+
+* `contentcol`: this is the central column; it is filled with:
+
+ * the `rqlinput` view (hidden by default)
+ * the `applmessages` component
+ * the `contentheader` view which in turns dispatches all available
+ content navigation components having the `navtop` context (this
+ is used to navigate through entities implementing the IPrevNext
+ interface)
+ * the view that was given as input to the template's `call`
+ method, also dealing with pagination concerns
+ * the `contentfooter`
+
+* `footer`: adds all footer actions
+
+.. note::
+
+ How and why a view object is given to the main template is explained
+ in the :ref:`publisher` chapter.
+
+Configure the main template
+```````````````````````````
+
+You can overload some methods of the
+:class:`~cubicweb.web.views.basetemplates.TheMainTemplate`, in order to fulfil
+your needs. There are also some attributes and methods which can be defined on a
+view to modify the base template behaviour:
+
+* `paginable`: if the result set is bigger than a configurable size, your result
+ page will be paginated by default. You can set this attribute to `False` to
+ avoid this.
+
+* `binary`: boolean flag telling if the view generates some text or a binary
+ stream. Default to False. When view generates text argument given to `self.w`
+ **must be a unicode string**, encoded string otherwise.
+
+* `content_type`, view's content type, default to 'text/xhtml'
+
+* `templatable`, boolean flag telling if the view's content should be returned
+ directly (when `False`) or included in the main template layout (including
+ header, boxes and so on).
+
+* `page_title()`, method that should return a title that will be set as page
+ title in the html headers.
+
+* `html_headers()`, method that should return a list of HTML headers to be
+ included the html headers.
+
+
+You can also modify certain aspects of the main template of a page
+when building a url or setting these parameters in the req.form:
+
+* `__notemplate`, if present (whatever the value assigned), only the content view
+ is returned
+
+* `__force_display`, if present and its value is not null, no pagination whatever
+ the number of entities to display (e.g. similar effect as view's `paginable`
+ attribute described above.
+
+* `__method`, if the result set to render contains only one entity and this
+ parameter is set, it refers to a method to call on the entity by passing it the
+ dictionary of the forms parameters, before going the classic way (through step
+ 1 and 2 described juste above)
+
+* `vtitle`, a title to be set as <h1> of the content
+
+Other templates
+~~~~~~~~~~~~~~~
+
+There are also the following other standard templates:
+
+* :class:`cubicweb.web.views.basetemplates.LogInTemplate`
+* :class:`cubicweb.web.views.basetemplates.LogOutTemplate`
+* :class:`cubicweb.web.views.basetemplates.ErrorTemplate` specializes
+ :class:`~cubicweb.web.views.basetemplates.TheMainTemplate` to do
+ proper end-user output if an error occurs during the computation of
+ TheMainTemplate (it is a fallback view).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/baseviews.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,21 @@
+Base views
+----------
+
+|cubicweb| provides a lot of standard views, that can be found in
+:mod:`cubicweb.web.views` sub-modules.
+
+A certain number of views are used to build the web interface, which apply to one
+or more entities. As other appobjects, their identifier is what distinguish them
+from each others. The most generic ones, found in
+:mod:`cubicweb.web.views.baseviews`, are described below.
+
+You'll probably want to customize one or more of the described views which are
+default, generic, implementations.
+
+
+.. automodule:: cubicweb.web.views.baseviews
+
+You will also find modules providing some specific services:
+
+.. automodule:: cubicweb.web.views.navigation
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/boxes.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,36 @@
+Boxes
+-----
+
+(:mod:`cubicweb.web.views.boxes`)
+
+*sidebox*
+ This view displays usually a side box of some related entities
+ in a primary view.
+
+The action box
+~~~~~~~~~~~~~~~
+
+The ``add_related`` is an automatic menu in the action box that allows to create
+an entity automatically related to the initial entity (context in
+which the box is displayed). By default, the links generated in this
+box are computed from the schema properties of the displayed entity,
+but it is possible to explicitly specify them thanks to the
+`cubicweb.web.views.uicfg.rmode` *relation tag*:
+
+* `link`, indicates that a relation is in general created pointing
+ to an existing entity and that we should not to display a link
+ for this relation
+
+* `create`, indicates that a relation is in general created pointing
+ to new entities and that we should display a link to create a new
+ entity and link to it automatically
+
+
+If necessary, it is possible to overwrite the method
+`relation_mode(rtype, targettype, x='subject')` to dynamically
+compute a relation creation category.
+
+Please note that if at least one action belongs to the `addrelated` category,
+the automatic behavior is desactivated in favor of an explicit behavior
+(e.g. display of `addrelated` category actions only).
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/breadcrumbs.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,60 @@
+Breadcrumbs
+-----------
+
+Breadcrumbs are a navigation component to help the user locate himself
+along a path of entities.
+
+Display
+~~~~~~~
+
+Breadcrumbs are displayed by default in the header section (see
+:ref:`the_main_template_sections`). With the default main template,
+the header section is composed by the logo, the application name,
+breadcrumbs and, at the most right, the login box. Breadcrumbs are
+displayed just next to the application name, thus they begin with a
+separator.
+
+Here is the header section of the CubicWeb's forge:
+
+.. image:: ../../images/breadcrumbs_header.png
+
+There are three breadcrumbs components defined in
+:mod:`cubicweb.web.views.ibreadcrumbs`:
+
+- `BreadCrumbEntityVComponent`: displayed for a result set with one line
+ if the entity is adaptable to ``IBreadCrumbsAdapter``.
+- `BreadCrumbETypeVComponent`: displayed for a result set with more than
+ one line, but with all entities of the same type which can adapt to
+ ``IBreadCrumbsAdapter``.
+- `BreadCrumbAnyRSetVComponent`: displayed for any other result set.
+
+Building breadcrumbs
+~~~~~~~~~~~~~~~~~~~~
+
+The ``IBreadCrumbsAdapter`` adapter is defined in the
+:mod:`cubicweb.web.views.ibreadcrumbs` module. It specifies that an
+entity which implements this interface must have a ``breadcrumbs`` and
+a ``parent_entity`` method. A default implementation for each is
+provided. This implementation expoits the ITreeAdapter.
+
+.. note::
+
+ Redefining the breadcrumbs is the hammer way to do it. Another way
+ is to define an `ITreeAdapter` adapter on an entity type. If
+ available, it will be used to compute breadcrumbs.
+
+Here is the API of the ``IBreadCrumbsAdapter`` class:
+
+.. automethod:: cubicweb.web.views.ibreadcrumbs.IBreadCrumbsAdapter.parent_entity
+.. automethod:: cubicweb.web.views.ibreadcrumbs.IBreadCrumbsAdapter.breadcrumbs
+
+If the breadcrumbs method return a list of entities, the
+``cubicweb.web.views.ibreadcrumbs.BreadCrumbView`` is used to display
+the elements.
+
+By default, for any entity, if recurs=True, breadcrumbs method returns
+a list of entities, else a list of a simple string.
+
+In order to see a hierarchical breadcrumbs, entities must have a
+``parent`` method which returns the parent entity. By default this
+method doesn't exist on entity, given that it can not be guessed.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/idownloadable.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,22 @@
+The 'download' views
+====================
+
+.. automodule:: cubicweb.web.views.idownloadable
+
+Components
+----------
+
+.. autoclass:: cubicweb.web.views.idownloadable.DownloadBox
+
+Download views
+--------------
+
+.. autoclass:: cubicweb.web.views.idownloadable.DownloadView
+.. autoclass:: cubicweb.web.views.idownloadable.DownloadLinkView
+.. autoclass:: cubicweb.web.views.idownloadable.IDownloadablePrimaryView
+
+Embedded views
+--------------
+
+.. autoclass:: cubicweb.web.views.idownloadable.ImageView
+.. autoclass:: cubicweb.web.views.idownloadable.EHTMLView
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,28 @@
+The View system
+===============
+
+This chapter aims to describe the concept of a `view` used all along
+the development of a web application and how it has been implemented
+in |cubicweb|.
+
+
+.. toctree::
+ :maxdepth: 3
+
+ views
+ basetemplates
+ primary
+ reledit
+ baseviews
+ startup
+ boxes
+ table
+ xmlrss
+ urlpublish
+ breadcrumbs
+ idownloadable
+ wdoc
+
+.. editforms
+.. embedding
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/primary.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,276 @@
+.. _primary_view:
+
+The Primary View
+-----------------
+
+By default, *CubicWeb* provides a view that fits every available
+entity type. This is the first view you might be interested in
+modifying. It is also one of the richest and most complex.
+
+It is automatically selected on a one line result set containing an
+entity.
+
+It lives in the :mod:`cubicweb.web.views.primary` module.
+
+The *primary* view is supposed to render a maximum of informations about the
+entity.
+
+.. _primary_view_layout:
+
+Layout
+``````
+
+The primary view has the following layout.
+
+.. image:: ../../images/primaryview_template.png
+
+.. _primary_view_configuration:
+
+Primary view configuration
+``````````````````````````
+
+If you want to customize the primary view of an entity, overriding the primary
+view class may not be necessary. For simple adjustments (attributes or relations
+display locations and styles), a much simpler way is to use uicfg.
+
+Attributes/relations display location
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the primary view, there are three sections where attributes and
+relations can be displayed (represented in pink in the image above):
+
+* 'attributes'
+* 'relations'
+* 'sideboxes'
+
+**Attributes** can only be displayed in the attributes section (default
+ behavior). They can also be hidden. By default, attributes of type `Password`
+ and `Bytes` are hidden.
+
+For instance, to hide the ``title`` attribute of the ``Blog`` entity:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views import uicfg
+ uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
+
+**Relations** can be either displayed in one of the three sections or hidden.
+
+For relations, there are two methods:
+
+* ``tag_object_of`` for modifying the primary view of the object
+* ``tag_subject_of`` for modifying the primary view of the subject
+
+These two methods take two arguments:
+
+* a triplet ``(subject, relation_name, object)``, where subject or object can be replaced with ``'*'``
+* the section name or ``hidden``
+
+.. sourcecode:: python
+
+ pv_section = uicfg.primaryview_section
+ # hide every relation `entry_of` in the `Blog` primary view
+ pv_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
+
+ # display `entry_of` relations in the `relations`
+ # section in the `BlogEntry` primary view
+ pv_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations')
+
+
+Display content
+^^^^^^^^^^^^^^^
+
+You can use ``primaryview_display_ctrl`` to customize the display of attributes
+or relations. Values of ``primaryview_display_ctrl`` are dictionaries.
+
+
+Common keys for attributes and relations are:
+
+* ``vid``: specifies the regid of the view for displaying the attribute or the relation.
+
+ If ``vid`` is not specified, the default value depends on the section:
+ * ``attributes`` section: 'reledit' view
+ * ``relations`` section: 'autolimited' view
+ * ``sideboxes`` section: 'sidebox' view
+
+* ``order``: int used to control order within a section. When not specified,
+ automatically set according to order in which tags are added.
+
+* ``label``: label for the relations section or side box
+
+* ``showlabel``: boolean telling whether the label is displayed
+
+.. sourcecode:: python
+
+ # let us remind the schema of a blog entry
+ class BlogEntry(EntityType):
+ title = String(required=True, fulltextindexed=True, maxsize=256)
+ publish_date = Date(default='TODAY')
+ content = String(required=True, fulltextindexed=True)
+ entry_of = SubjectRelation('Blog', cardinality='?*')
+
+ # now, we want to show attributes
+ # with an order different from that in the schema definition
+ view_ctrl = uicfg.primaryview_display_ctrl
+ for index, attr in enumerate('title', 'content', 'publish_date'):
+ view_ctrl.tag_attribute(('BlogEntry', attr), {'order': index})
+
+By default, relations displayed in the 'relations' section are being displayed by
+the 'autolimited' view. This view will use comma separated values, or list view
+and/or limit your rset if there is too much items in it (and generate the "view
+all" link in this case).
+
+You can control this view by setting the following values in the
+`primaryview_display_ctrl` relation tag:
+
+* `limit`, maximum number of entities to display. The value of the
+ 'navigation.related-limit' cwproperty is used by default (which is 8 by default).
+ If None, no limit.
+
+* `use_list_limit`, number of entities until which they should be display as a list
+ (eg using the 'list' view). Below that limit, the 'csv' view is used. If None,
+ display using 'csv' anyway.
+
+* `subvid`, the subview identifier (eg view that should be used of each item in the
+ list)
+
+Notice you can also use the `filter` key to set up a callback taking the related
+result set as argument and returning it filtered, to do some arbitrary filtering
+that can't be done using rql for instance.
+
+
+.. sourcecode:: python
+
+ pv_section = uicfg.primaryview_section
+ # in `CWUser` primary view, display `created_by`
+ # relations in relations section
+ pv_section.tag_object_of(('*', 'created_by', 'CWUser'), 'relations')
+
+ # display this relation as a list, sets the label,
+ # limit the number of results and filters on comments
+ def filter_comment(rset):
+ return rset.filtered_rset(lambda x: x.e_schema == 'Comment')
+ pv_ctrl = uicfg.primaryview_display_ctrl
+ pv_ctrl.tag_object_of(('*', 'created_by', 'CWUser'),
+ {'vid': 'list', 'label': _('latest comment(s):'),
+ 'limit': True,
+ 'filter': filter_comment})
+
+.. warning:: with the ``primaryview_display_ctrl`` rtag, the subject or the
+ object of the relation is ignored for respectively ``tag_object_of`` or
+ ``tag_subject_of``. To avoid warnings during execution, they should be set to
+ ``'*'``.
+
+
+.. automodule:: cubicweb.web.views.primary
+
+
+Example of customization and creation
+`````````````````````````````````````
+
+We'll show you now an example of a ``primary`` view and how to customize it.
+
+If you want to change the way a ``BlogEntry`` is displayed, just
+override the method ``cell_call()`` of the view ``primary`` in
+``BlogDemo/views.py``.
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import is_instance
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogEntryPrimaryView(PrimaryView):
+ __select__ = PrimaryView.__select__ & is_instance('BlogEntry')
+
+ def render_entity_attributes(self, entity):
+ self.w(u'<p>published on %s</p>' %
+ entity.publish_date.strftime('%Y-%m-%d'))
+ super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
+
+
+The above source code defines a new primary view for
+``BlogEntry``. The `__reid__` class attribute is not repeated there since it
+is inherited through the `primary.PrimaryView` class.
+
+The selector for this view chains the selector of the inherited class
+with its own specific criterion.
+
+The view method ``self.w()`` is used to output data. Here `lines
+08-09` output HTML for the publication date of the entry.
+
+.. image:: ../../images/lax-book_09-new-view-blogentry_en.png
+ :alt: blog entries now look much nicer
+
+Let us now improve the primary view of a blog
+
+.. sourcecode:: python
+
+ from logilab.mtconverter import xml_escape
+ from cubicweb.predicates import is_instance, one_line_rset
+ from cubicweb.web.views.primary import Primaryview
+
+ class BlogPrimaryView(PrimaryView):
+ __regid__ = 'primary'
+ __select__ = PrimaryView.__select__ & is_instance('Blog')
+ rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
+
+ def render_entity_relations(self, entity):
+ rset = self._cw.execute(self.rql, {'b' : entity.eid})
+ for entry in rset.entities():
+ self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
+
+ class BlogEntryInBlogView(EntityView):
+ __regid__ = 'inblogcontext'
+ __select__ = is_instance('BlogEntry')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w(u'<a href="%s" title="%s">%s</a>' %
+ entity.absolute_url(),
+ xml_escape(entity.content[:50]),
+ xml_escape(entity.description))
+
+This happens in two places. First we override the
+render_entity_relations method of a Blog's primary view. Here we want
+to display our blog entries in a custom way.
+
+At `line 10`, a simple request is made to build a result set with all
+the entities linked to the current ``Blog`` entity by the relationship
+``entry_of``. The part of the framework handling the request knows
+about the schema and infers that such entities have to be of the
+``BlogEntry`` kind and retrieves them (in the prescribed publish_date
+order).
+
+The request returns a selection of data called a result set. Result
+set objects have an .entities() method returning a generator on
+requested entities (going transparently through the `ORM` layer).
+
+At `line 13` the view 'inblogcontext' is applied to each blog entry to
+output HTML. (Note that the 'inblogcontext' view is not defined
+whatsoever in *CubicWeb*. You are absolutely free to define whole view
+families.) We juste arrange to wrap each blogentry output in a 'p'
+html element.
+
+Next, we define the 'inblogcontext' view. This is NOT a primary view,
+with its well-defined sections (title, metadata, attribtues,
+relations/boxes). All a basic view has to define is cell_call.
+
+Since views are applied to result sets which can be tables of data, we
+have to recover the entity from its (row,col)-coordinates (`line
+20`). Then we can spit some HTML.
+
+.. warning::
+
+ Be careful: all strings manipulated in *CubicWeb* are actually
+ unicode strings. While web browsers are usually tolerant to
+ incoherent encodings they are being served, we should not abuse
+ it. Hence we have to properly escape our data. The xml_escape()
+ function has to be used to safely fill (X)HTML elements from Python
+ unicode strings.
+
+Assuming we added entries to the blog titled `MyLife`, displaying it
+now allows to read its description and all its entries.
+
+.. image:: ../../images/lax-book_10-blog-with-two-entries_en.png
+ :alt: a blog and all its entries
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/reledit.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,149 @@
+.. _reledit:
+
+The "Click and Edit" (also `reledit`) View
+------------------------------------------
+
+The principal way to update data through the Web UI is through the
+`modify` action on entities, which brings a full form. This is
+described in the :ref:`webform` chapter.
+
+There is however another way to perform piecewise edition of entities
+and relations, using a specific `reledit` (for *relation edition*)
+view from the :mod:`cubicweb.web.views.reledit` module.
+
+This is typically applied from the default Primary View (see
+:ref:`primary_view`) on the attributes and relation section. It makes
+small editions more convenient.
+
+Of course, this can be used customely in any other view. Here come
+some explanation about its capabilities and instructions on the way to
+use it.
+
+Using `reledit`
+***************
+
+Let's start again with a simple example:
+
+.. sourcecode:: python
+
+ class Company(EntityType):
+ name = String(required=True, unique=True)
+ boss = SubjectRelation('Person', cardinality='1*')
+ status = SubjectRelation('File', cardinality='?*', composite='subject')
+
+In some view code we might want to show these attributes/relations and
+allow the user to edit each of them in turn without having to leave
+the current page. We would write code as below:
+
+.. sourcecode:: python
+
+ company.view('reledit', rtype='name', default_value='<name>') # editable name attribute
+ company.view('reledit', rtype='boss') # editable boss relation
+ company.view('reledit', rtype='status') # editable attribute-like relation
+
+If one wanted to edit the company from a boss's point of view, one
+would have to indicate the proper relation's role. By default the role
+is `subject`.
+
+.. sourcecode:: python
+
+ person.view('reledit', rtype='boss', role='object')
+
+Each of these will provide with a different editing widget. The `name`
+attribute will obviously get a text input field. The `boss` relation
+will be edited through a selection box, allowing to pick another
+`Person` as boss. The `status` relation, given that it defines Company
+as a composite entity with one file inside, will provide additional actions
+
+* to `add` a `File` when there is one
+* to `delete` the `File` (if the cardinality allows it)
+
+Moreover, editing the relation or using the `add` action leads to an
+embedded edition/creation form allowing edition of the target entity
+(which is `File` in our example) instead of merely allowing to choose
+amongst existing files.
+
+The `reledit_ctrl` rtag
+***********************
+
+The behaviour of reledited attributes/relations can be finely
+controlled using the reledit_ctrl rtag, defined in
+:mod:`cubicweb.web.views.uicfg`.
+
+This rtag provides four control variables:
+
+* ``default_value``: alternative default value
+ The default value is what is shown when there is no value.
+* ``reload``: boolean, eid (to reload to) or function taking subject
+ and returning bool/eid This is useful when editing a relation (or
+ attribute) that impacts the url or another parts of the current
+ displayed page. Defaults to false.
+* ``rvid``: alternative view id (as str) for relation or composite
+ edition Default is 'incontext' or 'csv' depending on the
+ cardinality. They can also be statically changed by subclassing
+ ClickAndEditFormView and redefining _one_rvid (resp. _many_rvid).
+* ``edit_target``: 'rtype' (to edit the relation) or 'related' (to
+ edit the related entity) This controls whether to edit the relation
+ or the target entity of the relation. Currently only one-to-one
+ relations support target entity edition. By default, the 'related'
+ option is taken whenever the relation is composite and one-to-one.
+
+Let's see how to use these controls.
+
+.. sourcecode:: python
+
+ from logilab.mtconverter import xml_escape
+ from cubicweb.web.views.uicfg import reledit_ctrl
+ reledit_ctrl.tag_attribute(('Company', 'name'),
+ {'reload': lambda x:x.eid,
+ 'default_value': xml_escape(u'<logilab tastes better>')})
+ reledit_ctrl.tag_object_of(('*', 'boss', 'Person'), {'edit_target': 'related'})
+
+The `default_value` needs to be an xml escaped unicode string.
+
+The `edit_target` tag on the `boss` relation being set to `related` will
+ensure edition of the `Person` entity instead (using a standard
+automatic form) of the association of Company and Person.
+
+Finally, the `reload` key accepts either a boolean, an eid or a
+unicode string representing a url. If an eid is provided, it will be
+internally transformed into a url. The eid/url case helps when one
+needs to reload and the current url is inappropriate. A common case is
+edition of a key attribute, which is part of the current url. If one
+user changed the Company's name from `lozilab` to `logilab`, reloading
+on http://myapp/company/lozilab would fail. Providing the entity's
+eid, then, forces to reload on something like http://myapp/company/42,
+which always work.
+
+
+Disable `reledit`
+*****************
+
+By default, `reledit` is available on attributes and relations displayed in
+the 'attribute' section of the default primary view. If you want to disable
+it for some attribute or relation, you have use `uicfg`:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.uicfg import primaryview_display_ctrl as _pvdc
+ _pvdc.tag_attribute(('Company', 'name'), {'vid': 'incontext'})
+
+To deactivate it everywhere it's used automatically, you may use the code snippet
+below somewhere in your cube's views:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views import reledit
+
+ class DeactivatedAutoClickAndEditFormView(reledit.AutoClickAndEditFormView):
+ def _should_edit_attribute(self, rschema):
+ return False
+
+ def _should_edit_attribute(self, rschema, role):
+ return False
+
+ def registration_callback(vreg):
+ vreg.register_and_replace(DeactivatedAutoClickAndEditFormView,
+ reledit.AutoClickAndEditFormView)
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/startup.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,18 @@
+Startup views
+-------------
+
+Startup views are views requiring no context, from which you usually start
+browsing (for instance the index page). The usual selectors are
+:class:`~cubicweb.predicates.none_rset` or :class:`~logilab.common.registry.yes`.
+
+You'll find here a description of startup views provided by the framework.
+
+.. automodule:: cubicweb.web.views.startup
+
+
+Other startup views:
+
+*schema*
+ A view dedicated to the display of the schema of the instance
+
+.. XXX to be continued
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/table.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,145 @@
+Table views
+-----------
+
+.. automodule:: cubicweb.web.views.tableview
+
+Example
+```````
+
+Let us take an example from the timesheet cube:
+
+.. sourcecode:: python
+
+ class ActivityResourcesTable(EntityView):
+ __regid__ = 'activity.resources.table'
+ __select__ = is_instance('Activity')
+
+ def call(self, showresource=True):
+ eids = ','.join(str(row[0]) for row in self.cw_rset)
+ rql = ('Any R,D,DUR,WO,DESCR,S,A, SN,RT,WT ORDERBY D DESC '
+ 'WHERE '
+ ' A is Activity, A done_by R, R title RT, '
+ ' A diem D, A duration DUR, '
+ ' A done_for WO, WO title WT, '
+ ' A description DESCR, A in_state S, S name SN, '
+ ' A eid IN (%s)' % eids)
+ rset = self._cw.execute(rql)
+ self.wview('resource.table', rset, 'null')
+
+ class ResourcesTable(RsetTableView):
+ __regid__ = 'resource.table'
+ # notice you may wish a stricter selector to check rql's shape
+ __select__ = is_instance('Resource')
+ # my table headers
+ headers = ['Resource', 'diem', 'duration', 'workpackage', 'description', 'state']
+ # I want a table where attributes are editable (reledit inside)
+ finalvid = 'editable-final'
+
+ cellvids = {3: 'editable-final'}
+ # display facets and actions with a menu
+ layout_args = {'display_filter': 'top',
+ 'add_view_actions': None}
+
+To obtain an editable table, you may specify the 'editable-table' view identifier
+using some of `cellvids`, `finalvid` or `nonfinalvid`.
+
+The previous example results in:
+
+.. image:: ../../images/views-table-shadow.png
+
+In order to activate table filter mechanism, the `display_filter` option is given
+as a layout argument. A small arrow will be displayed at the table's top right
+corner. Clicking on `show filter form` action, will display the filter form as
+below:
+
+.. image:: ../../images/views-table-filter-shadow.png
+
+By the same way, you can display additional actions for the selected entities
+by setting `add_view_actions` layout option to `True`. This will add actions
+returned by the view's :meth:`~cubicweb.web.views.tableview.TableMixIn.table_actions`.
+
+You can notice that all columns of the result set are not displayed. This is
+because of given `headers`, implying to display only columns from 0 to
+len(headers).
+
+Also Notice that the `ResourcesTable` view relies on a particular rql shape
+(which is not ensured by the way, the only checked thing is that the result set
+contains instance of the `Resource` type). That usually implies that you can't
+use this view for user specific queries (e.g. generated by facets or typed
+manually).
+
+
+So another option would be to write this view using
+:class:`~cubicweb.web.views.tableview.EntityTableView`, as below.
+
+.. sourcecode:: python
+
+ class ResourcesTable(EntityTableView):
+ __regid__ = 'resource.table'
+ __select__ = is_instance('Resource')
+ # table columns definition
+ columns = ['resource', 'diem', 'duration', 'workpackage', 'description', 'in_state']
+ # I want a table where attributes are editable (reledit inside)
+ finalvid = 'editable-final'
+ # display facets and actions with a menu
+ layout_args = {'display_filter': 'top',
+ 'add_view_actions': None}
+
+ def workpackage_cell(entity):
+ activity = entity.reverse_done_in[0]
+ activity.view('reledit', rtype='done_for', role='subject', w=w)
+ def workpackage_sortvalue(entity):
+ activity = entity.reverse_done_in[0]
+ return activity.done_for[0].sortvalue()
+
+ column_renderers = {
+ 'resource': MainEntityColRenderer(),
+ 'workpackage': EntityTableColRenderer(
+ header='Workpackage',
+ renderfunc=worpackage_cell,
+ sortfunc=worpackage_sortvalue,),
+ 'in_state': EntityTableColRenderer(
+ renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state),
+ sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state),
+ }
+
+Notice the following point:
+
+* `cell_<column>(w, entity)` will be searched for rendering the content of a
+ cell. If not found, `column` is expected to be an attribute of `entity`.
+
+* `cell_sortvalue_<column>(entity)` should return a typed value to use for
+ javascript sorting or None for not sortable columns (the default).
+
+* The :func:`etable_entity_sortvalue` decorator will set a 'sortvalue' function
+ for the column containing the main entity (the one given as argument to all
+ methods), which will call `entity.sortvalue()`.
+
+* You can set a column header using the :func:`etable_header_title` decorator.
+ This header will be translated. If it's not an already existing msgid, think
+ to mark it using `_()` (the example supposes headers are schema defined msgid).
+
+
+Pro/cons of each approach
+`````````````````````````
+:class:`EntityTableView` and :class:`RsetableView` provides basically the same
+set of features, though they don't share the same properties. Let's try to sum
+up pro and cons of each class.
+
+* `EntityTableView` view is:
+
+ - more verbose, but usually easier to understand
+
+ - easily extended (easy to add/remove columns for instance)
+
+ - doesn't rely on a particular rset shape. Simply give it a title and will be
+ listed in the 'possible views' box if any.
+
+* `RsetTableView` view is:
+
+ - hard to beat to display barely a result set, or for cases where some of
+ `headers`, `displaycols` or `cellvids` could be defined to enhance the table
+ while you don't care about e.g. pagination or facets.
+
+ - hardly extensible, as you usually have to change places where the view is
+ called to modify the RQL (hence the view's result set shape).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/urlpublish.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,137 @@
+.. -*- coding: utf-8 -*-
+
+URL publishing
+--------------
+
+(:mod:`cubicweb.web.views.urlpublishing`)
+
+.. automodule:: cubicweb.web.views.urlpublishing
+
+.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent
+ :members:
+
+
+You can write your own *URLPathEvaluator* class to handle custom paths.
+For instance, if you want */my-card-id* to redirect to the corresponding
+card's primary view, you would write:
+
+.. sourcecode:: python
+
+ class CardWikiidEvaluator(URLPathEvaluator):
+ priority = 3 # make it be evaluated *before* RestPathEvaluator
+
+ def evaluate_path(self, req, segments):
+ if len(segments) != 1:
+ raise PathDontMatch()
+ rset = req.execute('Any C WHERE C wikiid %(w)s',
+ {'w': segments[0]})
+ if len(rset) == 0:
+ # Raise NotFound if no card is found
+ raise PathDontMatch()
+ return None, rset
+
+On the other hand, you can also deactivate some of the standard
+evaluators in your final application. The only thing you have to
+do is to unregister them, for instance in a *registration_callback*
+in your cube:
+
+.. sourcecode:: python
+
+ def registration_callback(vreg):
+ vreg.unregister(RestPathEvaluator)
+
+You can even replace the :class:`cubicweb.web.views.urlpublishing.URLPublisherComponent`
+class if you want to customize the whole toolchain process or if you want
+to plug into an early enough extension point to control your request
+parameters:
+
+.. sourcecode:: python
+
+ class SanitizerPublisherComponent(URLPublisherComponent):
+ """override default publisher component to explicitly ignore
+ unauthorized request parameters in anonymous mode.
+ """
+ unauthorized_form_params = ('rql', 'vid', '__login', '__password')
+
+ def process(self, req, path):
+ if req.session.anonymous_session:
+ self._remove_unauthorized_params(req)
+ return super(SanitizerPublisherComponent, self).process(req, path)
+
+ def _remove_unauthorized_params(self, req):
+ for param in req.form.keys():
+ if param in self.unauthorized_form_params:
+ req.form.pop(param)
+
+
+ def registration_callback(vreg):
+ vreg.register_and_replace(SanitizerPublisherComponent, URLPublisherComponent)
+
+
+.. autoclass:: cubicweb.web.views.urlpublishing.RawPathEvaluator
+.. autoclass:: cubicweb.web.views.urlpublishing.EidPathEvaluator
+.. autoclass:: cubicweb.web.views.urlpublishing.URLRewriteEvaluator
+.. autoclass:: cubicweb.web.views.urlpublishing.RestPathEvaluator
+.. autoclass:: cubicweb.web.views.urlpublishing.ActionPathEvaluator
+
+URL rewriting
+-------------
+
+(:mod:`cubicweb.web.views.urlrewrite`)
+
+.. autoclass:: cubicweb.web.views.urlrewrite.URLRewriter
+ :members:
+
+.. autoclass:: cubicweb.web.views.urlrewrite.SimpleReqRewriter
+ :members:
+
+.. autoclass:: cubicweb.web.views.urlrewrite.SchemaBasedRewriter
+ :members:
+
+
+``SimpleReqRewriter`` is enough for a certain number of simple cases. If it is not sufficient, ``SchemaBasedRewriter`` allows to do more elaborate things.
+
+Here is an example of ``SimpleReqRewriter`` usage with plain string:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.urlrewrite import SimpleReqRewriter
+ class TrackerSimpleReqRewriter(SimpleReqRewriter):
+ rules = [
+ ('/versions', dict(vid='versionsinfo')),
+ ]
+
+When the url is `<base_url>/versions`, the view with the __regid__ `versionsinfo` is displayed.
+
+Here is an example of ``SimpleReqRewriter`` usage with regular expressions:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.urlrewrite import (
+ SimpleReqRewriter, rgx)
+
+ class BlogReqRewriter(SimpleReqRewriter):
+ rules = [
+ (rgx('/blogentry/([a-z_]+)\.rss'),
+ dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
+ 'X creation_date CD, X created_by U, '
+ 'U login "%(user)s"'
+ % {'user': r'\1'}), vid='rss'))
+ ]
+
+When a url matches the regular expression, the view with the __regid__
+`rss` which match the result set is displayed.
+
+Here is an example of ``SchemaBasedRewriter`` usage:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views.urlrewrite import (
+ SchemaBasedRewriter, rgx, build_rset)
+
+ class TrackerURLRewriter(SchemaBasedRewriter):
+ rules = [
+ (rgx('/project/([^/]+)/([^/]+)/tests'),
+ build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
+ rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
+ ]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/views.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,120 @@
+
+.. _Views:
+
+Principles
+----------
+
+We'll start with a description of the interface providing a basic
+understanding of the available classes and methods, then detail the
+view selection principle.
+
+A `View` is an object responsible for the rendering of data from the
+model into an end-user consummable form. They typically churn out an
+XHTML stream, but there are views concerned with email other non-html
+outputs.
+
+.. _views_base_class:
+
+Discovering possible views
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is possible to configure the web user interface to have a left box
+showing all the views than can be applied to the current result set.
+
+To enable this, click on your login at the top right corner. Chose
+"user preferences", then "boxes", then "possible views box" and check
+"visible = yes" before validating your changes.
+
+The views listed there we either not selected because of a lower
+score, or they were deliberately excluded by the main template logic.
+
+
+Basic class for views
+~~~~~~~~~~~~~~~~~~~~~
+
+Class :class:`~cubicweb.view.View`
+``````````````````````````````````
+
+.. autoclass:: cubicweb.view.View
+
+The basic interface for views is as follows (remember that the result
+set has a tabular structure with rows and columns, hence cells):
+
+* `render(**context)`, render the view by calling `call` or
+ `cell_call` depending on the context
+
+* `call(**kwargs)`, call the view for a complete result set or null
+ (the default implementation calls `cell_call()` on each cell of the
+ result set)
+
+* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
+ result set (`row` and `col` being integers used to access the cell)
+
+* `url()`, returns the URL enabling us to get the view with the current
+ result set
+
+* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of
+ identifier `__vid` on the given result set. It is possible to give a
+ fallback view identifier that will be used if the requested view is
+ not applicable to the result set.
+
+* `html_headers()`, returns a list of HTML headers to be set by the
+ main template
+
+* `page_title()`, returns the title to use in the HTML header `title`
+
+Other basic view classes
+````````````````````````
+Here are some of the subclasses of :class:`~cubicweb.view.View` defined in :mod:`cubicweb.view`
+that are more concrete as they relate to data rendering within the application:
+
+.. autoclass:: cubicweb.view.EntityView
+.. autoclass:: cubicweb.view.StartupView
+.. autoclass:: cubicweb.view.EntityStartupView
+.. autoclass:: cubicweb.view.AnyRsetView
+
+Examples of views class
+```````````````````````
+
+- Using `templatable`, `content_type` and HTTP cache configuration
+
+.. sourcecode:: python
+
+ class RSSView(XMLView):
+ __regid__ = 'rss'
+ title = _('rss')
+ templatable = False
+ content_type = 'text/xml'
+ http_cache_manager = MaxAgeHTTPCacheManager
+ cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
+
+- Using a custom selector
+
+.. sourcecode:: python
+
+ class SearchForAssociationView(EntityView):
+ """view called by the edition view when the user asks
+ to search for something to link to the edited eid
+ """
+ __regid__ = 'search-associate'
+ title = _('search for association')
+ __select__ = one_line_rset() & match_search_state('linksearch') & is_instance('Any')
+
+
+XML views, binaries views...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For views generating other formats than HTML (an image generated dynamically
+for example), and which can not simply be included in the HTML page generated
+by the main template (see above), you have to:
+
+* set the attribute `templatable` of the class to `False`
+* set, through the attribute `content_type` of the class, the MIME
+ type generated by the view to `application/octet-stream` or any
+ relevant and more specialised mime type
+
+For views dedicated to binary content creation (like dynamically generated
+images), we have to set the attribute `binary` of the class to `True` (which
+implies that `templatable == False`, so that the attribute `w` of the view could be
+replaced by a binary flow instead of unicode).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/wdoc.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,15 @@
+.. -*- coding: utf-8 -*-
+
+Online documentation system
+===========================
+
+.. automodule:: cubicweb.web.views.wdoc
+
+Help views
+----------
+.. autoclass:: cubicweb.web.views.wdoc.InlineHelpView
+
+Actions
+-------
+.. autoclass:: cubicweb.web.views.wdoc.HelpAction
+.. autoclass:: cubicweb.web.views.wdoc.AboutAction
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/devweb/views/xmlrss.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,66 @@
+.. _XmlAndRss:
+
+XML and RSS views
+-----------------
+
+(:mod:`cubicweb.web.views.xmlrss`)
+
+Overview
++++++++++
+
+*rss*
+ Creates a RSS/XML view and call the view `rssitem` for each entity of
+ the result set.
+
+*rssitem*
+ Create a RSS/XML view for each entity based on the results of the dublin core
+ methods of the entity (`dc_*`)
+
+RSS Channel Example
+++++++++++++++++++++
+
+Assuming you have several blog entries, click on the title of the
+search box in the left column. A larger search box should appear. Enter:
+
+.. sourcecode:: sql
+
+ Any X ORDERBY D WHERE X is BlogEntry, X creation_date D
+
+and you get a list of blog entries.
+
+Click on your login at the top right corner. Chose "user preferences",
+then "boxes", then "possible views box" and check "visible = yes"
+before validating your changes.
+
+Enter the same query in the search box and you will see the same list,
+plus a box titled "possible views" in the left column. Click on
+"entityview", then "RSS".
+
+You just applied the "RSS" view to the RQL selection you requested.
+
+That's it, you have a RSS channel for your blog.
+
+Try again with:
+
+.. sourcecode:: sql
+
+ Any X ORDERBY D WHERE X is BlogEntry, X creation_date D,
+ X entry_of B, B title "MyLife"
+
+Another RSS channel, but a bit more focused.
+
+A last one for the road:
+
+.. sourcecode:: sql
+
+ Any C ORDERBY D WHERE C is Comment, C creation_date D LIMIT 15
+
+displayed with the RSS view, that's a channel for the last fifteen
+comments posted.
+
+[WRITE ME]
+
+* show that the RSS view can be used to display an ordered selection
+ of blog entries, thus providing a RSS channel
+
+* show that a different selection (by category) means a different channel
Binary file doc/book/en/.static/cubicweb.png has changed
Binary file doc/book/en/.static/logilab.png has changed
--- a/doc/book/en/.static/sphinx-default.css Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,861 +0,0 @@
-/**
- * Sphinx Doc Design
- */
-
-html, body {
- background: white;
-}
-
-body {
- font-family: Verdana, sans-serif;
- font-size: 100%;
- background-color: white;
- color: black;
- margin: 0;
- padding: 0;
-}
-
-/* :::: LAYOUT :::: */
-
-div.logilablogo {
- padding: 10px 10px 10px 10px;
- height:75;
-}
-
-
-div.document {
- background-color: white;
-}
-
-div.documentwrapper {
- float: left;
- width: 100%;
-}
-
-div.bodywrapper {
- margin: 0 0 0 230px;
-}
-
-div.body {
- background-color: white;
- padding: 0 20px 30px 20px;
- border-left:solid;
- border-left-color:#e2e2e2;
- border-left-width:thin;
-}
-
-div.sphinxsidebarwrapper {
- padding: 10px 5px 0 10px;
-}
-
-div.sphinxsidebar {
- float: left;
- width: 230px;
- margin-left: -100%;
- font-size: 90%;
-}
-
-div.clearer {
- clear: both;
-}
-
-div.footer {
- color: #ff4500;
- width: 100%;
- padding: 9px 0 9px 0;
- text-align: center;
- font-size: 75%;
-}
-
-div.footer a {
- color: #ff4500;
- text-decoration: underline;
-}
-
-div.related {
- background-color: #ff7700;
- color: white;
- width: 100%;
- height: 30px;
- line-height: 30px;
- font-size: 90%;
-}
-
-div.related h3 {
- display: none;
-}
-
-div.related ul {
- margin: 0;
- padding: 0 0 0 10px;
- list-style: none;
-}
-
-div.related li {
- display: inline;
-}
-
-div.related li.right {
- float: right;
- margin-right: 5px;
-}
-
-div.related a {
- color: white;
- font-weight:bold;
-}
-
-/* ::: TOC :::: */
-
-div.sphinxsidebar {
- border-style:solid;
- border-color: white;
-/* background-color:#e2e2e2;*/
- padding-bottom:5px;
-}
-
-div.sphinxsidebar h3 {
- font-family: Verdana, sans-serif;
- color: black;
- font-size: 1.2em;
- font-weight: normal;
- margin: 0;
- padding: 0;
- font-weight:bold;
- font-style:italic;
-}
-
-div.sphinxsidebar h4 {
- font-family: Verdana, sans-serif;
- color: black;
- font-size: 1.1em;
- font-weight: normal;
- margin: 5px 0 0 0;
- padding: 0;
- font-weight:bold;
- font-style:italic;
-}
-
-div.sphinxsidebar p {
- color: black;
-}
-
-div.sphinxsidebar p.topless {
- margin: 5px 10px 10px 10px;
-}
-
-div.sphinxsidebar ul {
- margin: 10px;
- padding: 0;
- list-style: none;
- color: black;
-}
-
-div.sphinxsidebar ul ul,
-div.sphinxsidebar ul.want-points {
- margin-left: 20px;
- list-style: square;
-}
-
-div.sphinxsidebar ul ul {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-div.sphinxsidebar a {
- color: black;
- text-decoration: none;
-}
-
-div.sphinxsidebar form {
- margin-top: 10px;
-}
-
-div.sphinxsidebar input {
- border: 1px solid #e2e2e2;
- font-family: sans-serif;
- font-size: 1em;
- padding-bottom: 5px;
-}
-
-/* :::: MODULE CLOUD :::: */
-div.modulecloud {
- margin: -5px 10px 5px 10px;
- padding: 10px;
- line-height: 160%;
- border: 1px solid #cbe7e5;
- background-color: #f2fbfd;
-}
-
-div.modulecloud a {
- padding: 0 5px 0 5px;
-}
-
-/* :::: SEARCH :::: */
-ul.search {
- margin: 10px 0 0 20px;
- padding: 0;
-}
-
-ul.search li {
- padding: 5px 0 5px 20px;
- background-image: url(file.png);
- background-repeat: no-repeat;
- background-position: 0 7px;
-}
-
-ul.search li a {
- font-weight: bold;
-}
-
-ul.search li div.context {
- color: #888;
- margin: 2px 0 0 30px;
- text-align: left;
-}
-
-ul.keywordmatches li.goodmatch a {
- font-weight: bold;
-}
-
-/* :::: COMMON FORM STYLES :::: */
-
-div.actions {
- padding: 5px 10px 5px 10px;
- border-top: 1px solid #cbe7e5;
- border-bottom: 1px solid #cbe7e5;
- background-color: #e0f6f4;
-}
-
-form dl {
- color: #333;
-}
-
-form dt {
- clear: both;
- float: left;
- min-width: 110px;
- margin-right: 10px;
- padding-top: 2px;
-}
-
-input#homepage {
- display: none;
-}
-
-div.error {
- margin: 5px 20px 0 0;
- padding: 5px;
- border: 1px solid #d00;
- font-weight: bold;
-}
-
-/* :::: INLINE COMMENTS :::: */
-
-div.inlinecomments {
- position: absolute;
- right: 20px;
-}
-
-div.inlinecomments a.bubble {
- display: block;
- float: right;
- background-image: url(style/comment.png);
- background-repeat: no-repeat;
- width: 25px;
- height: 25px;
- text-align: center;
- padding-top: 3px;
- font-size: 0.9em;
- line-height: 14px;
- font-weight: bold;
- color: black;
-}
-
-div.inlinecomments a.bubble span {
- display: none;
-}
-
-div.inlinecomments a.emptybubble {
- background-image: url(style/nocomment.png);
-}
-
-div.inlinecomments a.bubble:hover {
- background-image: url(style/hovercomment.png);
- text-decoration: none;
- color: #3ca0a4;
-}
-
-div.inlinecomments div.comments {
- float: right;
- margin: 25px 5px 0 0;
- max-width: 50em;
- min-width: 30em;
- border: 1px solid #2eabb0;
- background-color: #f2fbfd;
- z-index: 150;
-}
-
-div#comments {
- border: 1px solid #2eabb0;
- margin-top: 20px;
-}
-
-div#comments div.nocomments {
- padding: 10px;
- font-weight: bold;
-}
-
-div.inlinecomments div.comments h3,
-div#comments h3 {
- margin: 0;
- padding: 0;
- background-color: #2eabb0;
- color: white;
- border: none;
- padding: 3px;
-}
-
-div.inlinecomments div.comments div.actions {
- padding: 4px;
- margin: 0;
- border-top: none;
-}
-
-div#comments div.comment {
- margin: 10px;
- border: 1px solid #2eabb0;
-}
-
-div.inlinecomments div.comment h4,
-div.commentwindow div.comment h4,
-div#comments div.comment h4 {
- margin: 10px 0 0 0;
- background-color: #2eabb0;
- color: white;
- border: none;
- padding: 1px 4px 1px 4px;
-}
-
-div#comments div.comment h4 {
- margin: 0;
-}
-
-div#comments div.comment h4 a {
- color: #d5f4f4;
-}
-
-div.inlinecomments div.comment div.text,
-div.commentwindow div.comment div.text,
-div#comments div.comment div.text {
- margin: -5px 0 -5px 0;
- padding: 0 10px 0 10px;
-}
-
-div.inlinecomments div.comment div.meta,
-div.commentwindow div.comment div.meta,
-div#comments div.comment div.meta {
- text-align: right;
- padding: 2px 10px 2px 0;
- font-size: 95%;
- color: #538893;
- border-top: 1px solid #cbe7e5;
- background-color: #e0f6f4;
-}
-
-div.commentwindow {
- position: absolute;
- width: 500px;
- border: 1px solid #cbe7e5;
- background-color: #f2fbfd;
- display: none;
- z-index: 130;
-}
-
-div.commentwindow h3 {
- margin: 0;
- background-color: #2eabb0;
- color: white;
- border: none;
- padding: 5px;
- font-size: 1.5em;
- cursor: pointer;
-}
-
-div.commentwindow div.actions {
- margin: 10px -10px 0 -10px;
- padding: 4px 10px 4px 10px;
- color: #538893;
-}
-
-div.commentwindow div.actions input {
- border: 1px solid #2eabb0;
- background-color: white;
- color: #135355;
- cursor: pointer;
-}
-
-div.commentwindow div.form {
- padding: 0 10px 0 10px;
-}
-
-div.commentwindow div.form input,
-div.commentwindow div.form textarea {
- border: 1px solid #3c9ea2;
- background-color: white;
- color: black;
-}
-
-div.commentwindow div.error {
- margin: 10px 5px 10px 5px;
- background-color: #fbe5dc;
- display: none;
-}
-
-div.commentwindow div.form textarea {
- width: 99%;
-}
-
-div.commentwindow div.preview {
- margin: 10px 0 10px 0;
- background-color: #70d0d4;
- padding: 0 1px 1px 25px;
-}
-
-div.commentwindow div.preview h4 {
- margin: 0 0 -5px -20px;
- padding: 4px 0 0 4px;
- color: white;
- font-size: 1.3em;
-}
-
-div.commentwindow div.preview div.comment {
- background-color: #f2fbfd;
-}
-
-div.commentwindow div.preview div.comment h4 {
- margin: 10px 0 0 0!important;
- padding: 1px 4px 1px 4px!important;
- font-size: 1.2em;
-}
-
-/* :::: SUGGEST CHANGES :::: */
-div#suggest-changes-box input, div#suggest-changes-box textarea {
- border: 1px solid #ccc;
- background-color: white;
- color: black;
-}
-
-div#suggest-changes-box textarea {
- width: 99%;
- height: 400px;
-}
-
-
-/* :::: PREVIEW :::: */
-div.preview {
- background-image: url(style/preview.png);
- padding: 0 20px 20px 20px;
- margin-bottom: 30px;
-}
-
-
-/* :::: INDEX PAGE :::: */
-
-table.contentstable {
- width: 90%;
-}
-
-table.contentstable p.biglink {
- line-height: 150%;
-}
-
-a.biglink {
- font-size: 1.3em;
-}
-
-span.linkdescr {
- font-style: italic;
- padding-top: 5px;
- font-size: 90%;
-}
-
-/* :::: INDEX STYLES :::: */
-
-table.indextable td {
- text-align: left;
- vertical-align: top;
-}
-
-table.indextable dl, table.indextable dd {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-table.indextable tr.pcap {
- height: 10px;
-}
-
-table.indextable tr.cap {
- margin-top: 10px;
- background-color: #f2f2f2;
-}
-
-img.toggler {
- margin-right: 3px;
- margin-top: 3px;
- cursor: pointer;
-}
-
-form.pfform {
- margin: 10px 0 20px 0;
-}
-
-/* :::: GLOBAL STYLES :::: */
-
-.docwarning {
- background-color: #ffe4e4;
- padding: 10px;
- margin: 0 -20px 0 -20px;
- border-bottom: 1px solid #f66;
-}
-
-p.subhead {
- font-weight: bold;
- margin-top: 20px;
-}
-
-a {
- color: orangered;
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-div.body h1,
-div.body h2,
-div.body h3,
-div.body h4,
-div.body h5,
-div.body h6 {
- font-family: 'Verdana', sans-serif;
- background-color: white;
- font-weight: bold;
- color: black;
- border-bottom: 1px solid #ccc;
- margin: 20px -20px 10px -20px;
- padding: 3px 0 3px 10px;
-}
-
-div.body h1 { margin-top: 10pt; font-size: 150%; }
-div.body h2 { font-size: 120%; }
-div.body h3 { font-size: 100%; }
-div.body h4 { font-size: 80%; }
-div.body h5 { font-size: 600%; }
-div.body h6 { font-size: 40%; }
-
-a.headerlink {
- color: #c60f0f;
- font-size: 0.8em;
- padding: 0 4px 0 4px;
- text-decoration: none;
- visibility: hidden;
-}
-
-h1:hover > a.headerlink,
-h2:hover > a.headerlink,
-h3:hover > a.headerlink,
-h4:hover > a.headerlink,
-h5:hover > a.headerlink,
-h6:hover > a.headerlink,
-dt:hover > a.headerlink {
- visibility: visible;
-}
-
-a.headerlink:hover {
- background-color: #c60f0f;
- color: white;
-}
-
-div.body p, div.body dd, div.body li {
- text-align: justify;
- line-height: 130%;
-}
-
-div.body p.caption {
- text-align: inherit;
-}
-
-div.body td {
- text-align: left;
-}
-
-ul.fakelist {
- list-style: none;
- margin: 10px 0 10px 20px;
- padding: 0;
-}
-
-.field-list ul {
- padding-left: 1em;
-}
-
-.first {
- margin-top: 0 !important;
-}
-
-/* "Footnotes" heading */
-p.rubric {
- margin-top: 30px;
- font-weight: bold;
-}
-
-/* "Topics" */
-
-div.topic {
- background-color: #eee;
- border: 1px solid #ccc;
- padding: 0 7px 0 7px;
- margin: 10px 0 10px 0;
-}
-
-p.topic-title {
- font-size: 1.1em;
- font-weight: bold;
- margin-top: 10px;
-}
-
-/* Admonitions */
-
-div.admonition {
- margin-top: 10px;
- margin-bottom: 10px;
- padding: 7px;
-}
-
-div.admonition dt {
- font-weight: bold;
-}
-
-div.admonition dl {
- margin-bottom: 0;
-}
-
-div.admonition p {
- display: inline;
-}
-
-div.seealso {
- background-color: #ffc;
- border: 1px solid #ff6;
-}
-
-div.warning {
- background-color: #ffe4e4;
- border: 1px solid #f66;
-}
-
-div.note {
- background-color: #eee;
- border: 1px solid #ccc;
-}
-
-p.admonition-title {
- margin: 0px 10px 5px 0px;
- font-weight: bold;
- display: inline;
-}
-
-p.admonition-title:after {
- content: ":";
-}
-
-div.body p.centered {
- text-align: center;
- margin-top: 25px;
-}
-
-table.docutils {
- border: 0;
-}
-
-table.docutils td, table.docutils th {
- padding: 1px 8px 1px 0;
- border-top: 0;
- border-left: 0;
- border-right: 0;
- border-bottom: 1px solid #aaa;
-}
-
-table.field-list td, table.field-list th {
- border: 0 !important;
-}
-
-table.footnote td, table.footnote th {
- border: 0 !important;
-}
-
-.field-list ul {
- margin: 0;
- padding-left: 1em;
-}
-
-.field-list p {
- margin: 0;
-}
-
-dl {
- margin-bottom: 15px;
- clear: both;
-}
-
-dd p {
- margin-top: 0px;
-}
-
-dd ul, dd table {
- margin-bottom: 10px;
-}
-
-dd {
- margin-top: 3px;
- margin-bottom: 10px;
- margin-left: 30px;
-}
-
-.refcount {
- color: #060;
-}
-
-dt:target,
-.highlight {
- background-color: #fbe54e;
-}
-
-dl.glossary dt {
- font-weight: bold;
- font-size: 1.1em;
-}
-
-th {
- text-align: left;
- padding-right: 5px;
-}
-
-pre {
- padding: 5px;
- background-color: #efc;
- color: #333;
- border: 1px solid #ac9;
- border-left: none;
- border-right: none;
- overflow: auto;
-}
-
-td.linenos pre {
- padding: 5px 0px;
- border: 0;
- background-color: transparent;
- color: #aaa;
-}
-
-table.highlighttable {
- margin-left: 0.5em;
-}
-
-table.highlighttable td {
- padding: 0 0.5em 0 0.5em;
-}
-
-tt {
- background-color: #ecf0f3;
- padding: 0 1px 0 1px;
- font-size: 0.95em;
-}
-
-tt.descname {
- background-color: transparent;
- font-weight: bold;
- font-size: 1.2em;
-}
-
-tt.descclassname {
- background-color: transparent;
-}
-
-tt.xref, a tt {
- background-color: transparent;
- font-weight: bold;
-}
-
-.footnote:target { background-color: #ffa }
-
-h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
- background-color: transparent;
-}
-
-.optional {
- font-size: 1.3em;
-}
-
-.versionmodified {
- font-style: italic;
-}
-
-form.comment {
- margin: 0;
- padding: 10px 30px 10px 30px;
- background-color: #eee;
-}
-
-form.comment h3 {
- background-color: #326591;
- color: white;
- margin: -10px -30px 10px -30px;
- padding: 5px;
- font-size: 1.4em;
-}
-
-form.comment input,
-form.comment textarea {
- border: 1px solid #ccc;
- padding: 2px;
- font-family: sans-serif;
- font-size: 100%;
-}
-
-form.comment input[type="text"] {
- width: 240px;
-}
-
-form.comment textarea {
- width: 100%;
- height: 200px;
- margin-bottom: 10px;
-}
-
-.system-message {
- background-color: #fda;
- padding: 5px;
- border: 3px solid red;
-}
-
-/* :::: PRINT :::: */
-@media print {
- div.document,
- div.documentwrapper,
- div.bodywrapper {
- margin: 0;
- width : 100%;
- }
-
- div.sphinxsidebar,
- div.related,
- div.footer,
- div#comments div.new-comment-box,
- #top-link {
- display: none;
- }
-}
--- a/doc/book/en/.templates/layout.html Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-{%- block doctype -%}
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-{%- endblock %}
-{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %}
-{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %}
-{%- macro relbar() %}
- <div class="related">
- <h3>Navigation</h3>
- <ul>
- {%- for rellink in rellinks %}
- <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
- <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags }}"
- accesskey="{{ rellink[2] }}">{{ rellink[3] }}</a>
- {%- if not loop.first %}{{ reldelim2 }}{% endif %}</li>
- {%- endfor %}
- {%- block rootrellink %}
- <li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li>
- {%- endblock %}
- {%- for parent in parents %}
- <li><a href="{{ parent.link|e }}" accesskey="U">{{ parent.title }}</a>{{ reldelim1 }}</li>
- {%- endfor %}
- {%- block relbaritems %}{% endblock %}
- </ul>
- </div>
-{%- endmacro %}
-{%- macro sidebar() %}
- {%- if builder != 'htmlhelp' %}
- <div class="sphinxsidebar">
- <div class="sphinxsidebarwrapper">
- {%- block sidebarlogo %}
- {%- if logo %}
- <p class="logo"><img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/></p>
- {%- endif %}
- {%- endblock %}
- {%- block sidebartoc %}
- {%- if display_toc %}
- <h3>Table Of Contents</h3>
- {{ toc }}
- {%- endif %}
- {%- endblock %}
- {%- block sidebarrel %}
- {%- if prev %}
- <h4>Previous topic</h4>
- <p class="topless"><a href="{{ prev.link|e }}" title="previous chapter">{{ prev.title }}</a></p>
- {%- endif %}
- {%- if next %}
- <h4>Next topic</h4>
- <p class="topless"><a href="{{ next.link|e }}" title="next chapter">{{ next.title }}</a></p>
- {%- endif %}
- {%- endblock %}
- {%- if sourcename %}
- <!--<h3>This Page</h3>
- <ul class="this-page-menu">
- {%- if builder == 'web' %}
- <li><a href="#comments">Comments ({{ comments|length }} so far)</a></li>
- <li><a href="{{ pathto('@edit/' + sourcename)|e }}">Suggest Change</a></li>
- <li><a href="{{ pathto('@source/' + sourcename)|e }}">Show Source</a></li>
- {%- elif builder == 'html' %}
- <li><a href="{{ pathto('_sources/' + sourcename, true)|e }}">Show Source</a></li>
- {%- endif %}
- </ul>-->
- {%- endif %}
- {%- if customsidebar %}
- {{ rendertemplate(customsidebar) }}
- {%- endif %}
- {%- block sidebarsearch %}
- {%- if pagename != "search" %}
- <h3>{{ builder == 'web' and 'Keyword' or 'Quick' }} search</h3>
- <form class="search" action="{{ pathto('search') }}" method="get">
- <input type="text" name="q" size="18" /> <input type="submit" value="Go" />
- <input type="hidden" name="check_keywords" value="yes" />
- <input type="hidden" name="area" value="default" />
- </form>
- {%- if builder == 'web' %}
- <p style="font-size: 90%">Enter a module, class or function name.</p>
- {%- endif %}
- {%- endif %}
- {%- endblock %}
- </div>
- </div>
- {%- endif %}
-{%- endmacro -%}
-
-<html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- {%- if builder != 'htmlhelp' %}
- {%- set titlesuffix = " — " + docstitle %}
- {%- endif %}
- <title>{{ title|striptags }}{{ titlesuffix }}</title>
- {%- if builder == 'web' %}
- <link rel="stylesheet" href="{{ pathto('index') }}?do=stylesheet{%
- if in_admin_panel %}&admin=yes{% endif %}" type="text/css" />
- {%- for link, type, title in page_links %}
- <link rel="alternate" type="{{ type|e(true) }}" title="{{ title|e(true) }}" href="{{ link|e(true) }}" />
- {%- endfor %}
- {%- else %}
- <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
- <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
- {%- endif %}
- {%- if builder != 'htmlhelp' %}
- <script type="text/javascript">
- var DOCUMENTATION_OPTIONS = {
- URL_ROOT: '{{ pathto("", 1) }}',
- VERSION: '{{ release }}',
- COLLAPSE_MODINDEX: false,
- FILE_SUFFIX: '{{ file_suffix }}'
- };
- </script>
- <script type="text/javascript" src="{{ pathto('_static/jquery.js', 1) }}"></script>
- <script type="text/javascript" src="{{ pathto('_static/interface.js', 1) }}"></script>
- <script type="text/javascript" src="{{ pathto('_static/doctools.js', 1) }}"></script>
- <script type="text/javascript" src="{{ pathto('_static/searchtools.js', 1) }}"></script>
- {%- if use_opensearch %}
- <link rel="search" type="application/opensearchdescription+xml"
- title="Search within {{ docstitle }}"
- href="{{ pathto('_static/opensearch.xml', 1) }}"/>
- {%- endif %}
- {%- if favicon %}
- <link rel="shortcut icon" href="{{ pathto('_static/' + favicon, 1) }}"/>
- {%- endif %}
- {%- endif %}
-{%- block rellinks %}
- {%- if hasdoc('about') %}
- <link rel="author" title="About these documents" href="{{ pathto('about') }}" />
- {%- endif %}
- <link rel="contents" title="Global table of contents" href="{{ pathto('contents') }}" />
- <link rel="index" title="Global index" href="{{ pathto('genindex') }}" />
- <link rel="search" title="Search" href="{{ pathto('search') }}" />
- {%- if hasdoc('copyright') %}
- <link rel="copyright" title="Copyright" href="{{ pathto('copyright') }}" />
- {%- endif %}
- <link rel="top" title="{{ docstitle }}" href="{{ pathto('index') }}" />
- {%- if parents %}
- <link rel="up" title="{{ parents[-1].title|striptags }}" href="{{ parents[-1].link|e }}" />
- {%- endif %}
- {%- if next %}
- <link rel="next" title="{{ next.title|striptags }}" href="{{ next.link|e }}" />
- {%- endif %}
- {%- if prev %}
- <link rel="prev" title="{{ prev.title|striptags }}" href="{{ prev.link|e }}" />
- {%- endif %}
-{%- endblock %}
-{%- block extrahead %}{% endblock %}
- </head>
- <body>
-
-{% block logilablogo %}
-<div class="logilablogo">
- <a class="logogo" href="http://www.cubicweb.org"><img border="0" src="{{ pathto('_static/cubicweb.png', 1) }}"/></a>
- </div>
-{% endblock %}
-
-{%- block relbar1 %}{{ relbar() }}{% endblock %}
-
-{%- block sidebar1 %}{# possible location for sidebar #}{% endblock %}
-
-{%- block document %}
- <div class="document">
- <div class="documentwrapper">
- {%- if builder != 'htmlhelp' %}
- <div class="bodywrapper">
- {%- endif %}
- <div class="body">
- {% block body %}{% endblock %}
- </div>
- {%- if builder != 'htmlhelp' %}
- </div>
- {%- endif %}
- </div>
-{%- endblock %}
-
-{%- block sidebar2 %}{{ sidebar() }}{% endblock %}
- <div class="clearer"></div>
- </div>
-
-{%- block relbar2 %}{{ relbar() }}{% endblock %}
-
-{%- block footer %}
- <div class="footer">
- {%- if hasdoc('copyright') %}
- © <a href="{{ pathto('copyright') }}">Copyright</a> {{ copyright }}.
- {%- else %}
- © Copyright {{ copyright }}.
- {%- endif %}
- {%- if last_updated %}
- Last updated on {{ last_updated }}.
- {%- endif %}
- {%- if show_sphinx %}
- Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.
- {%- endif %}
- </div>
-{%- endblock %}
- </body>
-</html>
--- a/doc/book/en/MERGE_ME-tut-create-app.en.txt Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,386 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-
-Tutoriel : créer votre première application web pour Google AppEngine
-=====================================================================
-
-[TRANSLATE ME TO FRENCH]
-
-This tutorial will guide you step by step to build a blog application
-and discover the unique features of `LAX`. It assumes that you followed
-the :ref:`installation` guidelines and that both the `AppEngine SDK` and the
-`LAX` framework are setup on your computer.
-
-Creating a new application
---------------------------
-
-We choosed in this tutorial to develop a blog as an example of web application
-and will go through each required steps/actions to have it running with `LAX`.
-When you installed `LAX`, you saw a directory named ``skel``. Make a copy of
-this directory and call it ``BlogDemo``.
-
-The location of this directory does not matter. But once decided, make sure your ``PYTHONPATH`` is properly set (:ref:`installation`).
-
-
-Defining a schema
------------------
-
-With `LAX`, the schema/datamodel is the core of the application. This is where
-you will define the type of content you have to hanlde in your application.
-
-Let us start with something simple and improve on it iteratively.
-
-In schema.py, we define two entities: ``Blog`` and ``BlogEntry``.
-
-::
-
- class Blog(EntityType):
- title = String(maxsize=50, required=True)
- description = String()
-
- class BlogEntry(EntityType):
- title = String(maxsize=100, required=True)
- publish_date = Date(default='TODAY')
- text = String(fulltextindexed=True)
- category = String(vocabulary=('important','business'))
- entry_of = SubjectRelation('Blog', cardinality='?*')
-
-A Blog has a title and a description. The title is a string that is
-required 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 text. The title is a
-string that is required and must be less than 100 characters. The
-publish_date is a Date with a default value of TODAY, meaning that
-when a BlogEntry is created, its publish_date will be the current day
-unless it is modified. The text is a string that will be indexed in
-the full-text index and has no constraint.
-
-A BlogEntry also has a relationship ``entry_of`` that link it to a
-Blog. The cardinality ``?*`` means that a BlogEntry can be part of
-zero or one Blog (``?`` means `zero or one`) and that a Blog can
-have any number of BlogEntry (``*`` means `any number including
-zero`). For completeness, remember that ``+`` means `one or more`.
-
-Running the application
------------------------
-
-Defining this simple schema is enough to get us started. Make sure you
-followed the setup steps described in detail in the installation
-chapter (especially visiting http://localhost:8080/_load as an
-administrator), then launch the application with the command::
-
- python dev_appserver.py BlogDemo
-
-and point your browser at http://localhost:8080/ (if it is easier for
-you, use the on-line demo at http://lax.appspot.com/).
-
-.. image:: images/lax-book.00-login.en.png
- :alt: login screen
-
-After you log in, you will see the home page of your application. It
-lists the entity types: Blog and BlogEntry. If these links read
-``blog_plural`` and ``blogentry_plural`` it is because
-internationalization (i18n) is not working for you yet. Please ignore
-this for now.
-
-.. image:: images/lax-book.01-start.en.png
- :alt: home page
-
-Creating system entities
-------------------------
-You can only create new users if you decided not to use google authentication.
-
-
-[WRITE ME : create users manages permissions etc]
-
-
-
-Creating application entites
-----------------------------
-
-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/lax-book.02-create-blog.en.png
- :alt: from to create blog
-
-Click on the logo at top left to get back to the home page, then
-follow the Blog link 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/lax-book.03-list-one-blog.en.png
- :alt: displaying a list of a single blog
-
-Clicking on this item will get you to its detailed description except
-that in this case, there is not much to display besides the name and
-the phrase ``everything about technology``.
-
-.. image:: images/lax-book.04-detail-one-blog.en.png
- :alt: displaying the detailed view of a blog
-
-Now get back to the home page by clicking on the top-left logo, then
-create a new Blog called ``MyLife`` and get back to the home page
-again to follow the Blog link for the second time. The list now
-has two items.
-
-.. image:: images/lax-book.05-list-two-blog.en.png
- :alt: displaying a list of two blogs
-
-
-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/lax-book.06-add-relation-entryof.en.png
- :alt: editing a blog entry to add a relation to a blog
-
-Validate the changes by clicking ``Validate``. The entity BlogEntry
-that is displayed now includes a link to the entity Blog named
-``MyLife``.
-
-.. image:: images/lax-book.07-detail-one-blogentry.en.png
- :alt: displaying the detailed view of a blogentry
-
-Remember that all of this was handled by the framework and that the
-only input that was provided so far is the schema. To get a graphical
-view of the schema, run the ``laxctl genschema BlogDemo`` command as
-explained in the installation section and point your browser to the
-URL http://localhost:8080/schema
-
-.. image:: images/lax-book.08-schema.en.png
- :alt: graphical view of the schema (aka data-model)
-
-Site configuration
-------------------
-
-.. image:: images/lax-book.03-site-config-panel.en.png
-
-This panel allows you to configure the appearance of your application site.
-Six menus are available and we will go through each of them to explain how
-to use them.
-
-Navigation
-~~~~~~~~~~
-This menu provides you a way to adjust some navigation options depending on
-your needs, such as the number of entities to display by page of results.
-Follows the detailled list of available options:
-
-* navigation.combobox-limit: maximum number of entities to display in related
- combo box (sample format: 23)
-* navigation.page-size: maximum number of objects displayed by page of results
- (sample format: 23)
-* navigation.related-limit: maximum number of related entities to display in
- the primary view (sample format: 23)
-* navigation.short-line-size: maximum number of characters in short description
- (sample format: 23)
-
-UI
-~~
-This menu provides you a way to customize the user interface settings such as
-date format or encoding in the produced html.
-Follows the detailled list of available options:
-
-* ui.date-format : how to format date in the ui ("man strftime" for format description)
-* ui.datetime-format : how to format date and time in the ui ("man strftime" for format
- description)
-* ui.default-text-format : default text format for rich text fields.
-* ui.encoding : user interface encoding
-* ui.fckeditor : should html fields being edited using fckeditor (a HTML WYSIWYG editor).
- You should also select text/html as default text format to actually get fckeditor.
-* ui.float-format : how to format float numbers in the ui
-* ui.language : language of the user interface
-* ui.main-template : id of main template used to render pages
-* ui.site-title : site title, which is displayed right next to the logo in the header
-* ui.time-format : how to format time in the ui ("man strftime" for format description)
-
-
-Actions
-~~~~~~~
-This menu provides a way to configure the context in which you expect the actions
-to be displayed to the user and if you want the action to be visible or not.
-You must have notice that when you view a list of entities, an action box is
-available on the left column which display some actions as well as a drop-down
-menu for more actions.
-
-The context available are:
-
-* mainactions : actions listed in the left box
-* moreactions : actions listed in the `more` menu of the left box
-* addrelated : add actions listed in the left box
-* useractions : actions listed in the first section of drop-down menu
- accessible from the right corner user login link
-* siteactions : actions listed in the second section of drop-down menu
- accessible from the right corner user login link
-* hidden : select this to hide the specific action
-
-Boxes
-~~~~~
-The application has already a pre-defined set of boxes you can use right away.
-This configuration section allows you to place those boxes where you want in the
-application interface to customize it.
-
-The available boxes are:
-
-* actions box : box listing the applicable actions on the displayed data
-
-* boxes_blog_archives_box : box listing the blog archives
-
-* possible views box : box listing the possible views for the displayed data
-
-* rss box : RSS icon to get displayed data as a RSS thread
-
-* search box : search box
-
-* startup views box : box listing the configuration options available for
- the application site, such as `Preferences` and `Site Configuration`
-
-Components
-~~~~~~~~~~
-[WRITE ME]
-
-Contextual components
-~~~~~~~~~~~~~~~~~~~~~
-[WRITE ME]
-
-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('CWGroup', 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.
-
-Change view permission
-~~~~~~~~~~~~~~~~~~~~~~
-
-
-
-Conclusion
-----------
-
-Exercise
-~~~~~~~~
-
-Create new blog entries in ``Tech-blog``.
-
-What we learned
-~~~~~~~~~~~~~~~
-
-Creating a simple schema was enough to set up a new application that
-can store blogs and blog entries.
-
-What is next ?
-~~~~~~~~~~~~~~
-
-Although the application is fully functionnal, its look is very
-basic. In the following section we will learn to create views to
-customize how data is displayed.
-
-
--- a/doc/book/en/MERGE_ME-tut-create-gae-app.en.txt Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _tutorielGAE:
-
-Tutoriel : créer votre première application web pour Google AppEngine
-=====================================================================
-
-Ce tutoriel va vous guider pas à pas a construire une apllication web
-de gestion de Blog afin de vous faire découvrir les fonctionnalités de
-*CubicWeb*.
-
-Nous supposons que vous avec déjà suivi le guide :ref:`installationGAE`.
-
-
-Créez une nouvelle application
-------------------------------
-
-Nous choisissons dans ce tutoriel de développer un blog comme un exemple
-d'application web et nous allons expliciter toutes les étapes nécessaires
-à sa réalisation.
-
-::
-
- cubicweb-ctl newgapp blogdemo
-
-`newgapp` est la commande permettant de créer une instance *CubicWeb* pour
-le datastore.
-
-Assurez-vous que votre variable d'environnement ``PYTHONPATH`` est correctement
-initialisée (:ref:`installationGAE`)
-
-Définissez un schéma
---------------------
-
-Le modèle de données ou schéma est au coeur d'une application *CubicWeb*.
-C'est là où vous allez devoir définir le type de contenu que votre application
-devra gérer.
-
-Commençons par un schéma simple que nous améliorerons progressivemment.
-
-Une fois votre instance ``blogdemo`` crée, vous trouverez un fichier ``schema.py``
-contenant la définition des entités suivantes : ``Blog`` and ``BlogEntry``.
-
-::
-
- class Blog(EntityType):
- title = String(maxsize=50, required=True)
- description = String()
-
- class BlogEntry(EntityType):
- title = String(maxsize=100, required=True)
- publish_date = Date(default='TODAY')
- text = String(fulltextindexed=True)
- category = String(vocabulary=('important','business'))
- entry_of = SubjectRelation('Blog', cardinality='?*')
-
-
-Un ``Blog`` a un titre et une description. Le titre est une chaîne
-de caractères requise par la classe parente EntityType and ne doit
-pas excéder 50 caractères. La description est une chaîne de
-caractères sans contraintes.
-
-Une ``BlogEntry`` a un titre, une date de publication et du texte
-étant son contenu. Le titre est une chaîne de caractères qui ne
-doit pas excéder 100 caractères. La date de publication est de type Date et a
-pour valeur par défaut TODAY, ce qui signifie que lorsqu'une
-``BlogEntry`` sera créée, sa date de publication sera la date
-courante a moins de modifier ce champ. Le texte est une chaîne de
-caractères qui sera indexée en plein texte et sans contraintes.
-
-Une ``BlogEntry`` a aussi une relation nommée ``entry_of`` qui la
-relie à un ``Blog``. La cardinalité ``?*`` signifie que BlogEntry
-peut faire partie de zero a un Blog (``?`` signifie `zero ou un`) et
-qu'un Blog peut avoir une infinité de BlogEntry (``*`` signifie
-`n'importe quel nombre incluant zero`).
-Par soucis de complétude, nous rappellerons que ``+`` signifie
-`un ou plus`.
-
-Lancez l'application
---------------------
-
-Définir ce simple schéma est suffisant pour commencer. Assurez-vous
-que vous avez suivi les étapes décrites dans la section installation
-(en particulier visitez http://localhost:8080/_load en tant qu'administrateur
-afin d'initialiser le datastore), puis lancez votre application avec la commande ::
-
- python dev_appserver.py BlogDemo
-
-puis dirigez vous vers http://localhost:8080/ (ou si c'est plus facile
-vous pouvez utiliser la démo en ligne http://lax.appspot.com/).
-[FIXME] -- changer la demo en ligne en quelque chose qui marche (!)
-
-.. image:: images/lax-book.00-login.en.png
- :alt: login screen
-
-Après vous être authentifié, vous arrivez sur la page d'accueil de votre
-application. Cette page liste les types d'entités accessibles dans votre
-application, en l'occurrence : Blog et Articles. Si vous lisez ``blog_plural``
-et ``blogentry_plural`` cela signifie que l'internationalisation (i18n)
-n'a pas encore fonctionné. Ignorez cela pour le moment.
-
-.. image:: images/lax-book.01-start.en.png
- :alt: home page
-
-Créez des entités système
--------------------------
-
-Vous ne pourrez créer de nouveaux utilisateurs que dans le cas où vous
-avez choisi de ne pas utiliser l'authentification Google.
-
-
-[WRITE ME : create users manages permissions etc]
-
-
-
-Créez des entités applicatives
-------------------------------
-
-Créez un Blog
-~~~~~~~~~~~~~
-
-Créons à présent quelques entités. Cliquez sur `[+]` sur la
-droite du lien Blog. Appelez cette nouvelle entité Blog ``Tech-Blog``
-et tapez pour la description ``everything about technology``,
-puis validez le formulaire d'édition en cliquant sur le bouton
-``Validate``.
-
-
-.. image:: images/lax-book.02-create-blog.en.png
- :alt: from to create blog
-
-En cliquant sur le logo situé dans le coin gauche de la fenêtre,
-vous allez être redirigé vers la page d'accueil. Ensuite, si vous allez
-sur le lien Blog, vous devriez voir la liste des entités Blog, en particulier
-celui que vous venez juste de créer ``Tech-Blog``.
-
-.. image:: images/lax-book.03-list-one-blog.en.png
- :alt: displaying a list of a single blog
-
-Si vous cliquez sur ``Tech-Blog`` vous devriez obtenir une description
-détaillée, ce qui dans notre cas, n'est rien de plus que le titre
-et la phrase ``everything about technology``
-
-
-.. image:: images/lax-book.04-detail-one-blog.en.png
- :alt: displaying the detailed view of a blog
-
-Maintenant retournons sur la page d'accueil et créons un nouveau
-Blog ``MyLife`` et retournons sur la page d'accueil, puis suivons
-le lien Blog et nous constatons qu'à présent deux blogs sont listés.
-
-.. image:: images/lax-book.05-list-two-blog.en.png
- :alt: displaying a list of two blogs
-
-Créons un article
-~~~~~~~~~~~~~~~~~
-
-Revenons sur la page d'accueil et cliquons sur `[+]` Ã droite du lien
-`articles`. Appellons cette nouvelle entité ``Hello World`` et introduisons
-un peut de texte avant de ``Valider``. Vous venez d'ajouter un article
-sans avoir précisé à quel Blog il appartenait. Dans la colonne de gauche
-se trouve une boite intitulé ``actions``, cliquez sur le menu ``modifier``.
-Vous êtes de retour sur le formulaire d'édition de l'article que vous
-venez de créer, à ceci près que ce formulaire a maintenant une nouvelle
-section intitulée ``ajouter relation``. Choisissez ``entry_of`` dans ce menu,
-cela va faire apparaitre une deuxième menu déroulant dans lequel vous
-allez pouvoir séléctionner le Blog ``MyLife``.
-
-Vous auriez pu aussi, au moment où vous avez crée votre article, sélectionner
-``appliquer`` au lieu de ``valider`` et le menu ``ajouter relation`` serait apparu.
-
-.. image:: images/lax-book.06-add-relation-entryof.en.png
- :alt: editing a blog entry to add a relation to a blog
-
-Validez vos modifications en cliquant sur ``Valider``. L'entité article
-qui est listée contient maintenant un lien vers le Blog auquel il
-appartient, ``MyLife``.
-
-.. image:: images/lax-book.07-detail-one-blogentry.en.png
- :alt: displaying the detailed view of a blogentry
-
-Rappelez-vous que pour le moment, tout a été géré par la plate-forme
-*CubicWeb* et que la seule chose qui a été fournie est le schéma de
-données. D'ailleurs pour obtenir une vue graphique du schéma, exécutez
-la commande ``laxctl genschema blogdemo`` et vous pourrez visualiser
-votre schéma a l'URL suivante : http://localhost:8080/schema
-
-.. image:: images/lax-book.08-schema.en.png
- :alt: graphical view of the schema (aka data-model)
-
-
-Change view permission
-~~~~~~~~~~~~~~~~~~~~~~
-
-
-
-Conclusion
-----------
-
-Exercise
-~~~~~~~~
-
-Create new blog entries in ``Tech-blog``.
-
-What we learned
-~~~~~~~~~~~~~~~
-
-Creating a simple schema was enough to set up a new application that
-can store blogs and blog entries.
-
-What is next ?
-~~~~~~~~~~~~~~
-
-Although the application is fully functionnal, its look is very
-basic. In the following section we will learn to create views to
-customize how data is displayed.
-
-
--- a/doc/book/en/_themes/cubicweb/layout.html Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-{% extends "basic/layout.html" %}
-
-{%- block extrahead %}
-<!--[if lte IE 6]>
-<link rel="stylesheet" href="{{ pathto('_static/ie6.css', 1) }}" type="text/css" media="screen" charset="utf-8" />
-<![endif]-->
-{%- if theme_favicon %}
-<link rel="shortcut icon" href="{{ pathto('_static/'+theme_favicon, 1) }}"/>
-{%- endif %}
-
-{%- if theme_canonical_url %}
-<link rel="canonical" href="{{ theme_canonical_url }}{{ pagename }}.html"/>
-{%- endif %}
-{% endblock %}
-
-{% block header %}
-
-{% if theme_in_progress|tobool %}
- <img style="position: fixed; display: block; width: 165px; height: 165px; bottom: 60px; right: 0; border: 0;" src="{{ pathto('_static/in_progress.png', 1) }}" alt="Documentation in progress" />
-{% endif %}
-
-{% if theme_outdated|tobool %}
- <div style="bottom: 60px; right: 20px;position: fixed;"><a href="{{ latest_url }}" class="btn btn-large btn-danger"><strong>></strong> Read the latest version of this page</a></div>
-{% endif %}
-
-<div class="header-small">
- {%- if theme_logo %}
- {% set img, ext = theme_logo.split('.', -1) %}
- <div class="logo-small">
- <a href="{{ pathto(master_doc) }}">
- <img class="logo" src="{{ pathto('_static/%s-small.%s' % (img, ext), 1)}}" alt="Logo"/>
- </a>
- </div>
- {%- endif %}
-</div>
-{% endblock %}
-
-{%- macro relbar() %}
-<div class="related">
- <h3>{{ _('Navigation') }}</h3>
- <ul>
- {%- for rellink in rellinks %}
- <li class="right" {% if loop.first %}style="margin-right: 10px"{% endif %}>
- <a href="{{ pathto(rellink[0]) }}" title="{{ rellink[1]|striptags|e }}"
- {{ accesskey(rellink[2]) }}>{{ rellink[3] }}</a>
- {%- if not loop.first %}{{ reldelim2 }}{% endif %}
- </li>
- {%- endfor %}
- {%- block rootrellink %}
- <li><a href="{{ pathto(master_doc) }}">{{ docstitle|e }}</a>{{ reldelim1 }}</li>
- {%- endblock %}
- {%- for parent in parents %}
- <li><a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a>{{ reldelim1 }}</li>
- {%- endfor %}
- {%- block relbaritems %} {% endblock %}
- </ul>
-</div>
-{%- endmacro %}
-
-{%- block sidebarlogo %}{%- endblock %}
-{%- block sidebarsourcelink %}{%- endblock %}
--- a/doc/book/en/_themes/cubicweb/static/cubicweb.css_t Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- * cubicweb.css_t
- * ~~~~~~~~~~~~~~
- *
- * Sphinx stylesheet -- cubicweb theme.
- *
- * :copyright: Copyright 2014 by the Cubicweb team, see AUTHORS.
- * :license: LGPL, see LICENSE for details.
- *
- */
-
-@import url("pyramid.css");
-
-div.header-small {
- background-image: linear-gradient(white, #e2e2e2);
- border-bottom: 1px solid #bbb;
-}
-
-div.logo-small {
- padding: 10px;
-}
-
-img.logo {
- width: 150px;
-}
-
-div.related a {
- color: #e6820e;
-}
-
-a, a .pre {
- color: #e6820e;
-}
--- a/doc/book/en/_themes/cubicweb/static/cubicweb.ico Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-../../../../../../web/data/favicon.ico
\ No newline at end of file
--- a/doc/book/en/_themes/cubicweb/static/logo-cubicweb-small.svg Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-logo-cubicweb.svg
\ No newline at end of file
--- a/doc/book/en/_themes/cubicweb/static/logo-cubicweb.svg Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-../../../../../../web/data/logo-cubicweb.svg
\ No newline at end of file
--- a/doc/book/en/_themes/cubicweb/theme.conf Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-[theme]
-inherit = pyramid
-pygments_style = sphinx.pygments_styles.PyramidStyle
-stylesheet = cubicweb.css
-
-
-[options]
-logo = logo-cubicweb.svg
-favicon = cubicweb.ico
-in_progress = false
-outdated = false
-canonical_url =
--- a/doc/book/en/additionnal_services/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-Additional services
-===================
-
-In this chapter, we introduce services crossing the *web -
-repository - administration* organisation of the first parts of the
-CubicWeb book. Those services can be either proper services (like the
-undo functionality) or mere *topical cross-sections* across CubicWeb.
-
-.. toctree::
- :maxdepth: 2
-
- undo
-
-
--- a/doc/book/en/additionnal_services/undo.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,337 +0,0 @@
-Undoing changes in CubicWeb
----------------------------
-
-Many desktop applications offer the possibility for the user to
-undo its last changes : this *undo feature* has now been
-integrated into the CubicWeb framework. This document will
-introduce you to the *undo feature* both from the end-user and the
-application developer point of view.
-
-But because a semantic web application and a common desktop
-application are not the same thing at all, especially as far as
-undoing is concerned, we will first introduce *what* is the *undo
-feature* for now.
-
-What's *undoing* in a CubicWeb application
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-What is an *undo feature* is quite intuitive in the context of a
-desktop application. But it is a bit subtler in the context of a
-Semantic Web application. This section introduces some of the main
-differences between a classical desktop and a Semantic Web
-applications to keep in mind in order to state precisely *what we
-want*.
-
-The notion transactions
-```````````````````````
-
-A CubicWeb application acts upon an *Entity-Relationship* model,
-described by a schema. This allows to ensure some data integrity
-properties. It also implies that changes are made by all-or-none
-groups called *transactions*, such that the data integrity is
-preserved whether the transaction is completely applied *or* none
-of it is applied.
-
-A transaction can thus include more actions than just those
-directly required by the main purpose of the user. For example,
-when a user *just* writes a new blog entry, the underlying
-*transaction* holds several *actions* as illustrated below :
-
-* By admin on 2012/02/17 15:18 - Created Blog entry : Torototo
-
- #. Created Blog entry : Torototo
- #. Added relation : Torototo owned by admin
- #. Added relation : Torototo blog entry of Undo Blog
- #. Added relation : Torototo in state draft (draft)
- #. Added relation : Torototo created by admin
-
-Because of the very nature (all-or-none) of the transactions, the
-"undoable stuff" are the transactions and not the actions !
-
-Public and private actions within a transaction
-```````````````````````````````````````````````
-
-Actually, within the *transaction* "Created Blog entry :
-Torototo", two of those *actions* are said to be *public* and
-the others are said to be *private*. *Public* here means that the
-public actions (1 and 3) were directly requested by the end user ;
-whereas *private* means that the other actions (2, 4, 5) were
-triggered "under the hood" to fulfill various requirements for the
-user operation (ensuring integrity, security, ... ).
-
-And because quite a lot of actions can be triggered by a "simple"
-end-user request, most of which the end-user is not (and does not
-need or wish to be) aware, only the so-called public actions will
-appear [1]_ in the description of the an undoable transaction.
-
-* By admin on 2012/02/17 15:18 - Created Blog entry : Torototo
-
- #. Created Blog entry : Torototo
- #. Added relation : Torototo blog entry of Undo Blog
-
-But note that both public and private actions will be undone
-together when the transaction is undone.
-
-(In)dependent transactions : the simple case
-````````````````````````````````````````````
-
-A CubicWeb application can be used *simultaneously* by different users
-(whereas a single user works on an given office document at a
-given time), so that there is not always a single history
-time-line in the CubicWeb case. Moreover CubicWeb provides
-security through the mechanism of *permissions* granted to each
-user. This can lead to some transactions *not* being undoable in
-some contexts.
-
-In the simple case two (unprivileged) users Alice and Bob make
-relatively independent changes : then both Alice and Bob can undo
-their changes. But in some case there is a clean dependency
-between Alice's and Bob's actions or between actions of one of
-them. For example let's suppose that :
-
-- Alice has created a blog,
-- then has published a first post inside,
-- then Bob has published a second post in the same blog,
-- and finally Alice has updated its post contents.
-
-Then it is clear that Alice can undo her contents changes and Bob
-can undo his post creation independently. But Alice can not undo
-her post creation while she has not first undone her changes.
-It is also clear that Bob should *not* have the
-permissions to undo any of Alice's transactions.
-
-
-More complex dependencies between transactions
-``````````````````````````````````````````````
-
-But more surprising things can quickly happen. Going back to the
-previous example, Alice *can* undo the creation of the blog after
-Bob has published its post in it ! But this is possible only
-because the schema does not *require* for a post to be in a
-blog. Would the *blog entry of* relation have been mandatory, then
-Alice could not have undone the blog creation because it would
-have broken integrity constraint for Bob's post.
-
-When a user attempts to undo a transaction the system will check
-whether a later transaction has explicit dependency on the
-would-be-undone transaction. In this case the system will not even
-attempt the undo operation and inform the user.
-
-If no such dependency is detected the system will attempt the undo
-operation but it can fail, typically because of integrity
-constraint violations. In such a case the undo operation is
-completely [3]_ rollbacked.
-
-
-The *undo feature* for CubicWeb end-users
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The exposition of the undo feature to the end-user through a Web
-interface is still quite basic and will be improved toward a
-greater usability. But it is already fully functional. For now
-there are two ways to access the *undo feature* as long as the it
-has been activated in the instance configuration file with the
-option *undo-support=yes*.
-
-Immediately after having done the change to be canceled through
-the **undo** link in the message. This allows to undo an
-hastily action immediately. For example, just after having
-validated the creation of the blog entry *A second blog entry* we
-get the following message, allowing to undo the creation.
-
-.. image:: /images/undo_mesage_w600.png
- :width: 600px
- :alt: Screenshot of the undo link in the message
- :align: center
-
-At any time we can access the **undo-history view** accessible from the
-start-up page.
-
-.. image:: /images/undo_startup-link_w600.png
- :width: 600px
- :alt: Screenshot of the startup menu with access to the history view
- :align: center
-
-This view will provide inspection of the transaction and their (public)
-actions. Each transaction provides its own **undo** link. Only the
-transactions the user has permissions to see and undo will be shown.
-
-.. image:: /images/undo_history-view_w600.png
- :width: 600px
- :alt: Screenshot of the undo history main view
- :align: center
-
-If the user attempts to undo a transaction which can't be undone or
-whose undoing fails, then a message will explain the situation and
-no partial undoing will be left behind.
-
-This is all for the end-user side of the undo mechanism : this is
-quite simple indeed ! Now, in the following section, we are going
-to introduce the developer side of the undo mechanism.
-
-The *undo feature* for CubicWeb application developers
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A word of warning : this section is intended for developers,
-already having some knowledge of what's under CubicWeb's hood. If
-it is not *yet* the case, please refer to CubicWeb documentation
-http://docs.cubicweb.org/ .
-
-Overview
-````````
-
-The core of the undo mechanisms is at work in the *native source*,
-beyond the RQL. This does mean that *transactions* and *actions*
-are *no entities*. Instead they are represented at the SQL level
-and exposed through the *DB-API* supported by the repository
-*Connection* objects.
-
-Once the *undo feature* has been activated in the instance
-configuration file with the option *undo-support=yes*, each
-mutating operation (cf. [2]_) will be recorded in some special SQL
-table along with its associated transaction. Transaction are
-identified by a *txuuid* through which the functions of the
-*DB-API* handle them.
-
-On the web side the last commited transaction *txuuid* is
-remembered in the request's data to allow for imediate undoing
-whereas the *undo-history view* relies upon the *DB-API* to list
-the accessible transactions. The actual undoing is performed by
-the *UndoController* accessible at URL of the form
-`www.my.host/my/instance/undo?txuuid=...`
-
-The repository side
-```````````````````
-
-Please refer to the file `cubicweb/server/sources/native.py` and
-`cubicweb/transaction.py` for the details.
-
-The undoing information is mainly stored in three SQL tables:
-
-`transactions`
- Stores the txuuid, the user eid and the date-and-time of
- the transaction. This table is referenced by the two others.
-
-`tx_entity_actions`
- Stores the undo information for actions on entities.
-
-`tx_relation_actions`
- Stores the undo information for the actions on relations.
-
-When the undo support is activated, entries are added to those
-tables for each mutating operation on the data repository, and are
-deleted on each transaction undoing.
-
-Those table are accessible through the following methods of the
-repository `Connection` object :
-
-`undoable_transactions`
- Returns a list of `Transaction` objects accessible to the user
- and according to the specified filter(s) if any.
-
-`tx_info`
- Returns a `Transaction` object from a `txuuid`
-
-`undo_transaction`
- Returns the list of `Action` object for the given `txuuid`.
-
- NB: By default it only return *public* actions.
-
-The web side
-````````````
-
-The exposure of the *undo feature* to the end-user through the Web
-interface relies on the *DB-API* introduced above. This implies
-that the *transactions* and *actions* are not *entities* linked by
-*relations* on which the usual views can be applied directly.
-
-That's why the file `cubicweb/web/views/undohistory.py` defines
-some dedicated views to access the undo information :
-
-`UndoHistoryView`
- This is a *StartupView*, the one accessible from the home
- page of the instance which list all transactions.
-
-`UndoableTransactionView`
- This view handles the display of a single `Transaction` object.
-
-`UndoableActionBaseView`
- This (abstract) base class provides private methods to build
- the display of actions whatever their nature.
-
-`Undoable[Add|Remove|Create|Delete|Update]ActionView`
- Those views all inherit from `UndoableActionBaseView` and
- each handles a specific kind of action.
-
-`UndoableActionPredicate`
- This predicate is used as a *selector* to pick the appropriate
- view for actions.
-
-Apart from this main *undo-history view* a `txuuid` is stored in
-the request's data `last_undoable_transaction` in order to allow
-immediate undoing of a hastily validated operation. This is
-handled in `cubicweb/web/application.py` in the `main_publish` and
-`add_undo_link_to_msg` methods for the storing and displaying
-respectively.
-
-Once the undo information is accessible, typically through a
-`txuuid` in an *undo* URL, the actual undo operation can be
-performed by the `UndoController` defined in
-`cubicweb/web/views/basecontrollers.py`. This controller basically
-extracts the `txuuid` and performs a call to `undo_transaction` and
-in case of an undo-specific error, lets the top level publisher
-handle it as a validation error.
-
-
-Conclusion
-~~~~~~~~~~
-
-The undo mechanism relies upon a low level recording of the
-mutating operation on the repository. Those records are accessible
-through some method added to the *DB-API* and exposed to the
-end-user either through a whole history view of through an
-immediate undoing link in the message box.
-
-The undo feature is functional but the interface and configuration
-options are still quite reduced. One major improvement would be to
-be able to filter with a finer grain which transactions or actions
-one wants to see in the *undo-history view*. Another critical
-improvement would be to enable the undo feature on a part only of
-the entity-relationship schema to avoid storing too much useless
-data and reduce the underlying overhead.
-
-But both functionality are related to the strong design choice not
-to represent transactions and actions as entities and
-relations. This has huge benefits in terms of safety and conceptual
-simplicity but prevents from using lots of convenient CubicWeb
-features such as *facets* to access undo information.
-
-Before developing further the undo feature or eventually revising
-this design choice, it appears that some return of experience is
-strongly needed. So don't hesitate to try the undo feature in your
-application and send us some feedback.
-
-
-Notes
-~~~~~
-
-.. [1] The end-user Web interface could be improved to enable
- user to choose whether he wishes to see private actions.
-
-.. [2] There is only five kind of elementary actions (beyond
- merely accessing data for reading):
-
- * **C** : creating an entity
- * **D** : deleting an entity
- * **U** : updating an entity attributes
- * **A** : adding a relation
- * **R** : removing a relation
-
-.. [3] Meaning none of the actions in the transaction is
- undone. Depending upon the application, it might make sense
- to enable *partial* undo. That is to say undo in which some
- actions could not be undo without preventing to undo the
- others actions in the transaction (as long as it does not
- break schema integrity). This is not forbidden by the
- back-end but is deliberately not supported by the front-end
- (for now at least).
--- a/doc/book/en/admin/additional-tips.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-
-.. _Additional Tips:
-
-Backups (mostly with postgresql)
---------------------------------
-
-It is always a good idea to backup. If your system does not do that,
-you should set it up. Note that whenever you do an upgrade,
-`cubicweb-ctl` offers you to backup your database. There are a number
-of ways for doing backups.
-
-Using postgresql (and only that)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Before you
-go ahead, make sure the following permissions are correct ::
-
- # chgrp postgres /var/lib/cubicweb/backup
- # chmod g+ws /var/lib/cubicweb/backup
- # chgrp postgres /etc/cubicweb.d/*<instance>*/sources
- # chmod g+r /etc/cubicweb.d/*<instance>*/sources
-
-Simply use the pg_dump in a cron installed for `postgres` user on the database server::
-
- # m h dom mon dow command
- 0 2 * * * pg_dump -Fc --username=cubicweb --no-owner <instance> > /var/backups/<instance>-$(date '+%Y-%m-%d_%H:%M:%S').dump
-
-Using :command:`cubicweb-ctl db-dump`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The CubicWeb way is to use the :command:`db-dump` command. For that,
-you have to put your passwords in a user-only-readable file at the
-home directory of root user. The file is `.pgpass` (`chmod 0600`), in
-this case for a socket run connection to PostgreSQL ::
-
- /var/run/postgresql:5432:<instance>:<database user>:<database password>
-
-The postgres documentation for the `.pgpass` format can be found `here`_
-
-Then add the following command to the crontab of the user (`crontab -e`)::
-
- # m h dom mon dow command
- 0 2 * * * cubicweb-ctl db-dump <instance>
-
-
-Backup ninja
-~~~~~~~~~~~~
-
-You can use a combination `backup-ninja`_ (which has a postgres script in the
-example directory), `backuppc`)_ (for versionning).
-
-Please note that in the *CubicWeb way* it adds a second location for your
-password which is error-prone.
-
-.. _`here` : http://www.postgresql.org/docs/current/static/libpq-pgpass.html
-.. _`backup-ninja` : https://labs.riseup.net/code/projects/show/backupninja/
-.. _`backuppc` : http://backuppc.sourceforge.net/
-
-.. warning::
-
- Remember that these indications will fail you whenever you use
- another database backend than postgres. Also it does properly handle
- externally managed data such as files (using the Bytes File System
- Storage).
--- a/doc/book/en/admin/config.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _ConfigEnv:
-
-Set-up of a *CubicWeb* environment
-==================================
-
-You can `configure the database`_ system of your choice:
-
- - `PostgreSQL configuration`_
- - `MySql configuration`_
- - `SQLServer configuration`_
- - `SQLite configuration`_
-
-For advanced features, have a look to:
-
- - `Cubicweb resources configuration`_
-
-.. _`configure the database`: DatabaseInstallation_
-.. _`PostgreSQL configuration`: PostgresqlConfiguration_
-.. _`MySql configuration`: MySqlConfiguration_
-.. _`SQLServer configuration`: SQLServerConfiguration_
-.. _`SQLite configuration`: SQLiteConfiguration_
-.. _`Cubicweb resources configuration`: RessourcesConfiguration_
-
-
-
-.. _RessourcesConfiguration:
-
-Cubicweb resources configuration
---------------------------------
-
-.. autodocstring:: cubicweb.cwconfig
-
-
-.. _DatabaseInstallation:
-
-Databases configuration
------------------------
-
-Each instance can be configured with its own database connection information,
-that will be stored in the instance's :file:`sources` file. The database to use
-will be chosen when creating the instance. CubicWeb is known to run with
-Postgresql (recommended), SQLServer and SQLite, and may run with MySQL.
-
-Other possible sources of data include CubicWeb, Subversion, LDAP and Mercurial,
-but at least one relational database is required for CubicWeb to work. You do
-not need to install a backend that you do not intend to use for one of your
-instances. SQLite is not fit for production use, but it works well for testing
-and ships with Python, which saves installation time when you want to get
-started quickly.
-
-.. _PostgresqlConfiguration:
-
-PostgreSQL
-~~~~~~~~~~
-
-Many Linux distributions ship with the appropriate PostgreSQL packages.
-Basically, you need to install the following packages:
-
-* `postgresql` and `postgresql-client`, which will pull the respective
- versioned packages (e.g. `postgresql-9.1` and `postgresql-client-9.1`) and,
- optionally,
-* a `postgresql-plpython-X.Y` package with a version corresponding to that of
- the aforementioned packages (e.g. `postgresql-plpython-9.1`).
-
-If you run postgres version prior to 8.3, you'll also need the
-`postgresql-contrib-8.X` package for full-text search extension.
-
-If you run postgres on another host than the |cubicweb| repository, you should
-install the `postgresql-client` package on the |cubicweb| host, and others on the
-database host.
-
-For extra details concerning installation, please refer to the `PostgreSQL
-project online documentation`_.
-
-.. _`PostgreSQL project online documentation`: http://www.postgresql.org/docs
-
-
-Database cluster
-++++++++++++++++
-
-If you already have an existing cluster and PostgreSQL server running, you do
-not need to execute the initilization step of your PostgreSQL database unless
-you want a specific cluster for |cubicweb| databases or if your existing
-cluster doesn't use the UTF8 encoding (see note below).
-
-To initialize a PostgreSQL cluster, use the command ``initdb``::
-
- $ initdb -E UTF8 -D /path/to/pgsql
-
-Notice the encoding specification. This is necessary since |cubicweb| usually
-want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll
-get error like::
-
- new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII)
- HINT: Use the same encoding as in the template database, or use template0 as template.
-
-Once initialized, start the database server PostgreSQL with the command::
-
- $ postgres -D /path/to/psql
-
-If you cannot execute this command due to permission issues, please make sure
-that your username has write access on the database. ::
-
- $ chown username /path/to/pgsql
-
-Database authentication
-+++++++++++++++++++++++
-
-The database authentication is configured in `pg_hba.conf`. It can be either set
-to `ident sameuser` or `md5`. If set to `md5`, make sure to use an existing
-user of your database. If set to `ident sameuser`, make sure that your client's
-operating system user name has a matching user in the database. If not, please
-do as follow to create a user::
-
- $ su
- $ su - postgres
- $ createuser -s -P username
-
-The option `-P` (for password prompt), will encrypt the password with the
-method set in the configuration file :file:`pg_hba.conf`. If you do not use this
-option `-P`, then the default value will be null and you will need to set it
-with::
-
- $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql"
-
-The above login/password will be requested when you will create an instance with
-`cubicweb-ctl create` to initialize the database of your instance.
-
-Notice that the `cubicweb-ctl db-create` does database initialization that
-may requires a postgres superuser. That's why a login/password is explicitly asked
-at this step, so you can use there a superuser without using this user when running
-the instance. Things that require special privileges at this step:
-
-* database creation, require the 'create database' permission
-* install the plpython extension language (require superuser)
-* install the tsearch extension for postgres version prior to 8.3 (require superuser)
-
-To avoid using a super user each time you create an install, a nice trick is to
-install plpython (and tsearch when needed) on the special `template1` database,
-so they will be installed automatically when cubicweb databases are created
-without even with needs for special access rights. To do so, run ::
-
- # Installation of plpythonu language by default ::
- $ createlang -U pgadmin plpythonu template1
- $ psql -U pgadmin template1
- template1=# update pg_language set lanpltrusted=TRUE where lanname='plpythonu';
-
-Where `pgadmin` is a postgres superuser. The last command is necessary since by
-default plpython is an 'untrusted' language and as such can't be used by non
-superuser. This update fix that problem by making it trusted.
-
-To install the tsearch plain-text index extension on postgres prior to 8.3, run::
-
- cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1
-
-
-.. _MySqlConfiguration:
-
-MySql
-~~~~~
-.. warning::
- CubicWeb's MySQL support is not commonly used, so things may or may not work properly.
-
-You must add the following lines in ``/etc/mysql/my.cnf`` file::
-
- transaction-isolation=READ-COMMITTED
- default-storage-engine=INNODB
- default-character-set=utf8
- max_allowed_packet = 128M
-
-.. Note::
- It is unclear whether mysql supports indexed string of arbitrary length or
- not.
-
-
-.. _SQLServerConfiguration:
-
-SQLServer
-~~~~~~~~~
-
-As of this writing, support for SQLServer 2005 is functional but incomplete. You
-should be able to connect, create a database and go quite far, but some of the
-SQL generated from RQL queries is still currently not accepted by the
-backend. Porting to SQLServer 2008 is also an item on the backlog.
-
-The `source` configuration file may look like this (specific parts only are
-shown)::
-
- [system]
- db-driver=sqlserver2005
- db-user=someuser
- # database password not needed
- #db-password=toto123
- #db-create/init may ask for a pwd: just say anything
- db-extra-arguments=Trusted_Connection
- db-encoding=utf8
-
-
-You need to change the default settings on the database by running::
-
- ALTER DATABASE <databasename> SET READ_COMMITTED_SNAPSHOT ON;
-
-The ALTER DATABASE command above requires some permissions that your
-user may not have. In that case you will have to ask your local DBA to
-run the query for you.
-
-You can check that the setting is correct by running the following
-query which must return '1'::
-
- SELECT is_read_committed_snapshot_on
- FROM sys.databases WHERE name='<databasename>';
-
-
-
-.. _SQLiteConfiguration:
-
-SQLite
-~~~~~~
-
-SQLite has the great advantage of requiring almost no configuration. Simply
-use 'sqlite' as db-driver, and set path to the dabase as db-name. Don't specify
-anything for db-user and db-password, they will be ignore anyway.
-
-.. Note::
- SQLite is great for testing and to play with cubicweb but is not suited for
- production environments.
-
--- a/doc/book/en/admin/create-instance.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Creation of your first instance
-===============================
-
-Instance creation
------------------
-
-Now that we created a cube, we can create an instance and access it via a web
-browser. We will use a `all-in-one` configuration to simplify things ::
-
- cubicweb-ctl create -c all-in-one mycube myinstance
-
-.. note::
- Please note that we created a new cube for a demo purposes but
- you could have used an existing cube available in our standard library
- such as blog or person for example.
-
-A series of questions will be prompted to you, the default answer is usually
-sufficient. You can anyway modify the configuration later on by editing
-configuration files. When a login/password are requested to access the database
-please use the credentials you created at the time you configured the database
-(:ref:`PostgresqlConfiguration`).
-
-It is important to distinguish here the user used to access the database and the
-user used to login to the cubicweb instance. When an instance starts, it uses
-the login/password for the database to get the schema and handle low level
-transaction. But, when :command:`cubicweb-ctl create` asks for a manager
-login/psswd of *CubicWeb*, it refers to the user you will use during the
-development to administrate your web instance. It will be possible, later on,
-to use this user to create other users for your final web instance.
-
-
-Instance administration
------------------------
-
-start / stop
-~~~~~~~~~~~~
-
-When this command is completed, the definition of your instance is
-located in :file:`~/etc/cubicweb.d/myinstance/*`. To launch it, you
-just type ::
-
- cubicweb-ctl start -D myinstance
-
-The option `-D` specifies the *debug mode* : the instance is not
-running in server mode and does not disconnect from the terminal,
-which simplifies debugging in case the instance is not properly
-launched. You can see how it looks by visiting the URL
-`http://localhost:8080` (the port number depends of your
-configuration). To login, please use the cubicweb administrator
-login/password you defined when you created the instance.
-
-To shutdown the instance, Crtl-C in the terminal window is enough.
-If you did not use the option `-D`, then type ::
-
- cubicweb-ctl stop myinstance
-
-This is it! All is settled down to start developping your data model...
-
-.. note::
-
- The output of `cubicweb-ctl start -D myinstance` can be
- overwhelming. It is possible to reduce the log level with the
- `--loglevel` parameter as in `cubicweb-ctl start -D myinstance -l
- info` to filter out all logs under `info` gravity.
-
-upgrade
-~~~~~~~
-
-A manual upgrade step is necessary whenever a new version of CubicWeb or
-a cube is installed, in order to synchronise the instance's
-configuration and schema with the new code. The command is::
-
- cubicweb-ctl upgrade myinstance
-
-A series of questions will be asked. It always starts with a proposal
-to make a backup of your sources (where it applies). Unless you know
-exactly what you are doing (i.e. typically fiddling in debug mode, but
-definitely NOT migrating a production instance), you should answer YES
-to that.
-
-The remaining questions concern the migration steps of |cubicweb|,
-then of the cubes that form the whole application, in reverse
-dependency order.
-
-In principle, if the migration scripts have been properly written and
-tested, you should answer YES to all questions.
-
-Somtimes, typically while debugging a migration script, something goes
-wrong and the migration fails. Unfortunately the databse may be in an
-incoherent state. You have two options here:
-
-* fix the bug, restore the database and restart the migration process
- from scratch (quite recommended in a production environement)
-
-* try to replay the migration up to the last successful commit, that
- is answering NO to all questions up to the step that failed, and
- finish by answering YES to the remaining questions.
-
--- a/doc/book/en/admin/cubicweb-ctl.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _cubicweb-ctl:
-
-``cubicweb-ctl`` tool
-=====================
-
-`cubicweb-ctl` is the swiss knife to manage *CubicWeb* instances.
-The general syntax is ::
-
- cubicweb-ctl <command> [options command] <arguments commands>
-
-To view available commands ::
-
- cubicweb-ctl
- cubicweb-ctl --help
-
-Please note that the commands available depends on the *CubicWeb* packages
-and cubes that have been installed.
-
-To view the help menu on specific command ::
-
- cubicweb-ctl <command> --help
-
-Listing available cubes and instance
--------------------------------------
-
-* ``list``, provides a list of the available configuration, cubes
- and instances.
-
-
-Creation of a new cube
------------------------
-
-Create your new cube cube ::
-
- cubicweb-ctl newcube
-
-This will create a new cube in
-``/path/to/grshell-cubicweb/cubes/<mycube>`` for a Mercurial
-installation, or in ``/usr/share/cubicweb/cubes`` for a debian
-packages installation.
-
-Create an instance
--------------------
-
-You must ensure `~/etc/cubicweb.d/` exists prior to this. On windows, the
-'~' part will probably expand to 'Documents and Settings/user'.
-
-To create an instance from an existing cube, execute the following
-command ::
-
- cubicweb-ctl create <cube_name> <instance_name>
-
-This command will create the configuration files of an instance in
-``~/etc/cubicweb.d/<instance_name>``.
-
-The tool ``cubicweb-ctl`` executes the command ``db-create`` and
-``db-init`` when you run ``create`` so that you can complete an
-instance creation in a single command. But of course it is possible
-to issue these separate commands separately, at a later stage.
-
-Command to create/initialize an instance database
--------------------------------------------------
-
-* ``db-create``, creates the system database of an instance (tables and
- extensions only)
-* ``db-init``, initializes the system database of an instance
- (schema, groups, users, workflows...)
-
-Commands to control instances
------------------------------
-
-* ``start``, starts one or more or all instances
-
-of special interest::
-
- start -D
-
-will start in debug mode (under windows, starting without -D will not
-work; you need instead to setup your instance as a service).
-
-* ``stop``, stops one or more or all instances
-* ``restart``, restarts one or more or all instances
-* ``status``, returns the status of the instance(s)
-
-Commands to maintain instances
-------------------------------
-
-* ``upgrade``, launches the existing instances migration when a new version
- of *CubicWeb* or the cubes installed is available
-* ``shell``, opens a (Python based) migration shell for manual maintenance of the instance
-* ``db-dump``, creates a dump of the system database
-* ``db-restore``, restores a dump of the system database
-* ``db-check``, checks data integrity of an instance. If the automatic correction
- is activated, it is recommanded to create a dump before this operation.
-* ``schema-sync``, synchronizes the persistent schema of an instance with
- the instance schema. It is recommanded to create a dump before this operation.
-
-Commands to maintain i18n catalogs
-----------------------------------
-* ``i18ncubicweb``, regenerates messages catalogs of the *CubicWeb* library
-* ``i18ncube``, regenerates the messages catalogs of a cube
-* ``i18ninstance``, recompiles the messages catalogs of an instance.
- This is automatically done while upgrading.
-
-See also chapter :ref:`internationalization`.
-
-Other commands
---------------
-* ``delete``, deletes an instance (configuration files and database)
--- a/doc/book/en/admin/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Part3:
-
---------------
-Administration
---------------
-
-This part is for installation and administration of the *CubicWeb* framework and
-instances based on that framework.
-
-.. toctree::
- :maxdepth: 1
- :numbered:
-
- setup
- setup-windows
- config
- cubicweb-ctl
- create-instance
- instance-config
- site-config
- multisources
- ldap
- migration
- additional-tips
- rql-logs
-
--- a/doc/book/en/admin/instance-config.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,200 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-
-Configure an instance
-=====================
-
-While creating an instance, a configuration file is generated in::
-
- $ (CW_INSTANCES_DIR) / <instance> / <configuration name>.conf
-
-For example::
-
- /etc/cubicweb.d/myblog/all-in-one.conf
-
-It is a simple text file in the INI format
-(http://en.wikipedia.org/wiki/INI_file). In the following description,
-each option name is prefixed with its own section and followed by its
-default value if necessary, e.g. "`<section>.<option>` [value]."
-
-.. _`WebServerConfig`:
-
-Configuring the Web server
---------------------------
-:`web.auth-model` [cookie]:
- authentication mode, cookie or http
-:`web.realm`:
- realm of the instance in http authentication mode
-:`web.http-session-time` [0]:
- period of inactivity of an HTTP session before it closes automatically.
- Duration in seconds, 0 meaning no expiration (or more exactly at the
- closing of the browser client)
-
-:`main.anonymous-user`, `main.anonymous-password`:
- login and password to use to connect to the RQL server with
- HTTP anonymous connection. CWUser account should exist.
-
-:`main.base-url`:
- url base site to be used to generate the urls of web pages
-
-Https configuration
-```````````````````
-It is possible to make a site accessible for anonymous http connections
-and https for authenticated users. This requires to
-use apache (for example) for redirection and the variable `main.https-url`
-of configuration file.
-
-For this to work you have to activate the following apache modules :
-
-* rewrite
-* proxy
-* http_proxy
-
-The command on Debian based systems for that is ::
-
- a2enmod rewrite http_proxy proxy
- /etc/init.d/apache2 restart
-
-:Example:
-
- For an apache redirection of a site accessible via `http://localhost/demo`
- and `https://localhost/demo` and actually running on port 8080, it
- takes to the http:::
-
- ProxyPreserveHost On
- RewriteEngine On
- RewriteCond %{REQUEST_URI} ^/demo
- RewriteRule ^/demo$ /demo/
- RewriteRule ^/demo/(.*) http://127.0.0.1:8080/$1 [L,P]
-
- and for the https:::
-
- ProxyPreserveHost On
- RewriteEngine On
- RewriteCond %{REQUEST_URI} ^/ demo
- RewriteRule ^/demo$/demo/
- RewriteRule ^/demo/(.*) http://127.0.0.1:8080/https/$1 [L,P]
-
-
- and we will file in the all-in-one.conf of the instance:::
-
- base-url = http://localhost/demo
- https-url = https://localhost/demo
-
-Notice that if you simply want a site accessible through https, not *both* http
-and https, simply set `base-url` to the https url and the first section into your
-apache configuration (as you would have to do for an http configuration with an
-apache front-end).
-
-Setting up the web client
--------------------------
-:`web.embed-allowed`:
- regular expression matching sites which could be "embedded" in
- the site (controllers 'embed')
-:`web.submit-url`:
- url where the bugs encountered in the instance can be mailed to
-
-
-RQL server configuration
-------------------------
-:`main.host`:
- host name if it can not be detected correctly
-:`main.pid-file`:
- file where will be written the server pid
-:`main.uid`:
- user account to use for launching the server when it is
- root launched by init
-:`main.session-time [30*60]`:
- timeout of a RQL session
-:`main.query-log-file`:
- file where all requests RQL executed by the server are written
-
-
-Configuring e-mail
-------------------
-RQL and web server side:
-
-:`email.mangle-mails [no]`:
- indicates whether the email addresses must be displayed as is or
- transformed
-
-RQL server side:
-
-:`email.smtp-host [mail]`:
- hostname hosting the SMTP server to use for outgoing mail
-:`email.smtp-port [25]`:
- SMTP server port to use for outgoing mail
-:`email.sender-name`:
- name to use for outgoing mail of the instance
-:`email.sender-addr`:
- address for outgoing mail of the instance
-:`email.default dest-addrs`:
- destination addresses by default, if used by the configuration of the
- dissemination of the model (separated by commas)
-:`email.supervising-addrs`:
- destination addresses of e-mails of supervision (separated by
- commas)
-
-
-Configuring logging
--------------------
-:`main.log-threshold`:
- level of filtering messages (DEBUG, INFO, WARNING, ERROR)
-:`main.log-file`:
- file to write messages
-
-
-.. _PersistentProperties:
-
-Configuring persistent properties
----------------------------------
-Other configuration settings are in the form of entities `CWProperty`
-in the database. It must be edited via the web interface or by
-RQL queries.
-
-:`ui.encoding`:
- Character encoding to use for the web
-:`navigation.short-line-size`:
- number of characters for "short" display
-:`navigation.page-size`:
- maximum number of entities to show per results page
-:`navigation.related-limit`:
- number of related entities to show up on primary entity view
-:`navigation.combobox-limit`:
- number of entities unrelated to show up on the drop-down lists of
- the sight on an editing entity view
-
-Cross-Origin Resource Sharing
------------------------------
-
-CubicWeb provides some support for the CORS_ protocol. For now, the
-provided implementation only deals with access to a CubicWeb instance
-as a whole. Support for a finer granularity may be considered in the
-future.
-
-Specificities of the provided implementation:
-
-- ``Access-Control-Allow-Credentials`` is always true
-- ``Access-Control-Allow-Origin`` header in response will never be
- ``*``
-- ``Access-Control-Expose-Headers`` can be configured globally (see below)
-- ``Access-Control-Max-Age`` can be configured globally (see below)
-- ``Access-Control-Allow-Methods`` can be configured globally (see below)
-- ``Access-Control-Allow-Headers`` can be configured globally (see below)
-
-
-A few parameters can be set to configure the CORS_ capabilities of CubicWeb.
-
-.. _CORS: http://www.w3.org/TR/cors/
-
-:`access-control-allow-origin`:
- comma-separated list of allowed origin domains or "*" for any domain
-:`access-control-allow-methods`:
- comma-separated list of allowed HTTP methods
-:`access-control-max-age`:
- maximum age of cross-origin resource sharing (in seconds)
-:`access-control-allow-headers`:
- comma-separated list of allowed HTTP custom headers (used in simple requests)
-:`access-control-expose-headers`:
- comma-separated list of allowed HTTP custom headers (used in preflight requests)
-
--- a/doc/book/en/admin/ldap.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-.. _LDAP:
-
-LDAP integration
-================
-
-Overview
---------
-
-Using LDAP as a source for user credentials and information is quite
-easy. The most difficult part lies in building an LDAP schema or
-using an existing one.
-
-At cube creation time, one is asked if more sources are wanted. LDAP
-is one possible option at this time. Of course, it is always possible
-to set it up later using the `CWSource` entity type, which we discuss
-there.
-
-It is possible to add as many LDAP sources as wanted, which translates
-in as many `CWSource` entities as needed.
-
-The general principle of the LDAP source is, given a proper
-configuration, to create local users matching the users available in
-the directory and deriving local user attributes from directory users
-attributes. Then a periodic task ensures local user information
-synchronization with the directory.
-
-Users handled by such a source should not be edited directly from
-within the application instance itself. Rather, updates should happen
-at the LDAP server level.
-
-Credential checks are _always_ done against the LDAP server.
-
-.. Note::
-
- There are currently two ldap source types: the older `ldapuser` and
- the newer `ldapfeed`. The older will be deprecated anytime soon, as
- the newer has now gained all the features of the old and does not
- suffer from some of its illnesses.
-
- The ldapfeed creates real `CWUser` entities, and then
- activate/deactivate them depending on their presence/absence in the
- corresponding LDAP source. Their attribute and state
- (activated/deactivated) are hence managed by the source mechanism;
- they should not be altered by other means (as such alterations may
- be overridden in some subsequent source synchronisation).
-
-
-Configuration of an LDAPfeed source
------------------------------------
-
-Additional sources are created at cube creation time or later through the
-user interface.
-
-Configure an `ldapfeed` source from the user interface under `Manage` then
-`data sources`:
-
-* At this point `type` has been set to `ldapfeed`.
-
-* The `parser` attribute shall be set to `ldapfeed`.
-
-* The `url` attribute shall be set to an URL such as ldap://ldapserver.domain/.
-
-* The `configuration` attribute contains many options. They are described in
- detail in the next paragraph.
-
-
-Options of an LDAPfeed source
------------------------------
-
-Let us enumerate the options by categories (LDAP server connection,
-LDAP schema mapping information).
-
-LDAP server connection options:
-
-* `auth-mode`, (choices are simple, cram_md5, digest_md5, gssapi, support
- for the later being partial as of now)
-
-* `auth-realm`, realm to use when using gssapi/kerberos authentication
-
-* `data-cnx-dn`, user dn to use to open data connection to the ldap (eg
- used to respond to rql queries)
-
-* `data-cnx-password`, password to use to open data connection to the
- ldap (eg used to respond to rql queries)
-
-If the LDAP server accepts anonymous binds, then it is possible to
-leave data-cnx-dn and data-cnx-password empty. This is, however, quite
-unlikely in practice. Beware that the LDAP server might hide attributes
-such as "userPassword" while the rest of the attributes remain visible
-through an anonymous binding.
-
-LDAP schema mapping options:
-
-* `user-base-dn`, base DN to lookup for users
-
-* `user-scope`, user search scope (valid values: "BASE", "ONELEVEL",
- "SUBTREE")
-
-* `user-classes`, classes of user (with Active Directory, you want to
- say "user" here)
-
-* `user-filter`, additional filters to be set in the ldap query to
- find valid users
-
-* `user-login-attr`, attribute used as login on authentication (with
- Active Directory, you want to use "sAMAccountName" here)
-
-* `user-default-group`, name of a group in which ldap users will be by
- default. You can set multiple groups by separating them by a comma
-
-* `user-attrs-map`, map from ldap user attributes to cubicweb
- attributes (with Active Directory, you want to use
- sAMAccountName:login,mail:email,givenName:firstname,sn:surname)
-
-
-Other notes
------------
-
-* Cubicweb is able to start if ldap cannot be reached, even on
- cubicweb-ctl start ... If some source ldap server cannot be used
- while an instance is running, the corresponding users won't be
- authenticated but their status will not change (e.g. they will not
- be deactivated)
-
-* The user-base-dn is a key that helps cubicweb map CWUsers to LDAP
- users: beware updating it
-
-* When a user is removed from an LDAP source, it is deactivated in the
- CubicWeb instance; when a deactivated user comes back in the LDAP
- source, it (automatically) is activated again
-
-* You can use the :class:`CWSourceHostConfig` to have variants for a source
- configuration according to the host the instance is running on. To do so
- go on the source's view from the sources management view.
--- a/doc/book/en/admin/migration.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Migrating cubicweb instances - benefits from a distributed architecture
-=======================================================================
-
-Migrate apache & cubicweb
--------------------------
-
-**Aim** : do the migration for N cubicweb instances hosted on a server to another with no downtime.
-
-**Prerequisites** : have an explicit definition of the database host (not default or localhost). In our case, the database is hosted on another host.
-
-**Steps** :
-
-1. *on new machine* : install your environment (*pseudocode*) ::
-
- apt-get install cubicweb cubicweb-applications apache2
-
-2. *on old machine* : copy your cubicweb and apache configuration to the new machine ::
-
- scp /etc/cubicweb.d/ newmachine:/etc/cubicweb.d/
- scp /etc/apache2/sites-available/ newmachine:/etc/apache2/sites-available/
-
-3. *on new machine* : start your instances ::
-
- cubicweb start
-
-4. *on new machine* : enable sites and modules for apache and start it, test it using by modifying your /etc/host file.
-
-5. change dns entry from your oldmachine to newmachine
-
-6. shutdown your *old machine* (if it doesn't host other services or your database)
-
-7. That's it.
-
-**Possible enhancements** : use right from the start a pound server behind your apache, that way you can add backends and smoothily migrate by shuting down backends that pound will take into account.
-
-
--- a/doc/book/en/admin/multisources.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-Multiple sources of data
-========================
-
-Data sources include SQL, LDAP, RQL, mercurial and subversion.
-
-.. XXX feed me
--- a/doc/book/en/admin/rql-logs.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-RQL logs
-========
-
-You can configure the *CubicWeb* instance to keep a log
-of the queries executed against your database. To do so,
-edit the configuration file of your instance
-``.../etc/cubicweb.d/myapp/all-in-one.conf`` and uncomment the
-variable ``query-log-file``::
-
- # web instance query log file
- query-log-file=/tmp/rql-myapp.log
-
--- a/doc/book/en/admin/setup-windows.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _SetUpWindowsEnv:
-
-Installing a development environement on Windows
-================================================
-
-Setting up a Windows development environment is not too complicated
-but it requires a series of small steps.
-
-We propose an example of a typical |cubicweb| installation on Windows
-from sources. We assume everything goes into ``C:\\`` and for any
-package, without version specification, "the latest is
-the greatest".
-
-Mind that adjusting the installation drive should be straightforward.
-
-
-
-Install the required elements
------------------------------
-
-|cubicweb| requires some base elements that must be installed to run
-correctly. So, first of all, you must install them :
-
-* python >= 2.6 and < 3
- (`Download Python <http://www.python.org/download/>`_).
- You can also consider the Python(x,y) distribution
- (`Download Python(x,y) <http://code.google.com/p/pythonxy/wiki/Downloads>`_)
- as it makes things easier for Windows user by wrapping in a single installer
- python 2.7 plus numerous useful third-party modules and
- applications (including Eclipse + pydev, which is an arguably good
- IDE for Python under Windows).
-
-* `Twisted <http://twistedmatrix.com/trac/>`_ is an event-driven
- networking engine
- (`Download Twisted <http://twistedmatrix.com/trac/>`_)
-
-* `lxml <http://codespeak.net/lxml/>`_ library
- (version >=2.2.1) allows working with XML and HTML
- (`Download lxml <http://pypi.python.org/pypi/lxml/2.2.1>`_)
-
-* `Postgresql <http://www.postgresql.org/>`_,
- an object-relational database system
- (`Download Postgresql <http://www.enterprisedb.com/products/pgdownload.do#windows>`_)
- and its python drivers
- (`Download psycopg <http://www.stickpeople.com/projects/python/win-psycopg/#Version2>`_)
-
-* A recent version of `gettext`
- (`Download gettext <http://download.logilab.org/pub/gettext/gettext-0.17-win32-setup.exe>`_).
-
-* `rql <http://www.logilab.org/project/rql>`_,
- the recent version of the Relationship Query Language parser.
-
-Install optional elements
--------------------------
-
-We recommend you to install the following elements. They are not
-mandatory but they activate very interesting features in |cubicweb|:
-
-* `python-ldap <http://pypi.python.org/pypi/python-ldap>`_
- provides access to LDAP/Active directory directories
- (`Download python-ldap <http://www.osuch.org/python-ldap>`_).
-
-* `graphviz <http://www.graphviz.org/>`_
- which allow schema drawings.
- (`Download graphviz <http://www.graphviz.org/Download_windows.php>`_).
- It is quite recommended (albeit not mandatory).
-
-Other elements will activate more features once installed. Take a look
-at :ref:`InstallDependencies`.
-
-Useful tools
-------------
-
-Some additional tools could be useful to develop :ref:`cubes <AvailableCubes>`
-with the framework.
-
-* `mercurial <http://mercurial.selenic.com/>`_ and its standard windows GUI
- (`TortoiseHG <http://tortoisehg.bitbucket.org/>`_) allow you to get the source
- code of |cubicweb| from control version repositories. So you will be able to
- get the latest development version and pre-release bugfixes in an easy way
- (`Download mercurial <http://bitbucket.org/tortoisehg/stable/wiki/download>`_).
-
-* You can also consider the ssh client `Putty` in order to peruse
- mercurial over ssh (`Download <http://www.putty.org/>`_).
-
-* If you are an Eclipse user, mercurial can be integrated using the
- `MercurialEclipse` plugin
- (`Home page <http://www.vectrace.com/mercurialeclipse/>`_).
-
-Getting the sources
--------------------
-
-There are two ways to get the sources of |cubicweb| and its
-:ref:`cubes <AvailableCubes>`:
-
-* download the latest release (:ref:`SourceInstallation`)
-* get the development version using Mercurial
- (:ref:`MercurialInstallation`)
-
-Environment variables
----------------------
-
-You will need some convenience environment variables once all is set up. These
-variables are settable through the GUI by getting at the `System properties`
-window (by righ-clicking on `My Computer` -> `properties`).
-
-In the `advanced` tab, there is an `Environment variables` button. Click on
-it. That opens a small window allowing edition of user-related and system-wide
-variables.
-
-We will consider only user variables. First, the ``PATH`` variable. Assuming
-you are logged as user *Jane*, add the following paths, separated by
-semi-colons::
-
- C:\Documents and Settings\Jane\My Documents\Python\cubicweb\cubicweb\bin
- C:\Program Files\Graphviz2.24\bin
-
-The ``PYTHONPATH`` variable should also contain::
-
- C:\Documents and Settings\Jane\My Documents\Python\cubicweb\
-
-From now, on a fresh `cmd` shell, you should be able to type::
-
- cubicweb-ctl list
-
-... and get a meaningful output.
-
-Running an instance as a service
---------------------------------
-
-This currently assumes that the instances configurations is located at
-``C:\\etc\\cubicweb.d``. For a cube 'my_instance', you will find
-``C:\\etc\\cubicweb.d\\my_instance\\win32svc.py``.
-
-Now, register your instance as a windows service with::
-
- win32svc install
-
-Then start the service with::
-
- net start cubicweb-my_instance
-
-In case this does not work, you should be able to see error reports in
-the application log, using the windows event log viewer.
--- a/doc/book/en/admin/setup.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _SetUpEnv:
-
-Installation of a *CubicWeb* environment
-========================================
-
-Official releases are available from the `CubicWeb.org forge`_ and from
-`PyPI`_. Since CubicWeb is developed using `Agile software development
-<http://en.wikipedia.org/wiki/Agile_software_development>`_ techniques, releases
-happen frequently. In a version numbered X.Y.Z, X changes after a few years when
-the API breaks, Y changes after a few weeks when features are added and Z
-changes after a few days when bugs are fixed.
-
-Depending on your needs, you will chose a different way to install CubicWeb on
-your system:
-
-- `Installation on Debian/Ubuntu`_
-- `Installation on Windows`_
-- `Installation in a virtualenv`_
-- `Installation with pip`_
-- `Installation with easy_install`_
-- `Installation from tarball`_
-
-If you are a power-user and need the very latest features, you will
-
-- `Install from version control`_
-
-Once the software is installed, move on to :ref:`ConfigEnv` for better control
-and advanced features of |cubicweb|.
-
-.. _`Installation on Debian/Ubuntu`: DebianInstallation_
-.. _`Installation on Windows`: WindowsInstallation_
-.. _`Installation in a virtualenv`: VirtualenvInstallation_
-.. _`Installation with pip`: PipInstallation_
-.. _`Installation with easy_install`: EasyInstallInstallation_
-.. _`Installation from tarball`: TarballInstallation_
-.. _`Install from version control`: MercurialInstallation_
-
-
-.. _DebianInstallation:
-
-Debian/Ubuntu install
----------------------
-
-|cubicweb| is packaged for Debian/Ubuntu (and derived
-distributions). Their integrated package-management system make
-installation and upgrade much easier for users since
-dependencies (like databases) are automatically installed.
-
-Depending on the distribution you are using, add the appropriate line to your
-`list of sources` (for example by editing ``/etc/apt/sources.list``).
-
-For Debian 7.0 Wheezy (stable)::
-
- deb http://download.logilab.org/production/ wheezy/
-
-For Debian Sid (unstable)::
-
- deb http://download.logilab.org/production/ sid/
-
-For Ubuntu 12.04 Precise Pangolin (Long Term Support) and newer::
-
- deb http://download.logilab.org/production/ precise/
-
-The repositories are signed with the `Logilab's gnupg key`_. You can download
-and register the key to avoid warnings::
-
- wget -q http://download.logilab.org/logilab-dists-key.asc -O- | sudo apt-key add -
-
-Update your list of packages and perform the installation::
-
- apt-get update
- apt-get install cubicweb cubicweb-dev
-
-``cubicweb`` installs the framework itself, allowing you to create new
-instances. ``cubicweb-dev`` installs the development environment
-allowing you to develop new cubes.
-
-There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
-list of available cubes using ``apt-cache search cubicweb`` or at the
-`CubicWeb.org forge`_.
-
-.. note::
-
- `cubicweb-dev` will install basic sqlite support. You can easily setup
- :ref:`cubicweb with other database <DatabaseInstallation>` using the following
- virtual packages :
-
- * `cubicweb-postgresql-support` contains the necessary dependencies for
- using :ref:`cubicweb with postgresql datatabase <PostgresqlConfiguration>`
-
- * `cubicweb-mysql-support` contains the necessary dependencies for using
- :ref:`cubicweb with mysql database <MySqlConfiguration>`.
-
-.. _`list of sources`: http://wiki.debian.org/SourcesList
-.. _`Logilab's gnupg key`: http://download.logilab.org/logilab-dists-key.asc
-.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/
-
-.. _WindowsInstallation:
-
-Windows Install
----------------
-
-You need to have `python`_ version >= 2.5 and < 3 installed.
-
-If you want an automated install, your best option is probably the
-:ref:`EasyInstallInstallation`. EasyInstall is a tool that helps users to
-install python packages along with their dependencies, searching for suitable
-pre-compiled binaries on the `The Python Package Index`_.
-
-If you want better control over the process as well as a suitable development
-environment or if you are having problems with `easy_install`, read on to
-:ref:`SetUpWindowsEnv`.
-
-.. _python: http://www.python.org/
-.. _`The Python Package Index`: http://pypi.python.org
-
-.. _VirtualenvInstallation:
-
-`Virtualenv` install
---------------------
-
-|cubicweb| can be safely installed, used and contained inside a
-`virtualenv`_. You can use either :ref:`pip <PipInstallation>` or
-:ref:`easy_install <EasyInstallInstallation>` to install |cubicweb|
-inside an activated virtual environment.
-
-.. _PipInstallation:
-
-`pip` install
--------------
-
-`pip <http://pip.openplans.org/>`_ is a python tool that helps downloading,
-building, installing, and managing Python packages and their dependencies. It
-is fully compatible with `virtualenv`_ and installs the packages from sources
-published on the `The Python Package Index`_.
-
-.. _`virtualenv`: http://virtualenv.openplans.org/
-
-A working compilation chain is needed to build the modules that include C
-extensions. If you really do not want to compile anything, installing `lxml <http://lxml.de/>`_,
-`Twisted Web <http://twistedmatrix.com/trac/wiki/Downloads/>`_ and `libgecode
-<http://www.gecode.org/>`_ will help.
-
-For Debian, these minimal dependencies can be obtained by doing::
-
- apt-get install gcc python-pip python-dev python-lxml
-
-or, if you prefer to get as much as possible from pip::
-
- apt-get install gcc python-pip python-dev libxslt1-dev libxml2-dev
-
-For Windows, you can install pre-built packages (possible `source
-<http://www.lfd.uci.edu/~gohlke/pythonlibs/>`_). For a minimal setup, install:
-
-- pip http://www.lfd.uci.edu/~gohlke/pythonlibs/#pip
-- setuptools http://www.lfd.uci.edu/~gohlke/pythonlibs/#setuptools
-- libxml-python http://www.lfd.uci.edu/~gohlke/pythonlibs/#libxml-python>
-- lxml http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml and
-- twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
-
-Make sure to choose the correct architecture and version of Python.
-
-Finally, install |cubicweb| and its dependencies, by running::
-
- pip install cubicweb
-
-Many other :ref:`cubes <AvailableCubes>` are available. A list is available at
-`PyPI <http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
-or at the `CubicWeb.org forge`_.
-
-For example, installing the *blog cube* is achieved by::
-
- pip install cubicweb-blog
-
-.. _EasyInstallInstallation:
-
-`easy_install` install
-----------------------
-
-.. note::
-
- If you are not a Windows user and you have a compilation environment, we
- recommend you to use the PipInstallation_.
-
-`easy_install`_ is a python utility that helps downloading, installing, and
-managing python packages and their dependencies.
-
-Install |cubicweb| and its dependencies, run::
-
- easy_install cubicweb
-
-There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
-list of available cubes on `PyPI
-<http://pypi.python.org/pypi?%3Aaction=search&term=cubicweb&submit=search>`_
-or at the `CubicWeb.org Forge`_.
-
-For example, installing the *blog cube* is achieved by::
-
- easy_install cubicweb-blog
-
-.. note::
-
- If you encounter problem with :ref:`cubes <AvailableCubes>` installation,
- consider using :ref:`PipInstallation` which is more stable
- but can not installed pre-compiled binaries.
-
-.. _`easy_install`: http://packages.python.org/distribute/easy_install.html
-
-
-.. _SourceInstallation:
-
-Install from source
--------------------
-
-.. _TarballInstallation:
-
-You can download the archive containing the sources from
-`http://download.logilab.org/pub/cubicweb/ <http://download.logilab.org/pub/cubicweb/>`_.
-
-Make sure you also have all the :ref:`InstallDependencies`.
-
-Once uncompressed, you can install the framework from inside the uncompressed
-folder with::
-
- python setup.py install
-
-Or you can run |cubicweb| directly from the source directory by
-setting the :ref:`resource mode <RessourcesConfiguration>` to `user`. This will
-ease the development with the framework.
-
-There is also a wide variety of :ref:`cubes <AvailableCubes>`. You can access a
-list of availble cubes at the `CubicWeb.org Forge`_.
-
-
-.. _MercurialInstallation:
-
-Install from version control system
------------------------------------
-
-To keep-up with on-going development, clone the :ref:`Mercurial
-<MercurialPresentation>` repository::
-
- hg clone -u stable http://hg.logilab.org/cubicweb # stable branch
- hg clone http://hg.logilab.org/cubicweb # development branch
-
-To get many of CubicWeb's dependencies and a nice set of base cubes, run the
-`clone_deps.py` script located in `cubicweb/bin/`::
-
- python cubicweb/bin/clone_deps.py
-
-(Windows users should replace slashes with antislashes).
-
-This script will clone a set of mercurial repositories into the
-directory containing the ``cubicweb`` repository, and update them to the
-latest published version tag (if any).
-
-.. note::
-
- In every cloned repositories, a `hg tags` will display a list of
- tags in reverse chronological order. One reasonnable option is to go to a
- tagged version: the latest published version or example, as done by
- the `clone_deps` script)::
-
- hg update cubicweb-version-3.12.2
-
-Make sure you also have all the :ref:`InstallDependencies`.
-
--- a/doc/book/en/admin/site-config.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-User interface for web site configuration
-=========================================
-
-.. image:: ../images/lax-book_03-site-config-panel_en.png
-
-This panel allows you to configure the appearance of your instance site.
-Six menus are available and we will go through each of them to explain how
-to use them.
-
-Navigation
-~~~~~~~~~~
-This menu provides you a way to adjust some navigation options depending on
-your needs, such as the number of entities to display by page of results.
-Follows the detailled list of available options :
-
-* navigation.combobox-limit : maximum number of entities to display in related
- combo box (sample format: 23)
-* navigation.page-size : maximum number of objects displayed by page of results
- (sample format: 23)
-* navigation.related-limit : maximum number of related entities to display in
- the primary view (sample format: 23)
-* navigation.short-line-size : maximum number of characters in short description
- (sample format: 23)
-
-UI
-~~
-This menu provides you a way to customize the user interface settings such as
-date format or encoding in the produced html.
-Follows the detailled list of available options :
-
-* ui.date-format : how to format date in the ui ("man strftime" for format description)
-* ui.datetime-format : how to format date and time in the ui ("man strftime" for format
- description)
-* ui.default-text-format : default text format for rich text fields.
-* ui.encoding : user interface encoding
-* ui.fckeditor :should html fields being edited using fckeditor (a HTML WYSIWYG editor).
- You should also select text/html as default text format to actually get fckeditor.
-* ui.float-format : how to format float numbers in the ui
-* ui.language : language of the user interface
-* ui.main-template : id of main template used to render pages
-* ui.site-title : site title, which is displayed right next to the logo in the header
-* ui.time-format : how to format time in the ui ("man strftime" for format description)
-
-
-Actions
-~~~~~~~
-This menu provides a way to configure the context in which you expect the actions
-to be displayed to the user and if you want the action to be visible or not.
-You must have notice that when you view a list of entities, an action box is
-available on the left column which display some actions as well as a drop-down
-menu for more actions.
-
-The context available are :
-
-* mainactions : actions listed in the left box
-* moreactions : actions listed in the `more` menu of the left box
-* addrelated : add actions listed in the left box
-* useractions : actions listed in the first section of drop-down menu
- accessible from the right corner user login link
-* siteactions : actions listed in the second section of drop-down menu
- accessible from the right corner user login link
-* hidden : select this to hide the specific action
-
-Boxes
-~~~~~
-The instance has already a pre-defined set of boxes you can use right away.
-This configuration section allows you to place those boxes where you want in the
-instance interface to customize it.
-
-The available boxes are :
-
-* actions box : box listing the applicable actions on the displayed data
-
-* boxes_blog_archives_box : box listing the blog archives
-
-* possible views box : box listing the possible views for the displayed data
-
-* rss box : RSS icon to get displayed data as a RSS thread
-
-* search box : search box
-
-* startup views box : box listing the configuration options available for
- the instance site, such as `Preferences` and `Site Configuration`
-
-Components
-~~~~~~~~~~
-[WRITE ME]
-
-Contextual components
-~~~~~~~~~~~~~~~~~~~~~
-[WRITE ME]
-
--- a/doc/book/en/annexes/depends.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _InstallDependencies:
-
-Installation dependencies
-=========================
-
-When you run CubicWeb from source, either by downloading the tarball or
-cloning the mercurial tree, here is the list of tools and libraries you need
-to have installed in order for CubicWeb to work:
-
-* yapps - http://theory.stanford.edu/~amitp/yapps/ -
- http://pypi.python.org/pypi/Yapps2
-
-* pygraphviz - http://networkx.lanl.gov/pygraphviz/ -
- http://pypi.python.org/pypi/pygraphviz
-
-* docutils - http://docutils.sourceforge.net/ - http://pypi.python.org/pypi/docutils
-
-* lxml - http://codespeak.net/lxml - http://pypi.python.org/pypi/lxml
-
-* twisted - http://twistedmatrix.com/ - http://pypi.python.org/pypi/Twisted
-
-* logilab-common - http://www.logilab.org/project/logilab-common -
- http://pypi.python.org/pypi/logilab-common/
-
-* logilab-database - http://www.logilab.org/project/logilab-database -
- http://pypi.python.org/pypi/logilab-database/
-
-* logilab-constraint - http://www.logilab.org/project/logilab-constraint -
- http://pypi.python.org/pypi/constraint/
-
-* logilab-mtconverter - http://www.logilab.org/project/logilab-mtconverter -
- http://pypi.python.org/pypi/logilab-mtconverter
-
-* rql - http://www.logilab.org/project/rql - http://pypi.python.org/pypi/rql
-
-* yams - http://www.logilab.org/project/yams - http://pypi.python.org/pypi/yams
-
-* indexer - http://www.logilab.org/project/indexer -
- http://pypi.python.org/pypi/indexer
-
-* passlib - https://code.google.com/p/passlib/ -
- http://pypi.python.org/pypi/passlib
-
-If you're using a Postgresql database (recommended):
-
-* psycopg2 - http://initd.org/projects/psycopg2 - http://pypi.python.org/pypi/psycopg2
-* plpythonu extension
-
-Other optional packages:
-
-* fyzz - http://www.logilab.org/project/fyzz -
- http://pypi.python.org/pypi/fyzz *to activate Sparql querying*
-
-
-Any help with the packaging of CubicWeb for more than Debian/Ubuntu (including
-eggs, buildouts, etc) will be greatly appreciated.
--- a/doc/book/en/annexes/docstrings-conventions.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-Javascript docstrings
-=====================
-
-Whereas in Python source code we only need to include a module docstrings
-using the directive `.. automodule:: mypythonmodule`, we will have to
-explicitely define Javascript modules and functions in the doctrings since
-there is no native directive to include Javascript files.
-
-Rest generation
----------------
-
-`pyjsrest` is a small utility parsing Javascript doctrings and generating the
-corresponding Restructured file used by Sphinx to generate HTML documentation.
-This script will have the following structure::
-
- ===========
- filename.js
- ===========
- .. module:: filename.js
-
-We use the `.. module::` directive to register a javascript library
-as a Python module for Sphinx. This provides an entry in the module index.
-
-The contents of the docstring found in the javascript file will be added as is
-following the module declaration. No treatment will be done on the doctring.
-All the documentation structure will be in the docstrings and will comply
-with the following rules.
-
-Docstring structure
--------------------
-
-Basically we document javascript with RestructuredText docstring
-following the same convention as documenting Python code.
-
-The doctring in Javascript files must be contained in standard
-Javascript comment signs, starting with `/**` and ending with `*/`,
-such as::
-
- /**
- * My comment starts here.
- * This is the second line prefixed with a `*`.
- * ...
- * ...
- * All the follwing line will be prefixed with a `*` followed by a space.
- * ...
- * ...
- */
-
-
-Comments line prefixed by `//` will be ignored. They are reserved for source
-code comments dedicated to developers.
-
-
-Javscript functions docstring
------------------------------
-
-By default, the `function` directive describes a module-level function.
-
-`function` directive
-~~~~~~~~~~~~~~~~~~~~
-
-Its purpose is to define the function prototype such as::
-
- .. function:: loadxhtml(url, data, reqtype, mode)
-
-If any namespace is used, we should add it in the prototype for now,
-until we define an appropriate directive::
-
- .. function:: jQuery.fn.loadxhtml(url, data, reqtype, mode)
-
-Function parameters
-~~~~~~~~~~~~~~~~~~~
-
-We will define function parameters as a bulleted list, where the
-parameter name will be backquoted and followed by its description.
-
-Example of a javascript function docstring::
-
- .. function:: loadxhtml(url, data, reqtype, mode)
-
- cubicweb loadxhtml plugin to make jquery handle xhtml response
-
- fetches `url` and replaces this's content with the result
-
- Its arguments are:
-
- * `url`
-
- * `mode`, how the replacement should be done (default is 'replace')
- Possible values are :
- - 'replace' to replace the node's content with the generated HTML
- - 'swap' to replace the node itself with the generated HTML
- - 'append' to append the generated HTML to the node's content
-
-
-Optional parameter specification
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Javascript functions handle arguments not listed in the function signature.
-In the javascript code, they will be flagged using `/* ... */`. In the docstring,
-we flag those optional arguments the same way we would define it in
-Python::
-
- .. function:: asyncRemoteExec(fname, arg1=None, arg2=None)
-
-
--- a/doc/book/en/annexes/faq.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,437 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Frequently Asked Questions (FAQ)
-================================
-
-
-Generalities
-````````````
-
-Why do you use the LGPL license to prevent me from doing X ?
-------------------------------------------------------------
-
-LGPL means that *if* you redistribute your application, you need to
-redistribute the changes you made to CubicWeb under the LGPL licence.
-
-Publishing a web site has nothing to do with redistributing source
-code according to the terms of the LGPL. A fair amount of companies
-use modified LGPL code for internal use. And someone could publish a
-*CubicWeb* component under a BSD licence for others to plug into a
-LGPL framework without any problem. The only thing we are trying to
-prevent here is someone taking the framework and packaging it as
-closed source to his own clients.
-
-Why does not CubicWeb have a template language ?
-------------------------------------------------
-
-There are enough template languages out there. You can use your
-preferred template language if you want. [explain how to use a
-template language]
-
-*CubicWeb* does not define its own templating language as this was
-not our goal. Based on our experience, we realized that
-we could gain productivity by letting designers use design tools
-and developpers develop without the use of the templating language
-as an intermediary that could not be anyway efficient for both parties.
-Python is the templating language that we use in *CubicWeb*, but again,
-it does not prevent you from using a templating language.
-
-Moreover, CubicWeb currently supports `simpletal`_ out of the box and
-it is also possible to use the `cwtags`_ library to build html trees
-using the `with statement`_ with more comfort than raw strings.
-
-.. _`simpletal`: http://www.owlfish.com/software/simpleTAL/
-.. _`cwtags`: http://www.cubicweb.org/project/cwtags
-.. _`with statement`: http://www.python.org/dev/peps/pep-0343/
-
-Why do you think using pure python is better than using a template language ?
------------------------------------------------------------------------------
-
-Python is an Object Oriented Programming language and as such it
-already provides a consistent and strong architecture and syntax
-a templating language would not reach.
-
-Using Python instead of a template langage for describing the user interface
-makes it to maintain with real functions/classes/contexts without the need of
-learning a new dialect. By using Python, we use standard OOP techniques and
-this is a key factor in a robust application.
-
-CubicWeb looks pretty recent. Is it stable ?
---------------------------------------------
-
-It is constantly evolving, piece by piece. The framework has evolved since
-2001 and data has been migrated from one schema to the other ever since. There
-is a well-defined way to handle data and schema migration.
-
-You can see the roadmap there:
-http://www.cubicweb.org/project/cubicweb?tab=projectroadmap_tab.
-
-
-Why is the RQL query language looking similar to X ?
-----------------------------------------------------
-
-It may remind you of SQL but it is higher level than SQL, more like
-SPARQL. Except that SPARQL did not exist when we started the project.
-With version 3.4, CubicWeb has support for SPARQL.
-
-The RQL language is what is going to make a difference with django-
-like frameworks for several reasons.
-
-1. accessing data is *much* easier with it. One can write complex
- queries with RQL that would be tedious to define and hard to maintain
- using an object/filter suite of method calls.
-
-2. it offers an abstraction layer allowing your applications to run
- on multiple back-ends. That means not only various SQL backends
- (postgresql, sqlite, sqlserver, mysql), but also non-SQL data stores like
- LDAP directories and subversion/mercurial repositories (see the `vcsfile`
- component).
-
-Which ajax library is CubicWeb using ?
---------------------------------------
-
-CubicWeb uses jQuery_ and provides a few helpers on top of that. Additionally,
-some jQuery plugins are provided (some are provided in specific cubes).
-
-.. _jQuery: http://jquery.com
-
-
-Development
-```````````
-
-How to change the instance logo ?
----------------------------------
-
-The logo is managed by css. You must provide a custom css that will contain
-the code below:
-
-::
-
- #logo {
- background-image: url("logo.jpg");
- }
-
-
-``logo.jpg`` is in ``mycube/data`` directory.
-
-How to create an anonymous user ?
----------------------------------
-
-This allows to browse the site without being authenticated. In the
-``all-in-one.conf`` file of your instance, define the anonymous user
-as follows ::
-
- # login of the CubicWeb user account to use for anonymous user (if you want to
- # allow anonymous)
- anonymous-user=anon
-
- # password of the CubicWeb user account matching login
- anonymous-password=anon
-
-You also must ensure that this `anon` user is a registered user of
-the DB backend. If not, you can create through the administation
-interface of your instance by adding a user with in the group `guests`.
-
-.. note::
- While creating a new instance, you can decide to allow access
- to anonymous user, which will automatically execute what is
- decribed above.
-
-How to load data from a python script ?
----------------------------------------
-Please, refer to :ref:`UsingPyro`.
-
-
-How to format an entity date attribute ?
-----------------------------------------
-
-If your schema has an attribute of type `Date` or `Datetime`, you usually want to
-format it when displaying it. First, you should define your preferred format
-using the site configuration panel
-``http://appurl/view?vid=systempropertiesform`` and then set ``ui.date`` and/or
-``ui.datetime``. Then in the view code, use:
-
-.. sourcecode:: python
-
- entity.printable_value(date_attribute)
-
-which will always return a string whatever the attribute's type (so it's
-recommended also for other attribute types). By default it expects to generate
-HTML, so it deals with rich text formating, xml escaping...
-
-How to update a database after a schema modification ?
-------------------------------------------------------
-
-It depends on what has been modified in the schema.
-
-* update the permissions and properties of an entity or a relation:
- ``sync_schema_props_perms('MyEntityOrRelation')``.
-
-* add an attribute: ``add_attribute('MyEntityType', 'myattr')``.
-
-* add a relation: ``add_relation_definition('SubjRelation', 'MyRelation', 'ObjRelation')``.
-
-I get `NoSelectableObject` exceptions, how do I debug selectors ?
------------------------------------------------------------------
-
-You just need to put the appropriate context manager around view/component
-selection. One standard place for components is in cubicweb/vregistry.py:
-
-.. sourcecode:: python
-
- def possible_objects(self, *args, **kwargs):
- """return an iterator on possible objects in this registry for the given
- context
- """
- from logilab.common.registry import traced_selection
- with traced_selection():
- for appobjects in self.itervalues():
- try:
- yield self._select_best(appobjects, *args, **kwargs)
- except NoSelectableObject:
- continue
-
-This will yield additional WARNINGs, like this::
-
- 2009-01-09 16:43:52 - (cubicweb.selectors) WARNING: selector one_line_rset returned 0 for <class 'cubicweb.web.views.basecomponents.WFHistoryVComponent'>
-
-For views, you can put this context in `cubicweb/web/views/basecontrollers.py` in
-the `ViewController`:
-
-.. sourcecode:: python
-
- def _select_view_and_rset(self, rset):
- ...
- try:
- from logilab.common.registry import traced_selection
- with traced_selection():
- view = self._cw.vreg['views'].select(vid, req, rset=rset)
- except ObjectNotFound:
- self.warning("the view %s could not be found", vid)
- req.set_message(req._("The view %s could not be found") % vid)
- vid = vid_from_rset(req, rset, self._cw.vreg.schema)
- view = self._cw.vreg['views'].select(vid, req, rset=rset)
- ...
-
-I get "database is locked" when executing tests
------------------------------------------------
-
-If you have "database is locked" as error when you are executing security tests,
-it is usually because commit or rollback are missing before login() calls.
-
-You can also use a context manager, to avoid such errors, as described
-here: :ref:`securitytest`.
-
-
-What are hooks used for ?
--------------------------
-
-Hooks are executed around (actually before or after) events. The most common
-events are data creation, update and deletion. They permit additional constraint
-checking (those not expressible at the schema level), pre and post computations
-depending on data movements.
-
-As such, they are a vital part of the framework.
-
-Other kinds of hooks, called Operations, are available
-for execution just before commit.
-
-For more information, read :ref:`hooks` section.
-
-
-Configuration
-`````````````
-
-How to configure a LDAP source ?
---------------------------------
-
-See :ref:`LDAP`.
-
-How to import LDAP users in |cubicweb| ?
-----------------------------------------
-
- Here is a useful script which enables you to import LDAP users
- into your *CubicWeb* instance by running the following:
-
-.. sourcecode:: python
-
- import os
- import pwd
- import sys
-
- from logilab.database import get_connection
-
- def getlogin():
- """avoid using os.getlogin() because of strange tty/stdin problems
- (man 3 getlogin)
- Another solution would be to use $LOGNAME, $USER or $USERNAME
- """
- return pwd.getpwuid(os.getuid())[0]
-
-
- try:
- database = sys.argv[1]
- except IndexError:
- print 'USAGE: python ldap2system.py <database>'
- sys.exit(1)
-
- if raw_input('update %s db ? [y/n]: ' % database).strip().lower().startswith('y'):
- cnx = get_connection(user=getlogin(), database=database)
- cursor = cnx.cursor()
-
- insert = ('INSERT INTO euser (creation_date, eid, modification_date, login, '
- ' firstname, surname, last_login_time, upassword) '
- "VALUES (%(mtime)s, %(eid)s, %(mtime)s, %(login)s, %(firstname)s, "
- "%(surname)s, %(mtime)s, './fqEz5LeZnT6');")
- update = "UPDATE entities SET source='system' WHERE eid=%(eid)s;"
- cursor.execute("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'")
- for eid, type, source, extid, mtime in cursor.fetchall():
- if type != 'CWUser':
- print "don't know what to do with entity type", type
- continue
- if source != 'ldapuser':
- print "don't know what to do with source type", source
- continue
- ldapinfos = dict(x.strip().split('=') for x in extid.split(','))
- login = ldapinfos['uid']
- firstname = ldapinfos['uid'][0].upper()
- surname = ldapinfos['uid'][1:].capitalize()
- if login != 'jcuissinat':
- args = dict(eid=eid, type=type, source=source, login=login,
- firstname=firstname, surname=surname, mtime=mtime)
- print args
- cursor.execute(insert, args)
- cursor.execute(update, args)
-
- cnx.commit()
- cnx.close()
-
-
-Security
-````````
-
-How to reset the password for user joe ?
-----------------------------------------
-
-If you want to reset the admin password for ``myinstance``, do::
-
- $ cubicweb-ctl reset-admin-pwd myinstance
-
-You need to generate a new encrypted password::
-
- $ python
- >>> from cubicweb.server.utils import crypt_password
- >>> crypt_password('joepass')
- 'qHO8282QN5Utg'
- >>>
-
-and paste it in the database::
-
- $ psql mydb
- mydb=> update cw_cwuser set cw_upassword='qHO8282QN5Utg' where cw_login='joe';
- UPDATE 1
-
-if you're running over SQL Server, you need to use the CONVERT
-function to convert the string to varbinary(255). The SQL query is
-therefore::
-
- update cw_cwuser set cw_upassword=CONVERT(varbinary(255), 'qHO8282QN5Utg') where cw_login='joe';
-
-Be careful, the encryption algorithm is different on Windows and on
-Unix. You cannot therefore use a hash generated on Unix to fill in a
-Windows database, nor the other way round.
-
-
-You can prefer use a migration script similar to this shell invocation instead::
-
- $ cubicweb-ctl shell <instance>
- >>> from cubicweb import Binary
- >>> from cubicweb.server.utils import crypt_password
- >>> crypted = crypt_password('joepass')
- >>> rset = rql('Any U WHERE U is CWUser, U login "joe"')
- >>> joe = rset.get_entity(0,0)
- >>> joe.cw_set(upassword=Binary(crypted))
-
-Please, refer to the script example is provided in the `misc/examples/chpasswd.py` file.
-
-The more experimented people would use RQL request directly::
-
- >>> rql('SET X upassword %(a)s WHERE X is CWUser, X login "joe"',
- ... {'a': crypted})
-
-I've just created a user in a group and it doesn't work !
----------------------------------------------------------
-
-You are probably getting errors such as ::
-
- remove {'PR': 'Project', 'C': 'CWUser'} from solutions since your_user has no read access to cost
-
-This is because you have to put your user in the "users" group. The user has to
-be in both groups.
-
-How is security implemented ?
-------------------------------
-
-The basis for security is a mapping from operations to groups or
-arbitrary RQL expressions. These mappings are scoped to entities and
-relations.
-
-This is an example for an Entity Type definition:
-
-.. sourcecode:: python
-
- class Version(EntityType):
- """a version is defining the content of a particular project's
- release"""
- # definition of attributes is voluntarily missing
- __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'),)}
-
-The above means that permission to read a Version is granted to any
-user that is part of one of the groups 'managers', 'users', 'guests'.
-The 'add' permission is granted to users in group 'managers' or
-'logilab' or to users in group G, if G is linked by a permission
-entity named "add_version" to the version's project.
-
-An example for a Relation Definition (RelationType both defines a
-relation type and implicitly one relation definition, on which the
-permissions actually apply):
-
-.. sourcecode:: python
-
- class version_of(RelationType):
- """link a version to its project. A version is necessarily linked
- to one and only one project. """
- # some lines voluntarily missing
- __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'),) }
-
-The main difference lies in the basic available operations (there is
-no 'update' operation) and the usage of an RRQLExpression (rql
-expression for a relation) instead of an ERQLExpression (rql
-expression for an entity).
-
-You can find additional information in the section :ref:`securitymodel`.
-
-Is it possible to bypass security from the UI (web front) part ?
-----------------------------------------------------------------
-
-No. Only Hooks/Operations can do that.
-
-Can PostgreSQL and CubicWeb authentication work with kerberos ?
-----------------------------------------------------------------
-
-If you have PostgreSQL set up to accept kerberos authentication, you can set
-the db-host, db-name and db-user parameters in the `sources` configuration
-file while leaving the password blank. It should be enough for your
-instance to connect to postgresql with a kerberos ticket.
-
-
--- a/doc/book/en/annexes/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Part4:
-
-----------
-Appendixes
-----------
-
-The following chapters are reference material.
-
-.. toctree::
- :maxdepth: 1
- :numbered:
-
- faq
- rql/index
- mercurial
- depends
- docstrings-conventions
--- a/doc/book/en/annexes/mercurial.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _MercurialPresentation:
-
-Introducing Mercurial
-=====================
-
-Introduction
-````````````
-Mercurial_ manages a distributed repository containing revisions
-trees (each revision indicates the changes required to obtain the
-next, and so on). Locally, we have a repository containing revisions
-tree, and a working directory. It is possible
-to put in its working directory, one of the versions of its local repository,
-modify and then push it in its repository.
-It is also possible to get revisions from another repository or to export
-its own revisions from the local repository to another repository.
-
-.. _Mercurial: http://www.selenic.com/mercurial/
-
-In contrast to CVS/Subversion, we usually create a repository per
-project to manage.
-
-In a collaborative development, we usually create a central repository
-accessible to all developers of the project. These central repository is used
-as a reference. According to their needs, everyone can have a local repository,
-that they will have to synchronize with the central repository from time to time.
-
-
-Major commands
-``````````````
-* Create a local repository::
-
- hg clone ssh://myhost//home/src/repo
-
-* See the contents of the local repository (graphical tool in Qt)::
-
- hgview
-
-* Add a sub-directory or file in the current directory::
-
- hg add subdir
-
-* Move to the working directory a specific revision (or last
- revision) from the local repository::
-
- hg update [identifier-revision]
- hg up [identifier-revision]
-
-* Get in its local repository, the tree of revisions contained in a
- remote repository (this does not change the local directory)::
-
- hg pull ssh://myhost//home/src/repo
- hg pull -u ssh://myhost//home/src/repo # equivalent to pull + update
-
-* See what are the heads of branches of the local repository if a `pull`
- returned a new branch::
-
- hg heads
-
-* Submit the working directory in the local repository (and create a new
- revision)::
-
- hg commit
- hg ci
-
-* Merge with the mother revision of local directory, another revision from
- the local respository (the new revision will be then two mothers
- revisions)::
-
- hg merge identifier-revision
-
-* Export to a remote repository, the tree of revisions in its content
- local respository (this does not change the local directory)::
-
- hg push ssh://myhost//home/src/repo
-
-* See what local revisions are not in another repository::
-
- hg outgoing ssh://myhost//home/src/repo
-
-* See what are the revisions of a repository not found locally::
-
- hg incoming ssh://myhost//home/src/repo
-
-* See what is the revision of the local repository which has been taken out
- from the working directory and amended::
-
- hg parent
-
-* See the differences between the working directory and the mother revision
- of the local repository, possibly to submit them in the local repository::
-
- hg diff
- hg commit-tool
- hg ct
-
-
-Best Practices
-``````````````
-* Remember to `hg pull -u` regularly, and particularly before
- a `hg commit`.
-
-* Remember to `hg push` when your repository contains a version
- relatively stable of your changes.
-
-* If a `hg pull -u` created a new branch head:
-
- 1. find its identifier with `hg head`
- 2. merge with `hg merge`
- 3. `hg ci`
- 4. `hg push`
-
-Installation of the guestrepo extension
-```````````````````````````````````````
-
-Set up the guestrepo extension by getting a copy of the sources
-from https://bitbucket.org/selinc/guestrepo and adding the following
-lines to your ``~/.hgrc``: ::
-
- [extensions]
- guestrepo=/path/to/guestrepo/guestrepo
-
-
-More information
-````````````````
-
-For more information about Mercurial, please refer to the Mercurial project online documentation_.
-
-.. _documentation: http://www.selenic.com/mercurial/wiki/
-
Binary file doc/book/en/annexes/rql/Graph-ex.gif has changed
--- a/doc/book/en/annexes/rql/debugging.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _DEBUGGING:
-
-Debugging RQL
--------------
-
-Available levels
-~~~~~~~~~~~~~~~~
-
-Server debugging flags. They may be combined using binary operators.
-
-.. autodata:: cubicweb.server.DBG_NONE
-.. autodata:: cubicweb.server.DBG_RQL
-.. autodata:: cubicweb.server.DBG_SQL
-.. autodata:: cubicweb.server.DBG_REPO
-.. autodata:: cubicweb.server.DBG_MS
-.. autodata:: cubicweb.server.DBG_HOOKS
-.. autodata:: cubicweb.server.DBG_OPS
-.. autodata:: cubicweb.server.DBG_MORE
-.. autodata:: cubicweb.server.DBG_ALL
-
-
-Enable verbose output
-~~~~~~~~~~~~~~~~~~~~~
-
-To debug your RQL statements, it can be useful to enable a verbose output:
-
-.. sourcecode:: python
-
- from cubicweb import server
- server.set_debug(server.DBG_RQL|server.DBG_SQL|server.DBG_ALL)
-
-.. autofunction:: cubicweb.server.set_debug
-
-Another example showing how to debug hooks at a specific code site:
-
-.. sourcecode:: python
-
- from cubicweb.server import debugged, DBG_HOOKS
- with debugged(DBG_HOOKS):
- person.cw_set(works_for=company)
-
-
-Detect largest RQL queries
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-See `Profiling and performance` chapter (see :ref:`PROFILING`).
-
-
-API
-~~~
-
-.. autoclass:: cubicweb.server.debugged
-
--- a/doc/book/en/annexes/rql/implementation.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-
-
-Implementation
---------------
-
-BNF grammar
-~~~~~~~~~~~
-
-The terminal elements are in capital letters, non-terminal in lowercase.
-The value of the terminal elements (between quotes) is a Python regular
-expression.
-::
-
- statement ::= (select | delete | insert | update) ';'
-
-
- # select specific rules
- select ::= 'DISTINCT'? E_TYPE selected_terms restriction? group? sort?
-
- selected_terms ::= expression ( ',' expression)*
-
- group ::= 'GROUPBY' VARIABLE ( ',' VARIABLE)*
-
- sort ::= 'ORDERBY' sort_term ( ',' sort_term)*
-
- sort_term ::= VARIABLE sort_method =?
-
- sort_method ::= 'ASC' | 'DESC'
-
-
- # delete specific rules
- delete ::= 'DELETE' (variables_declaration | relations_declaration) restriction?
-
-
- # insert specific rules
- insert ::= 'INSERT' variables_declaration ( ':' relations_declaration)? restriction?
-
-
- # update specific rules
- update ::= 'SET' relations_declaration restriction
-
-
- # common rules
- variables_declaration ::= E_TYPE VARIABLE (',' E_TYPE VARIABLE)*
-
- relations_declaration ::= simple_relation (',' simple_relation)*
-
- simple_relation ::= VARIABLE R_TYPE expression
-
- restriction ::= 'WHERE' relations
-
- relations ::= relation (LOGIC_OP relation)*
- | '(' relations')'
-
- relation ::= 'NOT'? VARIABLE R_TYPE COMP_OP? expression
- | 'NOT'? R_TYPE VARIABLE 'IN' '(' expression (',' expression)* ')'
-
- expression ::= var_or_func_or_const (MATH_OP var_or_func_or_const) *
- | '(' expression ')'
-
- var_or_func_or_const ::= VARIABLE | function | constant
-
- function ::= FUNCTION '(' expression ( ',' expression) * ')'
-
- constant ::= KEYWORD | STRING | FLOAT | INT
-
- # tokens
- LOGIC_OP ::= ',' | 'OR' | 'AND'
- MATH_OP ::= '+' | '-' | '/' | '*'
- COMP_OP ::= '>' | '>=' | '=' | '<=' | '<' | '~=' | 'LIKE'
-
- FUNCTION ::= 'MIN' | 'MAX' | 'SUM' | 'AVG' | 'COUNT' | 'UPPER' | 'LOWER'
-
- VARIABLE ::= '[A-Z][A-Z0-9]*'
- E_TYPE ::= '[A-Z]\w*'
- R_TYPE ::= '[a-z_]+'
-
- KEYWORD ::= 'TRUE' | 'FALSE' | 'NULL' | 'TODAY' | 'NOW'
- STRING ::= "'([^'\]|\\.)*'" |'"([^\"]|\\.)*\"'
- FLOAT ::= '\d+\.\d*'
- INT ::= '\d+'
-
-
-Internal representation (syntactic tree)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The tree research does not contain the selected variables
-(e.g. there is only what follows "WHERE").
-
-The insertion tree does not contain the variables inserted or relations
-defined on these variables (e.g. there is only what follows "WHERE").
-
-The removal tree does not contain the deleted variables and relations
-(e.g. there is only what follows the "WHERE").
-
-The update tree does not contain the variables and relations updated
-(e.g. there is only what follows the "WHERE").
-
-::
-
- Select ((Relationship | And | Or)?, Group?, Sort?)
- Insert (Relations | And | Or)?
- Delete (Relationship | And | Or)?
- Update (Relations | And | Or)?
-
- And ((Relationship | And | Or), (Relationship | And | Or))
- Or ((Relationship | And | Or), (Relationship | And | Or))
-
- Relationship ((VariableRef, Comparison))
-
- Comparison ((Function | MathExpression | Keyword | Constant | VariableRef) +)
-
- Function (())
- MathExpression ((MathExpression | Keyword | Constant | VariableRef), (MathExpression | Keyword | Constant | VariableRef))
-
- Group (VariableRef +)
- Sort (SortTerm +)
- SortTerm (VariableRef +)
-
- VariableRef ()
- Variable ()
- Keyword ()
- Constant ()
-
-
-Known limitations
-~~~~~~~~~~~~~~~~~
-
-- The current implementation does not support linking two relations of type 'is'
- with an OR. I do not think that the negation is supported on this type of
- relation (XXX to be confirmed).
-
-- missing COALESCE and certainly other things...
-
-- writing an rql query requires knowledge of the used schema (with real relation
- names and entities, not those viewed in the user interface). On the other
- hand, we cannot really bypass that, and it is the job of a user interface to
- hide the RQL.
-
-
-Topics
-~~~~~~
-
-It would be convenient to express the schema matching
-relations (non-recursive rules)::
-
- Document class Type <-> Document occurence_of Fiche class Type
- Sheet class Type <-> Form collection Collection class Type
-
-Therefore 1. becomes::
-
- Document X where
- X class C, C name 'Cartoon'
- X owned_by U, U login 'syt'
- X available true
-
-I'm not sure that we should handle this at RQL level ...
-
-There should also be a special relation 'anonymous'.
--- a/doc/book/en/annexes/rql/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-.. _RQLChapter:
-
-Relation Query Language (RQL)
-=============================
-
-This chapter describes the Relation Query Language syntax and its implementation in CubicWeb.
-
-.. toctree::
- :maxdepth: 2
-
- intro
- language
- debugging
- implementation
--- a/doc/book/en/annexes/rql/intro.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-
-.. _rql_intro:
-
-Introduction
-------------
-
-Goals of RQL
-~~~~~~~~~~~~
-
-The goal is to have a semantic language in order to:
-
-- query relations in a clear syntax
-- empowers access to data repository manipulation
-- making attributes/relations browsing easy
-
-As such, attributes will be regarded as cases of special relations (in
-terms of usage, the user should see no syntactic difference between an
-attribute and a relation).
-
-Comparison with existing languages
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-SQL
-```
-
-RQL may remind of SQL but works at a higher abstraction level (the *CubicWeb*
-framework generates SQL from RQL to fetch data from relation databases). RQL is
-focused on browsing relations. The user needs only to know about the *CubicWeb*
-data model he is querying, but not about the underlying SQL model.
-
-Sparql
-``````
-
-The query language most similar to RQL is SPARQL_, defined by the W3C to serve
-for the semantic web.
-
-Versa
-`````
-
-We should look in more detail, but here are already some ideas for the moment
-... Versa_ is the language most similar to what we wanted to do, but the model
-underlying data being RDF, there are some things such as namespaces or
-handling of the RDF types which does not interest us. On the functionality
-level, Versa_ is very comprehensive including through many functions of
-conversion and basic types manipulation, which we may want to look at one time
-or another. Finally, the syntax is a little esoteric.
-
-Datalog
-```````
-
-Datalog_ is a prolog derived query langage which applies to relational
-databases. It is more expressive than RQL in that it accepts either
-extensional_ and intensional_ predicates (or relations). As of now,
-RQL only deals with intensional relations.
-
-The different types of queries
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Search (`Any`)
- Extract entities and attributes of entities.
-
-Insert entities (`INSERT`)
- Insert new entities or relations in the database.
- It can also directly create relationships for the newly created entities.
-
-Update entities, create relations (`SET`)
- Update existing entities in the database,
- or create relations between existing entities.
-
-Delete entities or relationship (`DELETE`)
- Remove entities or relations existing in the database.
-
-
-RQL relation expressions
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-RQL expressions apply to a live database defined by a
-:ref:`datamodel_definition`. Apart from the main type, or head, of the
-expression (search, insert, etc.) the most common constituent of an
-RQL expression is a (set of) relation expression(s).
-
-An RQL relation expression contains three components:
-
-* the subject, which is an entity type
-* the predicate, which is a relation definition (an arc of the schema)
-* the object, which is either an attribute or a relation to another entity
-
-.. image:: Graph-ex.gif
- :alt: <subject> <predicate> <object>
- :align: center
-
-.. warning::
-
- A relation is always expressed in the order: ``subject``,
- ``predicate``, ``object``.
-
- It is important to determine if the entity type is subject or object
- to construct a valid expression. Inverting the subject/object is an
- error since the relation cannot be found in the schema.
-
- If one does not have access to the code, one can find the order by
- looking at the schema image in manager views (the subject is located
- at the beginning of the arrow).
-
-An example of two related relation expressions::
-
- P works_for C, P name N
-
-RQL variables represent typed entities. The type of entities is
-either automatically inferred (by looking at the possible relation
-definitions, see :ref:`RelationDefinition`) or explicitely constrained
-using the ``is`` meta relation.
-
-In the example above, we barely need to look at the schema. If
-variable names (in the RQL expression) and relation type names (in the
-schema) are expresssively designed, the human reader can infer as much
-as the |cubicweb| querier.
-
-The ``P`` variable is used twice but it always represent the same set
-of entities. Hence ``P works_for C`` and ``P name N`` must be
-compatible in the sense that all the Ps (which *can* refer to
-different entity types) must accept the ``works_for`` and ``name``
-relation types. This does restrict the set of possible values of P.
-
-Adding another relation expression::
-
- P works_for C, P name N, C name "logilab"
-
-This further restricts the possible values of P through an indirect
-constraint on the possible values of ``C``. The RQL-level unification_
-happening there is translated to one (or several) joins_ at the
-database level.
-
-.. note::
-
- In |cubicweb|, the term `relation` is often found without ambiguity
- instead of `predicate`. This predicate is also known as the
- `property` of the triple in `RDF concepts`_
-
-
-RQL Operators
-~~~~~~~~~~~~~
-
-An RQL expression's head can be completed using various operators such
-as ``ORDERBY``, ``GROUPBY``, ``HAVING``, ``LIMIT`` etc.
-
-RQL relation expressions can be grouped with ``UNION`` or
-``WITH``. Predicate oriented keywords such as ``EXISTS``, ``OR``,
-``NOT`` are available.
-
-The complete zoo of RQL operators is described extensively in the
-following chapter (:ref:`RQL`).
-
-.. _RDF concepts: http://www.w3.org/TR/rdf-concepts/
-.. _Versa: http://wiki.xml3k.org/Versa
-.. _SPARQL: http://www.w3.org/TR/rdf-sparql-query/
-.. _unification: http://en.wikipedia.org/wiki/Unification_(computing)
-.. _joins: http://en.wikipedia.org/wiki/Join_(SQL)
-.. _Datalog: http://en.wikipedia.org/wiki/Datalog
-.. _intensional: http://en.wikipedia.org/wiki/Intensional_definition
-.. _extensional: http://en.wikipedia.org/wiki/Extension_(predicate_logic)
-
--- a/doc/book/en/annexes/rql/language.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,804 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _RQL:
-
-RQL syntax
-----------
-
-.. _RQLKeywords:
-
-Reserved keywords
-~~~~~~~~~~~~~~~~~
-
-::
-
- AND, ASC, BEING, DELETE, DESC, DISTINCT, EXISTS, FALSE, GROUPBY,
- HAVING, ILIKE, INSERT, LIKE, LIMIT, NOT, NOW, NULL, OFFSET,
- OR, ORDERBY, SET, TODAY, TRUE, UNION, WHERE, WITH
-
-The keywords are not case sensitive. You should not use them when defining your
-schema, or as RQL variable names.
-
-
-.. _RQLCase:
-
-Case
-~~~~
-
-* Variables should be all upper-cased.
-
-* Relation should be all lower-cased and match exactly names of relations defined
- in the schema.
-
-* Entity types should start with an upper cased letter and be followed by at least
- a lower cased latter.
-
-
-.. _RQLVariables:
-
-Variables and typing
-~~~~~~~~~~~~~~~~~~~~
-
-Entities and values to browse and/or select are represented in the query by
-*variables* that must be written in capital letters.
-
-With RQL, we do not distinguish between entities and attributes. The value of an
-attribute is considered as an entity of a particular type (see below), linked to
-one (real) entity by a relation called the name of the attribute, where the
-entity is the subject and the attribute the object.
-
-The possible type(s) for each variable is derived from the schema according to
-the constraints expressed above and thanks to the relations between each
-variable.
-
-We can restrict the possible types for a variable using the special relation
-**is** in the restrictions.
-
-
-.. _VirtualRelations:
-
-Virtual relations
-~~~~~~~~~~~~~~~~~
-
-Those relations may only be used in RQL query but are not actual attributes of
-your entities.
-
-* `has_text`: relation to use to query the full text index (only for entities
- having fulltextindexed attributes).
-
-* `identity`: relation to use to tell that a RQL variable is the same as another
- when you've to use two different variables for querying purpose. On the
- opposite it's also useful together with the ``NOT`` operator to tell that two
- variables should not identify the same entity
-
-
-.. _RQLLiterals:
-
-Literal expressions
-~~~~~~~~~~~~~~~~~~~
-
-Bases types supported by RQL are those supported by yams schema. Literal values
-are expressed as explained below:
-
-* string should be between double or single quotes. If the value contains a
- quote, it should be preceded by a backslash '\\'
-
-* floats separator is dot '.'
-
-* boolean values are ``TRUE`` and ``FALSE`` keywords
-
-* date and time should be expressed as a string with ISO notation : YYYY/MM/DD
- [hh:mm], or using keywords ``TODAY`` and ``NOW``
-
-You may also use the ``NULL`` keyword, meaning 'unspecified'.
-
-
-.. _RQLOperators:
-
-Operators
-~~~~~~~~~
-
-.. _RQLLogicalOperators:
-
-Logical operators
-`````````````````
-::
-
- AND, OR, NOT, ','
-
-',' is equivalent to 'AND' but with the smallest among the priority of logical
-operators (see :ref:`RQLOperatorsPriority`).
-
-.. _RQLMathematicalOperators:
-
-Mathematical operators
-``````````````````````
-
-+----------+---------------------+-----------+--------+
-| Operator | Description | Example | Result |
-+==========+=====================+===========+========+
-| `+` | addition | 2 + 3 | 5 |
-+----------+---------------------+-----------+--------+
-| `-` | subtraction | 2 - 3 | -1 |
-+----------+---------------------+-----------+--------+
-| `*` | multiplication | 2 * 3 | 6 |
-+----------+---------------------+-----------+--------+
-| / | division | 4 / 2 | 2 |
-+----------+---------------------+-----------+--------+
-| % | modulo (remainder) | 5 % 4 | 1 |
-+----------+---------------------+-----------+--------+
-| ^ | exponentiation | 2.0 ^ 3.0 | 8 |
-+----------+---------------------+-----------+--------+
-| & | bitwise AND | 91 & 15 | 11 |
-+----------+---------------------+-----------+--------+
-| `|` | bitwise OR | 32 | 3 | 35 |
-+----------+---------------------+-----------+--------+
-| # | bitwise XOR | 17 # 5 | 20 |
-+----------+---------------------+-----------+--------+
-| ~ | bitwise NOT | ~1 | -2 |
-+----------+---------------------+-----------+--------+
-| << | bitwise shift left | 1 << 4 | 16 |
-+----------+---------------------+-----------+--------+
-| >> | bitwise shift right | 8 >> 2 | 2 |
-+----------+---------------------+-----------+--------+
-
-
-Notice integer division truncates results depending on the backend behaviour. For
-instance, postgresql does.
-
-
-.. _RQLComparisonOperators:
-
-Comparison operators
-````````````````````
- ::
-
- =, !=, <, <=, >=, >, IN
-
-
-The syntax to use comparison operators is:
-
- `VARIABLE attribute <operator> VALUE`
-
-The `=` operator is the default operator and can be omitted, i.e. :
-
- `VARIABLE attribute = VALUE`
-
-is equivalent to
-
- `VARIABLE attribute VALUE`
-
-
-The operator `IN` provides a list of possible values:
-
-.. sourcecode:: sql
-
- Any X WHERE X name IN ('chauvat', 'fayolle', 'di mascio', 'thenault')
-
-
-.. _RQLStringOperators:
-
-String operators
-````````````````
-::
-
- LIKE, ILIKE, ~=, REGEXP
-
-The ``LIKE`` string operator can be used with the special character `%` in
-a string as wild-card:
-
-.. sourcecode:: sql
-
- -- match every entity whose name starts with 'Th'
- Any X WHERE X name ~= 'Th%'
- -- match every entity whose name endswith 'lt'
- Any X WHERE X name LIKE '%lt'
- -- match every entity whose name contains a 'l' and a 't'
- Any X WHERE X name LIKE '%l%t%'
-
-``ILIKE`` is the case insensitive version of ``LIKE``. It's not
-available on all backend (e.g. sqlite doesn't support it). If not available for
-your backend, ``ILIKE`` will behave like ``LIKE``.
-
-`~=` is a shortcut version of ``ILIKE``, or of ``LIKE`` when the
-former is not available on the back-end.
-
-
-The ``REGEXP`` is an alternative to ``LIKE`` that supports POSIX
-regular expressions:
-
-.. sourcecode:: sql
-
- -- match entities whose title starts with a digit
- Any X WHERE X title REGEXP "^[0-9].*"
-
-
-The underlying SQL operator used is back-end-dependent :
-
-- the ``~`` operator is used for postgresql,
-- the ``REGEXP`` operator for mysql and sqlite.
-
-Other back-ends are not supported yet.
-
-
-.. _RQLOperatorsPriority:
-
-Operators priority
-``````````````````
-
-#. `(`, `)`
-#. `^`, `<<`, `>>`
-#. `*`, `/`, `%`, `&`
-#. `+`, `-`, `|`, `#`
-#. `NOT`
-#. `AND`
-#. `OR`
-#. `,`
-
-
-.. _RQLSearchQuery:
-
-Search Query
-~~~~~~~~~~~~
-
-Simplified grammar of search query: ::
-
- [ `DISTINCT`] `Any` V1 (, V2) \*
- [ `GROUPBY` V1 (, V2) \*] [ `ORDERBY` <orderterms>]
- [ `LIMIT` <value>] [ `OFFSET` <value>]
- [ `WHERE` <triplet restrictions>]
- [ `WITH` V1 (, V2)\* BEING (<query>)]
- [ `HAVING` <other restrictions>]
- [ `UNION` <query>]
-
-Selection
-`````````
-
-The fist occuring clause is the selection of terms that should be in the result
-set. Terms may be variable, literals, function calls, arithmetic, etc. and each
-term is separated by a comma.
-
-There will be as much column in the result set as term in this clause, respecting
-order.
-
-Syntax for function call is somewhat intuitive, for instance:
-
-.. sourcecode:: sql
-
- Any UPPER(N) WHERE P firstname N
-
-
-Grouping and aggregating
-````````````````````````
-
-The ``GROUPBY`` keyword is followed by a list of terms on which results
-should be grouped. They are usually used with aggregate functions, responsible to
-aggregate values for each group (see :ref:`RQLAggregateFunctions`).
-
-For grouped queries, all selected variables must be either aggregated (i.e. used
-by an aggregate function) or grouped (i.e. listed in the ``GROUPBY``
-clause).
-
-
-Sorting
-```````
-
-The ``ORDERBY`` keyword if followed by the definition of the selection
-order: variable or column number followed by sorting method (``ASC``,
-``DESC``), ``ASC`` being the default. If the sorting method is not
-specified, then the sorting is ascendant (`ASC`).
-
-
-Pagination
-``````````
-
-The ``LIMIT`` and ``OFFSET`` keywords may be respectively used to
-limit the number of results and to tell from which result line to start (for
-instance, use `LIMIT 20` to get the first 20 results, then `LIMIT 20 OFFSET 20`
-to get the next 20.
-
-
-Restrictions
-````````````
-
-The ``WHERE`` keyword introduce one of the "main" part of the query, where
-you "define" variables and add some restrictions telling what you're interested
-in.
-
-It's a list of triplets "subject relation object", e.g. `V1 relation
-(V2 | <static value>)`. Triplets are separated using :ref:`RQLLogicalOperators`.
-
-.. note::
-
- About the negation operator (``NOT``):
-
- * ``NOT X relation Y`` is equivalent to ``NOT EXISTS(X relation Y)``
-
- * ``Any X WHERE NOT X owned_by U`` means "entities that have no relation
- ``owned_by``".
-
- * ``Any X WHERE NOT X owned_by U, U login "syt"`` means "the entity have no
- relation ``owned_by`` with the user syt". They may have a relation "owned_by"
- with another user.
-
-In this clause, you can also use ``EXISTS`` when you want to know if some
-expression is true and do not need the complete set of elements that make it
-true. Testing for existence is much faster than fetching the complete set of
-results, especially when you think about using ``OR`` against several expressions. For instance
-if you want to retrieve versions which are in state "ready" or tagged by
-"priority", you should write :
-
-.. sourcecode:: sql
-
- Any X ORDERBY PN,N
- WHERE X num N, X version_of P, P name PN,
- EXISTS(X in_state S, S name "ready")
- OR EXISTS(T tags X, T name "priority")
-
-not
-
-.. sourcecode:: sql
-
- Any X ORDERBY PN,N
- WHERE X num N, X version_of P, P name PN,
- (X in_state S, S name "ready")
- OR (T tags X, T name "priority")
-
-Both queries aren't at all equivalent :
-
-* the former will retrieve all versions, then check for each one which are in the
- matching state of or tagged by the expected tag,
-
-* the later will retrieve all versions, state and tags (cartesian product!),
- compute join and then exclude each row which are in the matching state or
- tagged by the expected tag. This implies that you won't get any result if the
- in_state or tag tables are empty (ie there is no such relation in the
- application). This is usually NOT what you want.
-
-Another common case where you may want to use ``EXISTS`` is when you
-find yourself using ``DISTINCT`` at the beginning of your query to
-remove duplicate results. The typical case is when you have a
-multivalued relation such as Version version_of Project and you want
-to retrieve projects which have a version:
-
-.. sourcecode:: sql
-
- Any P WHERE V version_of P
-
-will return each project number of versions times. So you may be
-tempted to use:
-
-.. sourcecode:: sql
-
- DISTINCT ANY P WHERE V version_of P
-
-This will work, but is not efficient, as it will use the ``SELECT
-DISTINCT`` SQL predicate, which needs to retrieve all projects, then
-sort them and discard duplicates, which can have a very high cost for
-large result sets. So the best way to write this is:
-
-.. sourcecode:: sql
-
- ANY P WHERE EXISTS V version_of P
-
-
-You can also use the question mark (`?`) to mark optional relations. This allows
-you to select entities related **or not** to another. It is a similar concept
-to `Left outer join`_:
-
- the result of a left outer join (or simply left join) for table A and B
- always contains all records of the "left" table (A), even if the
- join-condition does not find any matching record in the "right" table (B).
-
-You must use the `?` behind a variable to specify that the relation to
-that variable is optional. For instance:
-
-- Bugs of a project attached or not to a version
-
- .. sourcecode:: sql
-
- Any X, V WHERE X concerns P, P eid 42, X corrected_in V?
-
- You will get a result set containing all the project's tickets, with either the
- version in which it's fixed or None for tickets not related to a version.
-
-
-- All cards and the project they document if any
-
- .. sourcecode:: sql
-
- Any C, P WHERE C is Card, P? documented_by C
-
-Notice you may also use outer join:
-
-- on the RHS of attribute relation, e.g.
-
- .. sourcecode:: sql
-
- Any X WHERE X ref XR, Y name XR?
-
- so that Y is outer joined on X by ref/name attributes comparison
-
-
-- on any side of an ``HAVING`` expression, e.g.
-
- .. sourcecode:: sql
-
- Any X WHERE X creation_date XC, Y creation_date YC
- HAVING YEAR(XC)=YEAR(YC)?
-
- so that Y is outer joined on X by comparison of the year extracted from their
- creation date.
-
- .. sourcecode:: sql
-
- Any X WHERE X creation_date XC, Y creation_date YC
- HAVING YEAR(XC)?=YEAR(YC)
-
- would outer join X on Y instead.
-
-
-Having restrictions
-```````````````````
-
-The ``HAVING`` clause, as in SQL, may be used to restrict a query
-according to value returned by an aggregate function, e.g.
-
-.. sourcecode:: sql
-
- Any X GROUPBY X WHERE X relation Y HAVING COUNT(Y) > 10
-
-It may however be used for something else: In the ``WHERE`` clause, we are
-limited to triplet expressions, so some things may not be expressed there. Let's
-take an example : if you want to get people whose upper-cased first name equals to
-another person upper-cased first name. There is no proper way to express this
-using triplet, so you should use something like:
-
-.. sourcecode:: sql
-
- Any X WHERE X firstname XFN, Y firstname YFN, NOT X identity Y HAVING UPPER(XFN) = UPPER(YFN)
-
-Another example: imagine you want person born in 2000:
-
-.. sourcecode:: sql
-
- Any X WHERE X birthday XB HAVING YEAR(XB) = 2000
-
-Notice that while we would like this to work without the HAVING clause, this
-can't be currently be done because it introduces an ambiguity in RQL's grammar
-that can't be handled by Yapps_, the parser's generator we're using.
-
-
-Sub-queries
-```````````
-
-The ``WITH`` keyword introduce sub-queries clause. Each sub-query has the
-form:
-
- V1(,V2) BEING (rql query)
-
-Variables at the left of the ``BEING`` keyword defines into which
-variables results from the sub-query will be mapped to into the outer query.
-Sub-queries are separated from each other using a comma.
-
-Let's say we want to retrieve for each project its number of versions and its
-number of tickets. Due to the nature of relational algebra behind the scene, this
-can't be achieved using a single query. You have to write something along the
-line of:
-
-.. sourcecode:: sql
-
- Any X, VC, TC WHERE X identity XX
- WITH X, VC BEING (Any X, COUNT(V) GROUPBY X WHERE V version_of X),
- XX, TC BEING (Any X, COUNT(T) GROUPBY X WHERE T ticket_of X)
-
-Notice that we can't reuse a same variable name as alias for two different
-sub-queries, hence the usage of 'X' and 'XX' in this example, which are then
-unified using the special `identity` relation (see :ref:`VirtualRelations`).
-
-.. warning::
-
- Sub-queries define a new variable scope, so even if a variable has the same name
- in the outer query and in the sub-query, they technically **aren't** the same
- variable. So:
-
- .. sourcecode:: sql
-
- Any W, REF WITH W, REF BEING
- (Any W, REF WHERE W is Workcase, W ref REF,
- W concerned_by D, D name "Logilab")
-
- could be written:
-
- .. sourcecode:: sql
-
- Any W, REF WITH W, REF BEING
- (Any W1, REF1 WHERE W1 is Workcase, W1 ref REF1,
- W1 concerned_by D, D name "Logilab")
-
- Also, when a variable is coming from a sub-query, you currently can't reference
- its attribute or inlined relations in the outer query, you've to fetch them in
- the sub-query. For instance, let's say we want to sort by project name in our
- first example, we would have to write:
-
- .. sourcecode:: sql
-
-
- Any X, VC, TC ORDERBY XN WHERE X identity XX
- WITH X, XN, VC BEING (Any X, COUNT(V) GROUPBY X,XN WHERE V version_of X, X name XN),
- XX, TC BEING (Any X, COUNT(T) GROUPBY X WHERE T ticket_of X)
-
- instead of:
-
- .. sourcecode:: sql
-
- Any X, VC, TC ORDERBY XN WHERE X identity XX, X name XN,
- WITH X, XN, VC BEING (Any X, COUNT(V) GROUPBY X WHERE V version_of X),
- XX, TC BEING (Any X, COUNT(T) GROUPBY X WHERE T ticket_of X)
-
- which would result in a SQL execution error.
-
-
-Union
-`````
-
-You may get a result set containing the concatenation of several queries using
-the ``UNION``. The selection of each query should have the same number of
-columns.
-
-.. sourcecode:: sql
-
- (Any X, XN WHERE X is Person, X surname XN) UNION (Any X,XN WHERE X is Company, X name XN)
-
-
-.. _RQLFunctions:
-
-Available functions
-~~~~~~~~~~~~~~~~~~~
-
-Below is the list of aggregate and transformation functions that are supported
-nativly by the framework. Notice that cubes may define additional functions.
-
-.. _RQLAggregateFunctions:
-
-Aggregate functions
-```````````````````
-+------------------------+----------------------------------------------------------+
-| ``COUNT(Any)`` | return the number of rows |
-+------------------------+----------------------------------------------------------+
-| ``MIN(Any)`` | return the minimum value |
-+------------------------+----------------------------------------------------------+
-| ``MAX(Any)`` | return the maximum value |
-+------------------------+----------------------------------------------------------+
-| ``AVG(Any)`` | return the average value |
-+------------------------+----------------------------------------------------------+
-| ``SUM(Any)`` | return the sum of values |
-+------------------------+----------------------------------------------------------+
-| ``COMMA_JOIN(String)`` | return each value separated by a comma (for string only) |
-+------------------------+----------------------------------------------------------+
-
-All aggregate functions above take a single argument. Take care some aggregate
-functions (e.g. ``MAX``, ``MIN``) may return `None` if there is no
-result row.
-
-.. _RQLStringFunctions:
-
-String transformation functions
-```````````````````````````````
-
-+-----------------------------------------------+-----------------------------------------------------------------+
-| ``UPPER(String)`` | upper case the string |
-+-----------------------------------------------+-----------------------------------------------------------------+
-| ``LOWER(String)`` | lower case the string |
-+-----------------------------------------------+-----------------------------------------------------------------+
-| ``LENGTH(String)`` | return the length of the string |
-+-----------------------------------------------+-----------------------------------------------------------------+
-| ``SUBSTRING(String, start, length)`` | extract from the string a string starting at given index and of |
-| | given length |
-+-----------------------------------------------+-----------------------------------------------------------------+
-| ``LIMIT_SIZE(String, max size)`` | if the length of the string is greater than given max size, |
-| | strip it and add ellipsis ("..."). The resulting string will |
-| | hence have max size + 3 characters |
-+-----------------------------------------------+-----------------------------------------------------------------+
-| ``TEXT_LIMIT_SIZE(String, format, max size)`` | similar to the above, but allow to specify the MIME type of the |
-| | text contained by the string. Supported formats are text/html, |
-| | text/xhtml and text/xml. All others will be considered as plain |
-| | text. For non plain text format, sgml tags will be first removed|
-| | before limiting the string. |
-+-----------------------------------------------+-----------------------------------------------------------------+
-
-.. _RQLDateFunctions:
-
-Date extraction functions
-`````````````````````````
-
-+----------------------+----------------------------------------+
-| ``YEAR(Date)`` | return the year of a date or datetime |
-+----------------------+----------------------------------------+
-| ``MONTH(Date)`` | return the month of a date or datetime |
-+----------------------+----------------------------------------+
-| ``DAY(Date)`` | return the day of a date or datetime |
-+----------------------+----------------------------------------+
-| ``HOUR(Datetime)`` | return the hours of a datetime |
-+----------------------+----------------------------------------+
-| ``MINUTE(Datetime)`` | return the minutes of a datetime |
-+----------------------+----------------------------------------+
-| ``SECOND(Datetime)`` | return the seconds of a datetime |
-+----------------------+----------------------------------------+
-| ``WEEKDAY(Date)`` | return the day of week of a date or |
-| | datetime. Sunday == 1, Saturday == 7. |
-+----------------------+----------------------------------------+
-
-.. _RQLOtherFunctions:
-
-Other functions
-```````````````
-+-------------------+--------------------------------------------------------------------+
-| ``ABS(num)`` | return the absolute value of a number |
-+-------------------+--------------------------------------------------------------------+
-| ``RANDOM()`` | return a pseudo-random value from 0.0 to 1.0 |
-+-------------------+--------------------------------------------------------------------+
-| ``FSPATH(X)`` | expect X to be an attribute whose value is stored in a |
-| | :class:`BFSStorage` and return its path on the file system |
-+-------------------+--------------------------------------------------------------------+
-| ``FTIRANK(X)`` | expect X to be an entity used in a has_text relation, and return a |
-| | number corresponding to the rank order of each resulting entity |
-+-------------------+--------------------------------------------------------------------+
-| ``CAST(Type, X)`` | expect X to be an attribute and return it casted into the given |
-| | final type |
-+-------------------+--------------------------------------------------------------------+
-
-
-.. _RQLExamples:
-
-Examples
-~~~~~~~~
-
-- *Search for the object of identifier 53*
-
- .. sourcecode:: sql
-
- Any X WHERE X eid 53
-
-- *Search material such as comics, owned by syt and available*
-
- .. sourcecode:: sql
-
- Any X WHERE X is Document,
- X occurence_of F, F class C, C name 'Comics',
- X owned_by U, U login 'syt',
- X available TRUE
-
-- *Looking for people working for eurocopter interested in training*
-
- .. sourcecode:: sql
-
- Any P WHERE P is Person, P work_for S, S name 'Eurocopter',
- P interested_by T, T name 'training'
-
-- *Search note less than 10 days old written by jphc or ocy*
-
- .. sourcecode:: sql
-
- Any N WHERE N is Note, N written_on D, D day> (today -10),
- N written_by P, P name 'jphc' or P name 'ocy'
-
-- *Looking for people interested in training or living in Paris*
-
- .. sourcecode:: sql
-
- Any P WHERE P is Person, EXISTS(P interested_by T, T name 'training') OR
- (P city 'Paris')
-
-- *The surname and firstname of all people*
-
- .. sourcecode:: sql
-
- Any N, P WHERE X is Person, X name N, X firstname P
-
- Note that the selection of several entities generally force
- the use of "Any" because the type specification applies otherwise
- to all the selected variables. We could write here
-
- .. sourcecode:: sql
-
- String N, P WHERE X is Person, X name N, X first_name P
-
-
- Note: You can not specify several types with * ... where X is FirstType or X is SecondType*.
- To specify several types explicitly, you have to do
-
-
- .. sourcecode:: sql
-
- Any X WHERE X is IN (FirstType, SecondType)
-
-
-.. _RQLInsertQuery:
-
-Insertion query
-~~~~~~~~~~~~~~~
-
- `INSERT` <entity type> V1 (, <entity type> V2) \ * `:` <assignments>
- [ `WHERE` <restriction>]
-
-:assignments:
- list of relations to assign in the form `V1 relationship V2 | <static value>`
-
-The restriction can define variables used in assignments.
-
-Caution, if a restriction is specified, the insertion is done for
-*each line result returned by the restriction*.
-
-- *Insert a new person named 'foo'*
-
- .. sourcecode:: sql
-
- INSERT Person X: X name 'foo'
-
-- *Insert a new person named 'foo', another called 'nice' and a 'friend' relation
- between them*
-
- .. sourcecode:: sql
-
- INSERT Person X, Person Y: X name 'foo', Y name 'nice', X friend Y
-
-- *Insert a new person named 'foo' and a 'friend' relation with an existing
- person called 'nice'*
-
- .. sourcecode:: sql
-
- INSERT Person X: X name 'foo', X friend Y WHERE Y name 'nice'
-
-.. _RQLSetQuery:
-
-Update and relation creation queries
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- `SET` <assignements>
- [ `WHERE` <restriction>]
-
-Caution, if a restriction is specified, the update is done *for
-each result line returned by the restriction*.
-
-- *Renaming of the person named 'foo' to 'bar' with the first name changed*
-
- .. sourcecode:: sql
-
- SET X name 'bar', X firstname 'original' WHERE X is Person, X name 'foo'
-
-- *Insert a relation of type 'know' between objects linked by
- the relation of type 'friend'*
-
- .. sourcecode:: sql
-
- SET X know Y WHERE X friend Y
-
-
-.. _RQLDeleteQuery:
-
-Deletion query
-~~~~~~~~~~~~~~
-
- `DELETE` (<entity type> V) | (V1 relation v2 ),...
- [ `WHERE` <restriction>]
-
-Caution, if a restriction is specified, the deletion is made *for
-each line result returned by the restriction*.
-
-- *Deletion of the person named 'foo'*
-
- .. sourcecode:: sql
-
- DELETE Person X WHERE X name 'foo'
-
-- *Removal of all relations of type 'friend' from the person named 'foo'*
-
- .. sourcecode:: sql
-
- DELETE X friend Y WHERE X is Person, X name 'foo'
-
-
-.. _Yapps: http://theory.stanford.edu/~amitp/yapps/
-.. _Left outer join: http://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join
-
--- a/doc/book/en/conf.py Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-# -*- coding: utf-8 -*-
-# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""
-
-"""
-#
-# Cubicweb documentation build configuration file, created by
-# sphinx-quickstart on Fri Oct 31 09:10:36 2008.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# The contents of this file are pickled, so don't put values in the namespace
-# that aren't pickleable (module imports are okay, they're removed automatically).
-#
-# All configuration values have a default value; values that are commented out
-# serve to show the default value.
-
-from os import path as osp
-
-path = __file__
-path = osp.dirname(path) #./doc/book/en
-path = osp.dirname(path) #./doc/book/
-path = osp.dirname(path) #./doc/
-path = osp.dirname(path) #./
-path = osp.join(path,'__pkginfo__.py') #./__pkginfo__.py
-cw = {}
-execfile(path,{},cw)
-
-# If your extensions are in another directory, add it here. If the directory
-# is relative to the documentation root, use os.path.abspath to make it
-# absolute, like shown here.
-#sys.path.append(os.path.abspath('some/directory'))
-
-# General configuration
-# ---------------------
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = [
- 'sphinx.ext.autodoc',
- 'sphinx.ext.viewcode',
- 'logilab.common.sphinx_ext',
- ]
-
-autoclass_content = 'both'
-
-# Add any paths that contain templates here, relative to this directory.
-#templates_path = []
-
-# The suffix of source filenames.
-source_suffix = '.rst'
-
-# The master toctree document.
-master_doc = 'index'
-
-# General substitutions.
-project = 'CubicWeb'
-copyright = '2001-2014, Logilab'
-
-# The default replacements for |version| and |release|, also used in various
-# other places throughout the built documents.
-#
-# The short X.Y version.
-version = '.'.join(str(n) for n in cw['numversion'][:2])
-# The full version, including alpha/beta/rc tags.
-release = cw['version']
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-#today = ''
-# Else, today_fmt is used as the format for a strftime call.
-today_fmt = '%B %d, %Y'
-
-# List of documents that shouldn't be included in the build.
-unused_docs = []
-
-# List of directories, relative to source directories, that shouldn't be searched
-# for source files.
-#exclude_dirs = []
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-#add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-#show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = 'sphinx'
-
-
-# Options for HTML output
-# -----------------------
-
-# The style sheet to use for HTML and HTML Help pages. A file of that name
-# must exist either in Sphinx' static/ path, or in one of the custom paths
-# given in html_static_path.
-#html_style = 'sphinx-default.css'
-
-# The name for this set of Sphinx documents. If None, it defaults to
-# "<project> v<release> documentation".
-html_title = '%s %s' % (project, release)
-
-html_theme_path = ['_themes']
-html_theme = 'cubicweb'
-
-# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
-
-# The name of an image file (within the static path) to place at the top of
-# the sidebar.
-#html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-#html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['.static']
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-#html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-#html_additional_pages = {}
-
-# If false, no module index is generated.
-html_use_modindex = True
-
-# If false, no index is generated.
-#html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-#html_split_index = False
-
-# If true, the reST sources are included in the HTML build as _sources/<name>.
-#html_copy_source = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it. The value of this option must be the
-# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
-
-# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
-html_file_suffix = '.html'
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = 'Cubicwebdoc'
-
-
-# Options for LaTeX output
-# ------------------------
-
-# The paper size ('letter' or 'a4').
-#latex_paper_size = 'letter'
-
-# The font size ('10pt', '11pt' or '12pt').
-#latex_font_size = '10pt'
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, document class [howto/manual]).
-latex_documents = [
- ('index', 'Cubicweb.tex', 'Cubicweb Documentation',
- 'Logilab', 'manual'),
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-#latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-#latex_use_parts = False
-
-# Additional stuff for the LaTeX preamble.
-#latex_preamble = ''
-
-# Documents to append as an appendix to all manuals.
-#latex_appendices = []
-
-# If false, no module index is generated.
-#latex_use_modindex = True
-
-#aafig_format = dict(latex='pdf', html='svg', text=None)
-
-rst_epilog = """
-.. |cubicweb| replace:: *CubicWeb*
-.. |yams| replace:: *Yams*
-.. |rql| replace:: *RQL*
-"""
--- a/doc/book/en/devrepo/cubes/available-cubes.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-.. _AvailableCubes:
-
-Available cubes
----------------
-
-An instance is made of several basic cubes. In the set of available
-basic cubes we can find for example:
-
-Base entity types
-~~~~~~~~~~~~~~~~~
-* addressbook_: PhoneNumber and PostalAddress
-* card_: Card, generic documenting card
-* event_: Event (define events, display them in calendars)
-* file_: File (to allow users to upload and store binary or text files)
-* link_: Link (to collect links to web resources)
-* mailinglist_: MailingList (to reference a mailing-list and the URLs
- for its archives and its admin interface)
-* person_: Person (easily mixed with addressbook)
-* task_: Task (something to be done between start and stop date)
-* zone_: Zone (to define places within larger places, for example a
- city in a state in a country)
-
-
-Classification
-~~~~~~~~~~~~~~
-* folder_: Folder (to organize things by grouping them in folders)
-* keyword_: Keyword (to define classification schemes)
-* tag_: Tag (to tag anything)
-
-Other features
-~~~~~~~~~~~~~~
-* basket_: Basket (like a shopping cart)
-* blog_: a blogging system using Blog and BlogEntry entity types
-* comment_: system to attach comment threads to entities)
-* email_: archiving management for emails (`Email`, `Emailpart`,
- `Emailthread`), trigger action in cubicweb through email
-
-
-
-
-
-.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook
-.. _basket: http://www.cubicweb.org/project/cubicweb-basket
-.. _card: http://www.cubicweb.org/project/cubicweb-card
-.. _blog: http://www.cubicweb.org/project/cubicweb-blog
-.. _comment: http://www.cubicweb.org/project/cubicweb-comment
-.. _email: http://www.cubicweb.org/project/cubicweb-email
-.. _event: http://www.cubicweb.org/project/cubicweb-event
-.. _file: http://www.cubicweb.org/project/cubicweb-file
-.. _folder: http://www.cubicweb.org/project/cubicweb-folder
-.. _keyword: http://www.cubicweb.org/project/cubicweb-keyword
-.. _link: http://www.cubicweb.org/project/cubicweb-link
-.. _mailinglist: http://www.cubicweb.org/project/cubicweb-mailinglist
-.. _person: http://www.cubicweb.org/project/cubicweb-person
-.. _tag: http://www.cubicweb.org/project/cubicweb-tag
-.. _task: http://www.cubicweb.org/project/cubicweb-task
-.. _zone: http://www.cubicweb.org/project/cubicweb-zone
-
-To declare the use of a cube, once installed, add the name of the cube
-and its dependency relation in the `__depends_cubes__` dictionary
-defined in the file `__pkginfo__.py` of your own component.
-
-.. note::
- The listed cubes above are available as debian-packages on `CubicWeb's forge`_.
-
-.. _`CubicWeb's forge`: http://www.cubicweb.org/project?vtitle=All%20cubicweb%20projects
--- a/doc/book/en/devrepo/cubes/cc-newcube.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-Creating a new cube from scratch
---------------------------------
-
-Let's start by creating the cube environment in which we will develop ::
-
- cd ~/cubes
- # use cubicweb-ctl to generate a template for the cube
- # will ask some questions, most with nice default
- cubicweb-ctl newcube mycube
- # makes the cube source code managed by mercurial
- cd mycube
- hg init
- hg add .
- hg ci
-
-If all went well, you should see the cube you just created in the list
-returned by ``cubicweb-ctl list`` in the *Available cubes* section.
-If not, please refer to :ref:`ConfigurationEnv`.
-
-To reuse an existing cube, add it to the list named
-``__depends_cubes__`` which is defined in :file:`__pkginfo__.py`.
-This variable is used for the instance packaging (dependencies handled
-by system utility tools such as APT) and to find used cubes when the
-database for the instance is created (import_erschema('MyCube') will
-not properly work otherwise).
-
-On a Unix system, the available cubes are usually stored in the
-directory :file:`/usr/share/cubicweb/cubes`. If you are using the
-cubicweb mercurial repository (:ref:`SourceInstallation`), the cubes
-are searched in the directory
-:file:`/path/to/cubicweb_toplevel/cubes`. In this configuration
-cubicweb itself ought to be located at
-:file:`/path/to/cubicweb_toplevel/cubicweb`.
-
-.. note::
-
- Please note that if you do not wish to use default directory for your cubes
- library, you should set the :envvar:`CW_CUBES_PATH` environment variable to
- add extra directories where cubes will be search, and you'll then have to use
- the option `--directory` to specify where you would like to place the source
- code of your cube:
-
- ``cubicweb-ctl newcube --directory=/path/to/cubes/library mycube``
-
-
-.. XXX resurrect once live-server is back
-.. Usage of :command:`cubicweb-ctl liveserver`
-.. -------------------------------------------
-
-.. To quickly test a new cube, you can also use the `liveserver` command for cubicweb-ctl
-.. which allows to create an instance in memory (using an SQLite database by
-.. default) and make it accessible through a web server ::
-
-.. cubicweb-ctl live-server mycube
-
-.. or by using an existing database (SQLite or Postgres)::
-
-.. cubicweb-ctl live-server -s myfile_sources mycube
--- a/doc/book/en/devrepo/cubes/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-Cubes
-=====
-
-This chapter describes how to define your own cubes and reuse already available cubes.
-
-.. toctree::
- :maxdepth: 1
-
- layout.rst
- cc-newcube.rst
- available-cubes.rst
--- a/doc/book/en/devrepo/cubes/layout.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-
-.. _foundationsCube:
-
-.. _cubelayout:
-
-Standard structure for a cube
------------------------------
-
-A cube is structured as follows:
-
-::
-
- mycube/
- |
- |-- data/
- | |-- cubes.mycube.css
- | |-- cubes.mycube.js
- | `-- external_resources
- |
- |-- debian/
- | |-- changelog
- | |-- compat
- | |-- control
- | |-- copyright
- | |-- cubicweb-mycube.prerm
- | `-- rules
- |
- |-- entities.py
- |
- |-- i18n/
- | |-- en.po
- | |-- es.po
- | `-- fr.po
- |
- |-- __init__.py
- |
- |-- MANIFEST.in
- |
- |-- migration/
- | |-- postcreate.py
- | `-- precreate.py
- |
- |-- __pkginfo__.py
- |
- |-- schema.py
- |
- |-- setup.py
- |
- |-- site_cubicweb.py
- |
- |-- hooks.py
- |
- |-- test/
- | |-- data/
- | | `-- bootstrap_cubes
- | |-- pytestconf.py
- | |-- realdb_test_mycube.py
- | `-- test_mycube.py
- |
- `-- views.py
-
-
-We can use subpackages instead of python modules for ``views.py``, ``entities.py``,
-``schema.py`` or ``hooks.py``. For example, we could have:
-
-::
-
- mycube/
- |
- |-- entities.py
- |-- hooks.py
- `-- views/
- |-- __init__.py
- |-- forms.py
- |-- primary.py
- `-- widgets.py
-
-
-where :
-
-* ``schema`` contains the schema definition (server side only)
-* ``entities`` contains the entity definitions (server side and web interface)
-* ``hooks`` contains hooks and/or views notifications (server side only)
-* ``views`` contains the web interface components (web interface only)
-* ``test`` contains tests related to the cube (not installed)
-* ``i18n`` contains message catalogs for supported languages (server side and
- web interface)
-* ``data`` contains data files for static content (images, css,
- javascript code)...(web interface only)
-* ``migration`` contains initialization files for new instances (``postcreate.py``)
- and a file containing dependencies of the component depending on the version
- (``depends.map``)
-* ``debian`` contains all the files managing debian packaging (you will find
- the usual files ``control``, ``rules``, ``changelog``... not installed)
-* file ``__pkginfo__.py`` provides component meta-data, especially the distribution
- and the current version (server side and web interface) or sub-cubes used by
- the cube.
-
-
-At least you should have the file ``__pkginfo__.py``.
-
-
-The :file:`__init__.py` and :file:`site_cubicweb.py` files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. XXX WRITEME
-
-The :file:`__pkginfo__.py` file
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It contains metadata describing your cube, mostly useful for packaging.
-
-Two important attributes of this module are __depends__ and __recommends__
-dictionaries that indicates what should be installed (and each version if
-necessary) for the cube to work.
-
-Dependency on other cubes are expected to be of the form 'cubicweb-<cubename>'.
-
-When an instance is created, dependencies are automatically installed, while
-recommends are not.
-
-Recommends may be seen as a kind of 'weak dependency'. Eg, the most important
-effect of recommending a cube is that, if cube A recommends cube B, the cube B
-will be loaded before the cube A (same thing happend when A depends on B).
-
-Having this behaviour is sometime desired: on schema creation, you may rely on
-something defined in the other's schema; on database creation, on something
-created by the other's postcreate, and so on.
-
-
-:file:`migration/precreate.py` and :file:`migration/postcreate.py`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. XXX detail steps of instance creation
-
-
-External resources such as image, javascript and css files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. XXX naming convention external_resources file
-
-
-Out-of the box testing
-~~~~~~~~~~~~~~~~~~~~~~
-
-.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
-
-
-Packaging and distribution
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. XXX MANIFEST.in, __pkginfo__.include_dirs, debian
-
--- a/doc/book/en/devrepo/dataimport.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _dataimport:
-
-Dataimport
-==========
-
-*CubicWeb* is designed to manipulate huge of amount of data, and provides utilities to do so.
-
-The main entry point is :mod:`cubicweb.dataimport.importer` which defines an
-:class:`ExtEntitiesImporter` class responsible for importing data from an external source in the
-form :class:`ExtEntity` objects. An :class:`ExtEntity` is a transitional representation of an
-entity to be imported in the CubicWeb instance; building this representation is usually
-domain-specific -- e.g. dependent of the kind of data source (RDF, CSV, etc.) -- and is thus the
-responsibility of the end-user.
-
-Along with the importer, a *store* must be selected, which is responsible for insertion of data into
-the database. There exists different kind of stores_, allowing to insert data within different
-levels of the *CubicWeb* API and with different speed/security tradeoffs. Those keeping all the
-*CubicWeb* hooks and security will be slower but the possible errors in insertion (bad data types,
-integrity error, ...) will be handled.
-
-
-Example
--------
-
-Consider the following schema snippet.
-
-.. code-block:: python
-
- class Person(EntityType):
- name = String(required=True)
-
- class knows(RelationDefinition):
- subject = 'Person'
- object = 'Person'
-
-along with some data in a ``people.csv`` file::
-
- # uri,name,knows
- http://www.example.org/alice,Alice,
- http://www.example.org/bob,Bob,http://www.example.org/alice
-
-The following code (using a shell context) defines a function `extentities_from_csv` to read
-`Person` external entities coming from a CSV file and calls the :class:`ExtEntitiesImporter` to
-insert corresponding entities and relations into the CubicWeb instance.
-
-.. code-block:: python
-
- from cubicweb.dataimport import ucsvreader, RQLObjectStore
- from cubicweb.dataimport.importer import ExtEntity, ExtEntitiesImporter
-
- def extentities_from_csv(fpath):
- """Yield Person ExtEntities read from `fpath` CSV file."""
- with open(fpath) as f:
- for uri, name, knows in ucsvreader(f, skipfirst=True, skip_empty=False):
- yield ExtEntity('Personne', uri,
- {'nom': set([name]), 'connait': set([knows])})
-
- extenties = extentities_from_csv('people.csv')
- store = RQLObjectStore(cnx)
- importer = ExtEntitiesImporter(schema, store)
- importer.import_entities(extenties)
- commit()
- rset = cnx.execute('String N WHERE X nom N, X connait Y, Y nom "Alice"')
- assert rset[0][0] == u'Bob', rset
-
-Importer API
-------------
-
-.. automodule:: cubicweb.dataimport.importer
-
-
-Stores
-~~~~~~
-
-Stores are responsible to insert properly formatted entities and relations into the database. They
-have the following API::
-
- >>> user_eid = store.prepare_insert_entity('CWUser', login=u'johndoe')
- >>> group_eid = store.prepare_insert_entity('CWUser', name=u'unknown')
- >>> store.relate(user_eid, 'in_group', group_eid)
- >>> store.flush()
- >>> store.commit()
- >>> store.finish()
-
-Some stores **require a flush** to copy data in the database, so if you want to have store
-independent code you should explicitly call it. (There may be multiple flushes during the
-process, or only one at the end if there is no memory issue). This is different from the
-commit which validates the database transaction. At last, the `finish()` method should be called in
-case the store requires additional work once everything is done.
-
-* ``prepare_insert_entity(<entity type>, **kwargs) -> eid``: given an entity
- type, attributes and inlined relations, return the eid of the entity to be
- inserted, *with no guarantee that anything has been inserted in database*.
-
-* ``prepare_update_entity(<entity type>, eid, **kwargs) -> None``: given an
- entity type and eid, promise for update given attributes and inlined
- relations *with no guarantee that anything has been inserted in database*.
-
-* ``prepare_insert_relation(eid_from, rtype, eid_to) -> None``: indicate that a
- relation ``rtype`` should be added between entities with eids ``eid_from``
- and ``eid_to``. Similar to ``prepare_insert_entity()``, *there is no
- guarantee that the relation has been inserted in database*.
-
-* ``flush() -> None``: flush any temporary data to database. May be called
- several times during an import.
-
-* ``commit() -> None``: commit the database transaction.
-
-* ``finish() -> None``: additional stuff to do after import is terminated.
-
-ObjectStore
------------
-
-This store keeps objects in memory for *faster* validation. It may be useful in development
-mode. However, as it will not enforce the constraints of the schema nor insert anything in the
-database, so it may miss some problems.
-
-
-RQLObjectStore
---------------
-
-This store works with an actual RQL repository, and it may be used in production mode.
-
-
-NoHookRQLObjectStore
---------------------
-
-This store works similarly to the *RQLObjectStore* but bypasses some *CubicWeb* hooks to be faster.
-
-
-SQLGenObjectStore
------------------
-
-This store relies on *COPY FROM*/execute many sql commands to directly push data using SQL commands
-rather than using the whole *CubicWeb* API. For now, **it only works with PostgresSQL** as it requires
-the *COPY FROM* command.
--- a/doc/book/en/devrepo/datamodel/baseschema.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-.. _pre_defined_entity_types:
-
-Pre-defined entities in the library
------------------------------------
-
-The library defines a set of entity schemas that are required by the system
-or commonly used in *CubicWeb* instances.
-
-
-Entity types used to store the schema
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`CWEType`, entity type
-* _`CWRType`, relation type
-* _`CWRelation`, relation definition
-* _`CWAttribute`, attribute relation definition
-* _`CWConstraint`, `CWConstraintType`, `RQLExpression`
-
-Entity types used to manage users and permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* _`CWUser`, system users
-* _`CWGroup`, users groups
-
-Entity types used to manage workflows
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* :ref:`Workflow <Workflow>`, workflow entity, linked to some entity types which may use this workflow
-* _`State`, workflow state
-* _`Transition`, workflow transition
-* _`TrInfo`, record of a transition trafic for an entity
-
-Other entity types
-~~~~~~~~~~~~~~~~~~
-* _`CWCache`, cache entities used to improve performances
-* _`CWProperty`, used to configure the instance
-
-* _`EmailAddress`, email address, used by the system to send notifications
- to the users and also used by others optionnals schemas
-
-* _`Bookmark`, an entity type used to allow a user to customize his links within
- the instance
-
-* _`ExternalUri`, used for semantic web site to indicate that an entity is the
- same as another from an external site
--- a/doc/book/en/devrepo/datamodel/define-workflows.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Workflow:
-
-Defining a Workflow
-===================
-
-General
--------
-
-A workflow describes how certain entities have to evolve between different
-states. Hence we have a set of states, and a "transition graph", i.e. a set of
-possible transitions from one state to another state.
-
-We will define a simple workflow for a blog, with only the following two states:
-`submitted` and `published`. You may want to take a look at :ref:`TutosBase` if
-you want to quickly setup an instance running a blog.
-
-Setting up a workflow
----------------------
-
-We want to create a workflow to control the quality of the BlogEntry
-submitted on the instance. When a BlogEntry is created by a user
-its state should be `submitted`. To be visible to all, it has to
-be in the state `published`. To move it from `submitted` to `published`,
-we need a transition that we can call `approve_blogentry`.
-
-A BlogEntry state should not be modifiable by every user.
-So we have to define a group of users, `moderators`, and
-this group will have appropriate permissions to publish a BlogEntry.
-
-There are two ways to create a workflow: from the user interface, or
-by defining it in ``migration/postcreate.py``. This script is executed
-each time a new ``cubicweb-ctl db-init`` is done. We strongly
-recommend to create the workflow in ``migration/postcreate.py`` and we
-will now show you how. Read `Two bits of warning`_ to understand why.
-
-The state of an entity is managed by the `in_state` attribute which
-can be added to your entity schema by inheriting from
-`cubicweb.schema.WorkflowableEntityType`.
-
-
-About our example of BlogEntry, we must have:
-
-.. sourcecode:: python
-
- from cubicweb.schema import WorkflowableEntityType
-
- class BlogEntry(WorkflowableEntityType):
- ...
-
-
-Creating states, transitions and group permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :mod:`postcreate` script is executed in a special environment,
-adding several |cubicweb| primitives that can be used.
-
-They are all defined in the :class:`ServerMigrationHelper` class.
-We will only discuss the methods we use to create a workflow in this example.
-
-A workflow is a collection of entities of type ``State`` and of type
-``Transition`` which are standard *CubicWeb* entity types.
-
-To define a workflow for BlogDemo, please add the following lines
-to ``migration/postcreate.py``:
-
-.. sourcecode:: python
-
- _ = unicode
-
- moderators = add_entity('CWGroup', name=u"moderators")
-
-This adds the `moderators` user group.
-
-.. sourcecode:: python
-
- wf = add_workflow(u'blog publication workflow', 'BlogEntry')
-
-At first, instanciate a new workflow object with a gentle description
-and the concerned entity types (this one can be a tuple for multiple
-value).
-
-.. sourcecode:: python
-
- submitted = wf.add_state(_('submitted'), initial=True)
- published = wf.add_state(_('published'))
-
-This will create two entities of type ``State``, one with name
-'submitted', and the other with name 'published'.
-
-``add_state`` expects as first argument the name of the state you want
-to create and an optional argument to say if it is supposed to be the
-initial state of the entity type.
-
-.. sourcecode:: python
-
- wf.add_transition(_('approve_blogentry'), (submitted,), published, ('moderators', 'managers'),)
-
-This will create an entity of type ``Transition`` with name
-`approve_blogentry` which will be linked to the ``State`` entities
-created before.
-
-``add_transition`` expects
-
- * as the first argument: the name of the transition
- * then the list of states on which the transition can be triggered,
- * the target state of the transition,
- * and the permissions
- (e.g. a list of user groups who can apply the transition; the user
- has to belong to at least one of the listed group to perform the action).
-
-.. sourcecode:: python
-
- checkpoint()
-
-.. note::
- Do not forget to add the `_()` in front of all states and
- transitions names while creating a workflow so that they will be
- identified by the i18n catalog scripts.
-
-In addition to the user groups (one of which the user needs to belong
-to), we could have added a RQL condition. In this case, the user can
-only perform the action if the two conditions are satisfied.
-
-If we use an RQL condition on a transition, we can use the following variables:
-
-* `X`, the entity on which we may pass the transition
-* `U`, the user executing that may pass the transition
-
-
-.. image:: ../../images/03-transitions-view_en.png
-
-You can notice that in the action box of a BlogEntry, the state is now
-listed as well as the possible transitions for the current state
-defined by the workflow.
-
-The transitions will only be displayed for users having the right permissions.
-In our example, the transition `approve_blogentry` will only be displayed
-for the users belonging to the group `moderators` or `managers`.
-
-
-Two bits of warning
-~~~~~~~~~~~~~~~~~~~
-
-We could perfectly use the administration interface to do these
-operations. It is a convenient thing to do at times (when doing
-development, to quick-check things). But it is not recommended beyond
-that because it is a bit complicated to do it right and it will be
-only local to your instance (or, said a bit differently, such a
-workflow only exists in an instance database). Furthermore, you cannot
-write unit tests against deployed instances, and experience shows it
-is mandatory to have tests for any mildly complicated workflow
-setup.
-
-Indeed, if you create the states and transitions through the user
-interface, next time you initialize the database you will have to
-re-create all the workflow entities. The user interface should only be
-a reference for you to view the states and transitions, but is not the
-appropriate interface to define your application workflow.
--- a/doc/book/en/devrepo/datamodel/definition.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,912 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _datamodel_definition:
-
-Yams *schema*
--------------
-
-The **schema** is the core piece of a *CubicWeb* instance as it
-defines and handles the data model. It is based on entity types that
-are either already defined in `Yams`_ and the *CubicWeb* standard
-library; or more specific types defined in cubes. The schema for a
-cube is defined in a `schema` python module or package.
-
-.. _`Yams`: http://www.logilab.org/project/yams
-
-.. _datamodel_overview:
-
-Overview
-~~~~~~~~
-
-The core idea of the yams schema is not far from the classical
-`Entity-relationship`_ model. But while an E/R model (or `logical
-model`) traditionally has to be manually translated to a lower-level
-data description language (such as the SQL `create table`
-sublanguage), also often described as the `physical model`, no such
-step is required with |yams| and |cubicweb|.
-
-.. _`Entity-relationship`: http://en.wikipedia.org/wiki/Entity-relationship_model
-
-This is because in addition to high-level, logical |yams| models, one
-uses the |rql| data manipulation language to query, insert, update and
-delete data. |rql| abstracts as much of the underlying SQL database as
-a |yams| schema abstracts from the physical layout. The vagaries of
-SQL are avoided.
-
-As a bonus point, such abstraction make it quite comfortable to build
-or use different backends to which |rql| queries apply.
-
-So, as in the E/R formalism, the building blocks are ``entities``
-(:ref:`EntityType`), ``relationships`` (:ref:`RelationType`,
-:ref:`RelationDefinition`) and ``attributes`` (handled like relation
-with |yams|).
-
-Let us detail a little the divergences between E/R and |yams|:
-
-* all relationship are binary which means that to represent a
- non-binary relationship, one has to use an entity,
-* relationships do not support attributes (yet, see:
- http://www.cubicweb.org/ticket/341318), hence the need to reify it
- as an entity if need arises,
-* all entities have an `eid` attribute (an integer) that is its
- primary key (but it is possible to declare uniqueness on other
- attributes)
-
-Also |yams| supports the notions of:
-
-* entity inheritance (quite experimental yet, and completely
- undocumented),
-* relation type: that is, relationships can be established over a set
- of couple of entity types (henre the distinction made between
- `RelationType` and `RelationDefinition` below)
-
-Finally |yams| has a few concepts of its own:
-
-* relationships being oriented and binary, we call the left hand
- entity type the `subject` and the right hand entity type the
- `object`
-
-.. note::
-
- The |yams| schema is available at run time through the .schema
- attribute of the `vregistry`. It's an instance of
- :class:`cubicweb.schema.Schema`, which extends
- :class:`yams.schema.Schema`.
-
-.. _EntityType:
-
-Entity type
-~~~~~~~~~~~
-
-An entity type is an instance of :class:`yams.schema.EntitySchema`. Each entity type has
-a set of attributes and relations, and some permissions which define who can add, read,
-update or delete entities of this type.
-
-The following built-in types are available: ``String``,
-``Int``, ``BigInt``, ``Float``, ``Decimal``, ``Boolean``,
-``Date``, ``Datetime``, ``Time``, ``Interval``, ``Byte`` and
-``Password``. They can only be used as attributes of an other entity
-type.
-
-There is also a `RichString` kindof type:
-
- .. autoclass:: yams.buildobjs.RichString
-
-The ``__unique_together__`` class attribute is a list of tuples of names of
-attributes or inlined relations. For each tuple, CubicWeb ensures the unicity
-of the combination. For example:
-
-.. sourcecode:: python
-
- class State(EntityType):
- __unique_together__ = [('name', 'state_of')]
-
- name = String(required=True)
- state_of = SubjectRelation('Workflow', cardinality='1*',
- composite='object', inlined=True)
-
-
-You can find more base entity types in
-:ref:`pre_defined_entity_types`.
-
-.. XXX yams inheritance
-
-.. _RelationType:
-
-Relation type
-~~~~~~~~~~~~~
-
-A relation type is an instance of
-:class:`yams.schema.RelationSchema`. A relation type is simply a
-semantic definition of a kind of relationship that may occur in an
-application.
-
-It may be referenced by zero, one or more relation definitions.
-
-It is important to choose a good name, at least to avoid conflicts
-with some semantically different relation defined in other cubes
-(since there's only a shared name space for these names).
-
-A relation type holds the following properties (which are hence shared
-between all relation definitions of that type):
-
-* `inlined`: boolean handling the physical optimization for archiving
- the relation in the subject entity table, instead of creating a specific
- table for the relation. This applies to relations where cardinality
- of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
- definitions.
-
-* `symmetric`: boolean indicating that the relation is symmetrical, which
- means that `X relation Y` implies `Y relation X`.
-
-.. _RelationDefinition:
-
-Relation definition
-~~~~~~~~~~~~~~~~~~~
-
-A relation definition is an instance of
-:class:`yams.schema.RelationDefinition`. It is a complete triplet
-"<subject entity type> <relation type> <object entity type>".
-
-When creating a new instance of that class, the corresponding
-:class:`RelationType` instance is created on the fly if necessary.
-
-Properties
-``````````
-
-The available properties for relation definitions are enumerated
-here. There are several kind of properties, as some relation
-definitions are actually attribute definitions, and other are not.
-
-Some properties may be completely optional, other may have a default
-value.
-
-Common properties for attributes and relations:
-
-* `description`: a unicode string describing an attribute or a
- relation. By default this string will be used in the editing form of
- the entity, which means that it is supposed to help the end-user and
- should be flagged by the function `_` to be properly
- internationalized.
-
-* `constraints`: a list of conditions/constraints that the relation has to
- satisfy (c.f. `Constraints`_)
-
-* `cardinality`: a two character string specifying the cardinality of
- the relation. The first character defines the cardinality of the
- relation on the subject, and the second on the object. When a
- relation can have multiple subjects or objects, the cardinality
- applies to all, not on a one-to-one basis (so it must be
- consistent...). Default value is '**'. The possible values are
- inspired from regular expression syntax:
-
- * `1`: 1..1
- * `?`: 0..1
- * `+`: 1..n
- * `*`: 0..n
-
-Attributes properties:
-
-* `unique`: boolean indicating if the value of the attribute has to be
- unique or not within all entities of the same type (false by
- default)
-
-* `indexed`: boolean indicating if an index needs to be created for
- this attribute in the database (false by default). This is useful
- only if you know that you will have to run numerous searches on the
- value of this attribute.
-
-* `default`: default value of the attribute. In case of date types, the values
- which could be used correspond to the RQL keywords `TODAY` and `NOW`.
-
-* `metadata`: Is also accepted as an argument of the attribute contructor. It is
- not really an attribute property. see `Metadata`_ for details.
-
-Properties for `String` attributes:
-
-* `fulltextindexed`: boolean indicating if the attribute is part of
- the full text index (false by default) (*applicable on the type
- `Byte` as well*)
-
-* `internationalizable`: boolean indicating if the value of the
- attribute is internationalizable (false by default)
-
-Relation properties:
-
-* `composite`: string indicating that the subject (composite ==
- 'subject') is composed of the objects of the relations. For the
- opposite case (when the object is composed of the subjects of the
- relation), we just set 'object' as value. The composition implies
- that when the relation is deleted (so when the composite is deleted,
- at least), the composed are also deleted.
-
-* `fulltext_container`: string indicating if the value if the full
- text indexation of the entity on one end of the relation should be
- used to find the entity on the other end. The possible values are
- 'subject' or 'object'. For instance the use_email relation has that
- property set to 'subject', since when performing a full text search
- people want to find the entity using an email address, and not the
- entity representing the email address.
-
-Constraints
-```````````
-
-By default, the available constraint types are:
-
-General Constraints
-......................
-
-* `SizeConstraint`: allows to specify a minimum and/or maximum size on
- string (generic case of `maxsize`)
-
-* `BoundaryConstraint`: allows to specify a minimum and/or maximum value
- on numeric types and date
-
-.. sourcecode:: python
-
- from yams.constraints import BoundaryConstraint, TODAY, NOW, Attribute
-
- class DatedEntity(EntityType):
- start = Date(constraints=[BoundaryConstraint('>=', TODAY())])
- end = Date(constraints=[BoundaryConstraint('>=', Attribute('start'))])
-
- class Before(EntityType);
- last_time = DateTime(constraints=[BoundaryConstraint('<=', NOW())])
-
-* `IntervalBoundConstraint`: allows to specify an interval with
- included values
-
-.. sourcecode:: python
-
- class Node(EntityType):
- latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
-
-* `UniqueConstraint`: identical to "unique=True"
-
-* `StaticVocabularyConstraint`: identical to "vocabulary=(...)"
-
-Constraints can be dependent on a fixed value (90, Date(2015,3,23)) or a variable.
-In this second case, yams can handle :
-
-* `Attribute`: compare to the value of another attribute.
-* `TODAY`: compare to the current Date.
-* `NOW`: compare to the current Datetime.
-
-RQL Based Constraints
-......................
-
-RQL based constraints may take three arguments. The first one is the ``WHERE``
-clause of a RQL query used by the constraint. The second argument ``mainvars``
-is the ``Any`` clause of the query. By default this include `S` reserved for the
-subject of the relation and `O` for the object. Additional variables could be
-specified using ``mainvars``. The argument expects a single string with all
-variable's name separated by spaces. The last one, ``msg``, is the error message
-displayed when the constraint fails. As RQLVocabularyConstraint never fails the
-third argument is not available.
-
-* `RQLConstraint`: allows to specify a RQL query that has to be satisfied
- by the subject and/or the object of relation. In this query the variables
- `S` and `O` are reserved for the relation subject and object entities.
-
-* `RQLVocabularyConstraint`: similar to the previous type of constraint except
- that it does not express a "strong" constraint, which means it is only used to
- restrict the values listed in the drop-down menu of editing form, but it does
- not prevent another entity to be selected.
-
-* `RQLUniqueConstraint`: allows to the specify a RQL query that ensure that an
- attribute is unique in a specific context. The Query must **never** return more
- than a single result to be satisfied. In this query the variables `S` is
- reserved for the relation subject entity. The other variables should be
- specified with the second constructor argument (mainvars). This constraint type
- should be used when __unique_together__ doesn't fit.
-
-.. XXX note about how to add new constraint
-
-.. _securitymodel:
-
-The security model
-~~~~~~~~~~~~~~~~~~
-
-The security model of `CubicWeb` is based on `Access Control List`.
-The main principles are:
-
-* users and groups of users
-* a user belongs to at least one group of user
-* permissions (`read`, `update`, `create`, `delete`)
-* permissions are assigned to groups (and not to users)
-
-For *CubicWeb* in particular:
-
-* we associate rights at the entities/relations schema level
-
-* the default groups are: `managers`, `users` and `guests`
-
-* users belong to the `users` group
-
-* there is a virtual group called `owners` to which we can associate only
- `delete` and `update` permissions
-
- * we can not add users to the `owners` group, they are implicitly added to it
- according to the context of the objects they own
-
- * the permissions of this group are only checked on `update`/`delete` actions
- if all the other groups the user belongs to do not provide those permissions
-
-Setting permissions is done with the class attribute `__permissions__`
-of entity types and relation definitions. The value of this attribute
-is a dictionary where the keys are the access types (action), and the
-values are the authorized groups or rql expressions.
-
-For an entity type, the possible actions are `read`, `add`, `update` and
-`delete`.
-
-For a relation, the possible actions are `read`, `add`, and `delete`.
-
-For an attribute, the possible actions are `read`, `add` and `update`,
-and they are a refinement of an entity type permission.
-
-.. note::
-
- By default, the permissions of an entity type attributes are
- equivalent to the permissions of the entity type itself.
-
- It is possible to provide custom attribute permissions which are
- stronger than, or are more lenient than the entity type
- permissions.
-
- In a situation where all attributes were given custom permissions,
- the entity type permissions would not be checked, except for the
- `delete` action.
-
-For each access type, a tuple indicates the name of the authorized groups and/or
-one or multiple RQL expressions to satisfy to grant access. The access is
-provided if the user is in one of the listed groups or if one of the RQL condition
-is satisfied.
-
-Default permissions
-```````````````````
-
-The default permissions for ``EntityType`` are:
-
-.. sourcecode:: python
-
- __permissions__ = {
- 'read': ('managers', 'users', 'guests',),
- 'update': ('managers', 'owners',),
- 'delete': ('managers', 'owners'),
- 'add': ('managers', 'users',)
- }
-
-The default permissions for relations are:
-
-.. sourcecode:: python
-
- __permissions__ = {'read': ('managers', 'users', 'guests',),
- 'delete': ('managers', 'users'),
- 'add': ('managers', 'users',)}
-
-The default permissions for attributes are:
-
-.. sourcecode:: python
-
- __permissions__ = {'read': ('managers', 'users', 'guests',),
- 'add': ('managers', ERQLExpression('U has_add_permission X'),
- 'update': ('managers', ERQLExpression('U has_update_permission X')),}
-
-.. note::
-
- The default permissions for attributes are not syntactically
- equivalent to the default permissions of the entity types, but the
- rql expressions work by delegating to the entity type permissions.
-
-
-The standard user groups
-````````````````````````
-
-* `guests`
-
-* `users`
-
-* `managers`
-
-* `owners`: virtual group corresponding to the entity's owner.
- This can only be used for the actions `update` and `delete` of an entity
- type.
-
-It is also possible to use specific groups if they are defined in the precreate
-script of the cube (``migration/precreate.py``). Defining groups in postcreate
-script or later makes them unavailable for security purposes (in this case, an
-`sync_schema_props_perms` command has to be issued in a CubicWeb shell).
-
-
-Use of RQL expression for write permissions
-```````````````````````````````````````````
-
-It is possible to define RQL expression to provide update permission (`add`,
-`delete` and `update`) on entity type / relation definitions. An rql expression
-is a piece of query (corresponds to the WHERE statement of an RQL query), and the
-expression will be considered as satisfied if it returns some results. They can
-not be used in `read` permission.
-
-To use RQL expression in entity type permission:
-
-* you have to use the class :class:`~cubicweb.schema.ERQLExpression`
-
-* 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
-
-For RQL expressions on a relation type, the principles are the same except for
-the following:
-
-* you have to use the class :class:`~cubicweb.schema.RRQLExpression` instead of
- :class:`~cubicweb.schema.ERQLExpression`
-
-* 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
-
-To define security for attributes of an entity (non-final relation), you have to
-use the class :class:`~cubicweb.schema.ERQLExpression` in which `X` represents
-the entity the attribute belongs to.
-
-It is possible to use in those expression a special relation
-`has_<ACTION>_permission` where the subject is the user (eg 'U') and the object
-is any variable representing an entity (usually 'X' in
-:class:`~cubicweb.schema.ERQLExpression`, 'S' or 'O' in
-:class:`~cubicweb.schema.RRQLExpression`), meaning that the user needs to have
-permission to execute the action <ACTION> on the entities represented by this
-variable. It's recommanded to use this feature whenever possible since it
-simplify greatly complex security definition and upgrade.
-
-
-.. sourcecode:: python
-
- class my_relation(RelationDefinition):
- __permissions__ = {'read': ('managers', 'users'),
- 'add': ('managers', RRQLExpression('U has_update_permission S')),
- 'delete': ('managers', RRQLExpression('U has_update_permission S'))
- }
-
-In the above example, user will be allowed to add/delete `my_relation` if he has
-the `update` permission on the subject of the relation.
-
-.. note::
-
- Potentially, the `use of an RQL expression to add an entity or a relation` can
- cause problems for the user interface, because if the expression uses the
- entity or the relation to create, we are not able to verify the permissions
- before we actually added the entity (please note that this is not a problem for
- the RQL server at all, because the permissions checks are done after the
- creation). In such case, the permission check methods
- (CubicWebEntitySchema.check_perm and has_perm) can indicate that the user is
- not allowed to create this entity while it would obtain the permission. To
- compensate this problem, it is usually necessary in such case to use an action
- that reflects the schema permissions but which check properly the permissions
- so that it would show up only if possible.
-
-
-Use of RQL expression for reading rights
-````````````````````````````````````````
-
-The principles are the same but with the following restrictions:
-
-* you can not use rql expression for the `read` permission of relations and
- attributes,
-
-* you can not use special `has_<ACTION>_permission` relation in the rql
- expression.
-
-
-Important notes about write permissions checking
-````````````````````````````````````````````````
-
-Write permissions (e.g. 'add', 'update', 'delete') are checked in core hooks.
-
-When a permission is checked slightly vary according to if it's an entity or
-relation, and if the relation is an attribute relation or not). It's important to
-understand that since according to when a permission is checked, values returned
-by rql expressions may changes, hence the permission being granted or not.
-
-Here are the current rules:
-
-1. permission to add/update entity and its attributes are checked on
- commit
-
-2. permission to delete an entity is checked in 'before_delete_entity' hook
-
-3. permission to add a relation is checked either:
-
- - in 'before_add_relation' hook if the relation type is in the
- `BEFORE_ADD_RELATIONS` set
-
- - else at commit time if the relation type is in the `ON_COMMIT_ADD_RELATIONS`
- set
-
- - else in 'after_add_relation' hook (the default)
-
-4. permission to delete a relation is checked in 'before_delete_relation' hook
-
-Last but not least, remember queries issued from hooks and operation are by
-default 'unsafe', eg there are no read or write security checks.
-
-See :mod:`cubicweb.hooks.security` for more details.
-
-
-.. _yams_example:
-
-
-Derived attributes and relations
---------------------------------
-
-.. note:: **TODO** Check organisation of the whole chapter of the documentation
-
-Cubicweb offers the possibility to *query* data using so called
-*computed* relations and attributes. Those are *seen* by RQL requests
-as normal attributes and relations but are actually derived from other
-attributes and relations. In a first section we'll informally review
-two typical use cases. Then we see how to use computed attributes and
-relations in your schema. Last we will consider various significant
-aspects of their implementation and the impact on their usage.
-
-Motivating use cases
-~~~~~~~~~~~~~~~~~~~~
-
-Computed (or reified) relations
-```````````````````````````````
-
-It often arises that one must represent a ternary relation, or a
-family of relations. For example, in the context of an exhibition
-catalog you might want to link all *contributors* to the *work* they
-contributed to, but this contribution can be as *illustrator*,
-*author*, *performer*, ...
-
-The classical way to describe this kind of information within an
-entity-relationship schema is to *reify* the relation, that is turn
-the relation into a entity. In our example the schema will have a
-*Contribution* entity type used to represent the family of the
-contribution relations.
-
-
-.. sourcecode:: python
-
- class ArtWork(EntityType):
- name = String()
- ...
-
- class Person(EntityType):
- name = String()
- ...
-
- class Contribution(EntityType):
- contributor = SubjectRelation('Person', cardinality='1*', inlined=True)
- manifestation = SubjectRelation('ArtWork')
- role = SubjectRelation('Role')
-
- class Role(EntityType):
- name = String()
-
-But then, in order to query the illustrator(s) ``I`` of a work ``W``,
-one has to write::
-
- Any I, W WHERE C is Contribution, C contributor I, C manifestation W,
- C role R, R name 'illustrator'
-
-whereas we would like to be able to simply write::
-
- Any I, W WHERE I illustrator_of W
-
-This is precisely what the computed relations allow.
-
-
-Computed (or synthesized) attribute
-```````````````````````````````````
-
-Assuming a trivial schema for describing employees in companies, one
-can be interested in the total of salaries payed by a company for
-all its employees. One has to write::
-
- Any C, SUM(SA) GROUPBY S WHERE E works_for C, E salary SA
-
-whereas it would be most convenient to simply write::
-
- Any C, TS WHERE C total_salary TS
-
-And this is again what computed attributes provide.
-
-
-Using computed attributes and relations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Computed (or reified) relations
-```````````````````````````````
-
-In the above case we would define the *computed relation*
-``illustrator_of`` in the schema by:
-
-.. sourcecode:: python
-
- class illustrator_of(ComputedRelation):
- rule = ('C is Contribution, C contributor S, C manifestation O,'
- 'C role R, R name "illustrator"')
-
-You will note that:
-
-* the ``S`` and ``O`` RQL variables implicitly identify the subject and
- object of the defined computed relation, akin to what happens in
- RRQLExpression
-* the possible subject and object entity types are inferred from the rule;
-* computed relation definitions always have empty *add* and *delete* permissions
-* *read* permissions can be defined, permissions from the relations used in the
- rewrite rule **are not considered** ;
-* nothing else may be defined on the `ComputedRelation` subclass beside
- description, permissions and rule (e.g. no cardinality, composite, etc.,).
- `BadSchemaDefinition` is raised on attempt to specify other attributes;
-* computed relations can not be used in 'SET' and 'DELETE' rql queries
- (`BadQuery` exception raised).
-
-
-NB: The fact that the *add* and *delete* permissions are *empty* even
-for managers is expected to make the automatic UI not attempt to edit
-them.
-
-Computed (or synthesized) attributes
-````````````````````````````````````
-
-In the above case we would define the *computed attribute*
-``total_salary`` on the ``Company`` entity type in the schema by:
-
-.. sourcecode:: python
-
- class Company(EntityType):
- name = String()
- total_salary = Int(formula='Any SUM(SA) GROUPBY E WHERE P works_for X, E salary SA')
-
-* the ``X`` RQL variable implicitly identifies the entity holding the
- computed attribute, akin to what happens in ERQLExpression;
-* the type inferred from the formula is checked against the declared type, and
- `BadSchemaDefinition` is raised if they don't match;
-* the computed attributes always have empty *update* permissions
-* `BadSchemaDefinition` is raised on attempt to set 'update' permissions;
-* 'read' permissions can be defined, permissions regarding the formula
- **are not considered**;
-* other attribute's property (inlined, ...) can be defined as for normal attributes;
-* Similarly to computed relation, computed attribute can't be used in 'SET' and
- 'DELETE' rql queries (`BadQuery` exception raised).
-
-
-API and implementation
-~~~~~~~~~~~~~~~~~~~~~~
-
-Representation in the data backend
-``````````````````````````````````
-
-Computed relations have no direct representation at the SQL table
-level. Instead, each time a query is issued the query is rewritten to
-replace the computed relation by its equivalent definition and the
-resulting rewritten query is performed in the usual way.
-
-On the contrary, computed attributes are represented as a column in the
-table for their host entity type, just like normal attributes. Their
-value is kept up-to-date with respect to their defintion by a system
-of hooks (also called triggers in most RDBMS) which recomputes them
-when the relations and attributes they depend on are modified.
-
-Yams API
-````````
-
-When accessing the schema through the *yams API* (not when defining a
-schema in a ``schema.py`` file) the computed attributes and relations
-are represented as follows:
-
-relations
- The ``yams.RelationSchema`` class has a new ``rule`` attribute
- holding the rule as a string. If this attribute is set all others
- must not be set.
-attributes
- A new property ``formula`` is added on class
- ``yams.RelationDefinitionSchema`` alomng with a new keyword
- argument ``formula`` on the initializer.
-
-Migration
-`````````
-
-The migrations are to be handled as summarized in the array below.
-
-+------------+---------------------------------------------------+---------------------------------------+
-| | Computed rtype | Computed attribute |
-+============+===================================================+=======================================+
-| add | * add_relation_type | * add_attribute |
-| | * add_relation_definition should trigger an error | * add_relation_definition |
-+------------+---------------------------------------------------+---------------------------------------+
-| modify | * sync_schema_prop_perms: | * sync_schema_prop_perms: |
-| | checks the rule is | |
-| (rule or | synchronized with the database | - empty the cache, |
-| formula) | | - check formula, |
-| | | - make sure all the values get |
-| | | updated |
-+------------+---------------------------------------------------+---------------------------------------+
-| del | * drop_relation_type | * drop_attribute |
-| | * drop_relation_definition should trigger an error| * drop_relation_definition |
-+------------+---------------------------------------------------+---------------------------------------+
-
-
-Defining your schema using yams
--------------------------------
-
-Entity type definition
-~~~~~~~~~~~~~~~~~~~~~~
-
-An entity type is defined by a Python class which inherits from
-:class:`yams.buildobjs.EntityType`. The class definition contains the
-description of attributes and relations for the defined entity type.
-The class name corresponds to the entity type name. It is expected to
-be defined in the module ``mycube.schema``.
-
-:Note on schema definition:
-
- The code in ``mycube.schema`` is not meant to be executed. The class
- EntityType mentioned above is different from the EntitySchema class
- described in the previous chapter. EntityType is a helper class to
- make Entity definition easier. Yams will process EntityType classes
- and create EntitySchema instances from these class definitions. Similar
- manipulation happen for relations.
-
-When defining a schema using python files, you may use the following shortcuts:
-
-- `required`: boolean indicating if the attribute is required, ed subject cardinality is '1'
-
-- `vocabulary`: specify static possible values of an attribute
-
-- `maxsize`: integer providing the maximum size of a string (no limit by default)
-
-For example:
-
-.. sourcecode:: python
-
- class Person(EntityType):
- """A person with the properties and the relations necessary for my
- application"""
-
- last_name = String(required=True, fulltextindexed=True)
- first_name = String(required=True, fulltextindexed=True)
- title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
- date_of_birth = Date()
- works_for = SubjectRelation('Company', cardinality='?*')
-
-
-The entity described above defines three attributes of type String,
-last_name, first_name and title, an attribute of type Date for the date of
-birth and a relation that connects a `Person` to another entity of type
-`Company` through the semantic `works_for`.
-
-
-
-:Naming convention:
-
- Entity class names must start with an uppercase letter. The common
- usage is to use ``CamelCase`` names.
-
- Attribute and relation names must start with a lowercase letter. The
- common usage is to use ``underscore_separated_words``. Attribute and
- relation names starting with a single underscore are permitted, to
- denote a somewhat "protected" or "private" attribute.
-
- In any case, identifiers starting with "CW" or "cw" are reserved for
- internal use by the framework.
-
- .. _Metadata:
-
- Some attribute using the name of another attribute as prefix are considered
- metadata. For example, if an EntityType have both a ``data`` and
- ``data_format`` attribute, ``data_format`` is view as the ``format`` metadata
- of ``data``. Later the :meth:`cw_attr_metadata` method will allow you to fetch
- metadata related to an attribute. There are only three valid metadata names:
- ``format``, ``encoding`` and ``name``.
-
-
-The name of the Python attribute corresponds to the name of the attribute
-or the relation in *CubicWeb* application.
-
-An attribute is defined in the schema as follows::
-
- attr_name = AttrType(*properties, metadata={})
-
-where
-
-* `AttrType`: is one of the type listed in EntityType_,
-
-* `properties`: is a list of the attribute needs to satisfy (see `Properties`_
- for more details),
-
-* `metadata`: is a dictionary of meta attributes related to ``attr_name``.
- Dictionary keys are the name of the meta attribute. Dictionary values
- attributes objects (like the content of ``AttrType``). For each entry of the
- metadata dictionary a ``<attr_name>_<key> = <value>`` attribute is
- automaticaly added to the EntityType. see `Metadata`_ section for details
- about valid key.
-
-
- ---
-
-While building your schema
-
-* it is possible to use the attribute `meta` to flag an entity type as a `meta`
- (e.g. used to describe/categorize other entities)
-
-.. XXX the paragraph below needs clarification and / or moving out in
-.. another place
-
-*Note*: if you end up with an `if` in the definition of your entity, this probably
-means that you need two separate entities that implement the `ITree` interface and
-get the result from `.children()` which ever entity is concerned.
-
-.. Inheritance
-.. ```````````
-.. XXX feed me
-
-
-Definition of relations
-~~~~~~~~~~~~~~~~~~~~~~~
-
-.. XXX add note about defining relation type / definition
-
-A relation is defined by a Python class heriting `RelationType`. The name
-of the class corresponds to the name of the type. The class then contains
-a description of the properties of this type of relation, and could as well
-contain a string for the subject and a string for the object. This allows to create
-new definition of associated relations, (so that the class can have the
-definition properties from the relation) for example ::
-
- class locked_by(RelationType):
- """relation on all entities indicating that they are locked"""
- inlined = True
- cardinality = '?*'
- subject = '*'
- object = 'CWUser'
-
-If provided, the `subject` and `object` attributes denote the subject
-and object of the various relation definitions related to the relation
-type. Allowed values for these attributes are:
-
-* a string corresponding to an entity type
-* a tuple of string corresponding to multiple entity types
-* the '*' special string, meaning all types of entities
-
-When a relation is not inlined and not symmetrical, and it does not require
-specific permissions, it can be defined using a `SubjectRelation`
-attribute in the EntityType class. The first argument of `SubjectRelation` gives
-the entity type for the object of the relation.
-
-:Naming convention:
-
- Although this way of defining relations uses a Python class, the
- naming convention defined earlier prevails over the PEP8 conventions
- used in the framework: relation type class names use
- ``underscore_separated_words``.
-
-:Historical note:
-
- It has been historically possible to use `ObjectRelation` which
- defines a relation in the opposite direction. This feature is
- deprecated and therefore should not be used in newly written code.
-
-:Future deprecation note:
-
- In an even more remote future, it is quite possible that the
- SubjectRelation shortcut will become deprecated, in favor of the
- RelationType declaration which offers some advantages in the context
- of reusable cubes.
-
-
-
-
-Handling schema changes
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Also, it should be clear that to properly handle data migration, an
-instance's schema is stored in the database, so the python schema file
-used to defined it is only read when the instance is created or
-upgraded.
-
-.. XXX complete me
--- a/doc/book/en/devrepo/datamodel/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-Data model
-==========
-
-This chapter describes how you define a schema and how to make it evolves as the time goes.
-
-.. toctree::
- :maxdepth: 1
-
- definition
- metadata
- baseschema
- define-workflows
--- a/doc/book/en/devrepo/datamodel/metadata.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-
-Metadata
---------
-
-.. index::
- schema: meta-data;
- schema: eid; creation_date; modification_data; cwuri
- schema: created_by; owned_by; is; is_instance;
-
-Each entity type in |cubicweb| has at least the following meta-data attributes and relations:
-
-`eid`
- entity's identifier which is unique in an instance. We usually call this identifier `eid` for historical reason.
-
-`creation_date`
- Date and time of the creation of the entity.
-
-`modification_date`
- Date and time of the latest modification of an entity.
-
-`cwuri`
- Reference URL of the entity, which is not expected to change.
-
-`created_by`
- Relation to the :ref:`users <CWUser>` who has created the entity
-
-`owned_by`
- Relation to :ref:`users <CWUser>` whom the entity belongs; usually the creator but not
- necessary, and it could have multiple owners notably for permission control
-
-`is`
- Relation to the :ref:`entity type <CWEType>` of which type the entity is.
-
-`is_instance`
- Relation to the :ref:`entity types <CWEType>` of which type the
- entity is an instance of.
-
--- a/doc/book/en/devrepo/devcore/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-Core APIs
-=========
-
-.. toctree::
- :maxdepth: 1
-
- reqbase.rst
-
--- a/doc/book/en/devrepo/devcore/reqbase.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-Request and ResultSet methods
------------------------------
-
-Those are methods you'll find on both request objects and on
-repository session.
-
-Request methods
-~~~~~~~~~~~~~~~
-
-`URL handling`:
-
-* `build_url(*args, **kwargs)`, returns an absolute URL based on the
- given arguments. The *controller* supposed to handle the response,
- can be specified through the first positional parameter (the
- connection is theoretically done automatically :).
-
-`Data formatting`:
-
-* `format_date(date, date_format=None, time=False)` returns a string for a
- date time according to instance's configuration
-
-* `format_time(time)` returns a string for a date time according to
- instance's configuration
-
-`And more...`:
-
-* `tal_render(template, variables)`, renders a precompiled page template with
- variables in the given dictionary as context
-
-
-Result set methods
-~~~~~~~~~~~~~~~~~~
-
-* `get_entity(row, col)`, returns the entity corresponding to the data position
- in the *result set*
-
-* `complete_entity(row, col, skip_bytes=True)`, is equivalent to `get_entity` but
- also call the method `complete()` on the entity before returning it
-
-
--- a/doc/book/en/devrepo/entityclasses/adapters.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-.. _adapters:
-
-Interfaces and Adapters
------------------------
-
-Interfaces are the same thing as object-oriented programming `interfaces`_.
-Adapter refers to a well-known `adapter`_ design pattern that helps separating
-concerns in object oriented applications.
-
-.. _`interfaces`: http://java.sun.com/docs/books/tutorial/java/concepts/interface.html
-.. _`adapter`: http://en.wikipedia.org/wiki/Adapter_pattern
-
-In |cubicweb| adapters provide logical functionalities to entity types.
-
-Definition of an adapter is quite trivial. An excerpt from cubicweb
-itself (found in :mod:`cubicweb.entities.adapters`):
-
-.. sourcecode:: python
-
-
- class ITreeAdapter(EntityAdapter):
- """This adapter has to be overriden to be configured using the
- tree_relation, child_role and parent_role class attributes to
- benefit from this default implementation
- """
- __regid__ = 'ITree'
-
- child_role = 'subject'
- parent_role = 'object'
-
- def children_rql(self):
- """returns RQL to get children """
- return self.entity.cw_related_rql(self.tree_relation, self.parent_role)
-
-The adapter object has ``self.entity`` attribute which represents the
-entity being adapted.
-
-.. Note::
-
- Adapters came with the notion of service identified by the registry identifier
- of an adapters, hence dropping the need for explicit interface and the
- :class:`cubicweb.predicates.implements` selector. You should instead use
- :class:`cubicweb.predicates.is_instance` when you want to select on an entity
- type, or :class:`cubicweb.predicates.adaptable` when you want to select on a
- service.
-
-
-Specializing and binding an adapter
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. sourcecode:: python
-
- from cubicweb.entities.adapters import ITreeAdapter
-
- class MyEntityITreeAdapter(ITreeAdapter):
- __select__ = is_instance('MyEntity')
- tree_relation = 'filed_under'
-
-The ITreeAdapter here provides a default implementation. The
-tree_relation class attribute is actually used by this implementation
-to help implement correct behaviour.
-
-Here we provide a specific implementation which will be bound for
-``MyEntity`` entity type (the `adaptee`).
-
-
-.. _interfaces_to_adapters:
-
-Converting code from Interfaces/Mixins to Adapters
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here we go with a small example. Before:
-
-.. sourcecode:: python
-
- from cubicweb.predicates import implements
- from cubicweb.interfaces import ITree
- from cubicweb.mixins import ITreeMixIn
-
- class MyEntity(ITreeMixIn, AnyEntity):
- __implements__ = AnyEntity.__implements__ + (ITree,)
-
-
- class ITreeView(EntityView):
- __select__ = implements('ITree')
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- children = entity.children()
-
-After:
-
-.. sourcecode:: python
-
- from cubicweb.predicates import adaptable, is_instance
- from cubicweb.entities.adapters import ITreeAdapter
-
- class MyEntityITreeAdapter(ITreeAdapter):
- __select__ = is_instance('MyEntity')
-
- class ITreeView(EntityView):
- __select__ = adaptable('ITree')
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- itree = entity.cw_adapt_to('ITree')
- children = itree.children()
-
-As we can see, the interface/mixin duality disappears and the entity
-class itself is completely freed from these concerns. When you want
-to use the ITree interface of an entity, call its `cw_adapt_to` method
-to get an adapter for this interface, then access to members of the
-interface on the adapter
-
-Let's look at an example where we defined everything ourselves. We
-start from:
-
-.. sourcecode:: python
-
- class IFoo(Interface):
- def bar(self, *args):
- raise NotImplementedError
-
- class MyEntity(AnyEntity):
- __regid__ = 'MyEntity'
- __implements__ = AnyEntity.__implements__ + (IFoo,)
-
- def bar(self, *args):
- return sum(captain.age for captain in self.captains)
-
- class FooView(EntityView):
- __regid__ = 'mycube.fooview'
- __select__ = implements('IFoo')
-
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- self.w('bar: %s' % entity.bar())
-
-Converting to:
-
-.. sourcecode:: python
-
- class IFooAdapter(EntityAdapter):
- __regid__ = 'IFoo'
- __select__ = is_instance('MyEntity')
-
- def bar(self, *args):
- return sum(captain.age for captain in self.entity.captains)
-
- class FooView(EntityView):
- __regid__ = 'mycube.fooview'
- __select__ = adaptable('IFoo')
-
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- self.w('bar: %s' % entity.cw_adapt_to('IFoo').bar())
-
-.. note::
-
- When migrating an entity method to an adapter, the code can be moved as is
- except for the `self` of the entity class, which in the adapter must become `self.entity`.
-
-Adapters defined in the library
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: cubicweb.entities.adapters
- :members:
-
-More are defined in web/views.
--- a/doc/book/en/devrepo/entityclasses/application-logic.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-How to use entities objects and adapters
-----------------------------------------
-
-The previous chapters detailed the classes and methods available to
-the developer at the so-called `ORM`_ level. However they say little
-about the common patterns of usage of these objects.
-
-.. _`ORM`: http://en.wikipedia.org/wiki/Object-relational_mapping
-
-Entities objects (and their adapters) are used in the repository and
-web sides of CubicWeb. On the repository side of things, one should
-manipulate them in Hooks and Operations.
-
-Hooks and Operations provide support for the implementation of rules
-such as computed attributes, coherency invariants, etc (they play the
-same role as database triggers, but in a way that is independent of
-the actual data sources).
-
-So a lot of an application's business rules will be written in Hooks
-(or Operations).
-
-On the web side, views also typically operate using entity
-objects. Obvious entity methods for use in views are the Dublin Core
-methods like ``dc_title``. For separation of concerns reasons, one
-should ensure no ui logic pervades the entities level, and also no
-business logic should creep into the views.
-
-In the duration of a transaction, entities objects can be instantiated
-many times, in views and hooks, even for the same database entity. For
-instance, in a classic CubicWeb deployment setup, the repository and
-the web front-end are separated process communicating over the
-wire. There is no way state can be shared between these processes
-(there is a specific API for that). Hence, it is not possible to use
-entity objects as messengers between these components of an
-application. It means that an attribute set as in ``obj.x = 42``,
-whether or not x is actually an entity schema attribute, has a short
-life span, limited to the hook, operation or view within which the
-object was built.
-
-Setting an attribute or relation value can be done in the context of a
-Hook/Operation, using the ``obj.cw_set(x=42)`` notation or a plain
-RQL ``SET`` expression.
-
-In views, it would be preferable to encapsulate the necessary logic in
-a method of an adapter for the concerned entity class(es). But of
-course, this advice is also reasonable for Hooks/Operations, though
-the separation of concerns here is less stringent than in the case of
-views.
-
-This leads to the practical role of objects adapters: it's where an
-important part of the application logic lies (the other part being
-located in the Hook/Operations).
-
-Anatomy of an entity class
---------------------------
-
-We can look now at a real life example coming from the `tracker`_
-cube. Let us begin to study the ``entities/project.py`` content.
-
-.. sourcecode:: python
-
- from cubicweb.entities.adapters import ITreeAdapter
-
- class ProjectAdapter(ITreeAdapter):
- __select__ = is_instance('Project')
- tree_relation = 'subproject_of'
-
- class Project(AnyEntity):
- __regid__ = 'Project'
- fetch_attrs, cw_fetch_order = fetch_config(('name', 'description',
- 'description_format', 'summary'))
-
- TICKET_DEFAULT_STATE_RESTR = 'S name IN ("created","identified","released","scheduled")'
-
- def dc_title(self):
- return self.name
-
-The fact that the `Project` entity type implements an ``ITree``
-interface is materialized by the ``ProjectAdapter`` class (inheriting
-the pre-defined ``ITreeAdapter`` whose ``__regid__`` is of course
-``ITree``), which will be selected on `Project` entity types because
-of its selector. On this adapter, we redefine the ``tree_relation``
-attribute of the ``ITreeAdapter`` class.
-
-This is typically used in views concerned with the representation of
-tree-like structures (CubicWeb provides several such views).
-
-It is important that the views themselves try not to implement this
-logic, not only because such views would be hardly applyable to other
-tree-like relations, but also because it is perfectly fine and useful
-to use such an interface in Hooks.
-
-In fact, Tree nature is a property of the data model that cannot be
-fully and portably expressed at the level of database entities (think
-about the transitive closure of the child relation). This is a further
-argument to implement it at entity class level.
-
-``fetch_attrs`` configures which attributes should be pre-fetched when using ORM
-methods retrieving entity of this type. In a same manner, the ``cw_fetch_order`` is
-a class method allowing to control sort order. More on this in :ref:`FetchAttrs`.
-
-We can observe the big ``TICKET_DEFAULT_STATE_RESTR`` is a pure
-application domain piece of data. There is, of course, no limitation
-to the amount of class attributes of this kind.
-
-The ``dc_title`` method provides a (unicode string) value likely to be
-consumed by views, but note that here we do not care about output
-encodings. We care about providing data in the most universal format
-possible, because the data could be used by a web view (which would be
-responsible of ensuring XHTML compliance), or a console or file
-oriented output (which would have the necessary context about the
-needed byte stream encoding).
-
-.. note::
-
- The Dublin Core `dc_xxx` methods are not moved to an adapter as they
- are extremely prevalent in CubicWeb and assorted cubes and should be
- available for all entity types.
-
-Let us now dig into more substantial pieces of code, continuing the
-Project class.
-
-.. sourcecode:: python
-
- def latest_version(self, states=('published',), reverse=None):
- """returns the latest version(s) for the project in one of the given
- states.
-
- when no states specified, returns the latest published version.
- """
- order = 'DESC'
- if reverse is not None:
- warn('reverse argument is deprecated',
- DeprecationWarning, stacklevel=1)
- if reverse:
- order = 'ASC'
- rset = self.versions_in_state(states, order, True)
- if rset:
- return rset.get_entity(0, 0)
- return None
-
- def versions_in_state(self, states, order='ASC', limit=False):
- """returns version(s) for the project in one of the given states, sorted
- by version number.
-
- If limit is true, limit result to one version.
- If reverse, versions are returned from the smallest to the greatest.
- """
- if limit:
- order += ' LIMIT 1'
- rql = 'Any V,N ORDERBY version_sort_value(N) %s ' \
- 'WHERE V num N, V in_state S, S name IN (%s), ' \
- 'V version_of P, P eid %%(p)s' % (order, ','.join(repr(s) for s in states))
- return self._cw.execute(rql, {'p': self.eid})
-
-.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker/
-
-These few lines exhibit the important properties we want to outline:
-
-* entity code is concerned with the application domain
-
-* it is NOT concerned with database consistency (this is the realm of
- Hooks/Operations); in other words, it assumes a consistent world
-
-* it is NOT (directly) concerned with end-user interfaces
-
-* however it can be used in both contexts
-
-* it does not create or manipulate the internal object's state
-
-* it plays freely with RQL expression as needed
-
-* it is not concerned with internationalization
-
-* it does not raise exceptions
-
-
--- a/doc/book/en/devrepo/entityclasses/data-as-objects.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-Access to persistent data
---------------------------
-
-Python-level access to persistent data is provided by the
-:class:`Entity <cubicweb.entity>` class.
-
-.. XXX this part is not clear. refactor it.
-
-An entity class is bound to a schema entity type. Descriptors are added when
-classes are registered in order to initialize the class according to its schema:
-
-* the attributes defined in the schema appear as attributes of these classes
-
-* the relations defined in the schema appear as attributes of these classes,
- but are lists of instances
-
-`Formatting and output generation`:
-
-* :meth:`view(__vid, __registry='views', **kwargs)`, applies the given view to the entity
- (and returns a unicode string)
-
-* :meth:`absolute_url(*args, **kwargs)`, returns an absolute URL including the base-url
-
-* :meth:`rest_path()`, returns a relative REST URL to get the entity
-
-* :meth:`printable_value(attr, value=_marker, attrtype=None, format='text/html', displaytime=True)`,
- returns a string enabling the display of an attribute value in a given format
- (the value is automatically recovered if necessary)
-
-`Data handling`:
-
-* :meth:`as_rset()`, converts the entity into an equivalent result set simulating the
- request `Any X WHERE X eid _eid_`
-
-* :meth:`complete(skip_bytes=True)`, executes a request that recovers at
- once all the missing attributes of an entity
-
-* :meth:`get_value(name)`, returns the value associated to the attribute name given
- in parameter
-
-* :meth:`related(rtype, role='subject', limit=None, entities=False)`,
- returns a list of entities related to the current entity by the
- relation given in parameter
-
-* :meth:`unrelated(rtype, targettype, role='subject', limit=None)`,
- returns a result set corresponding to the entities not (yet)
- related to the current entity by the relation given in parameter
- and satisfying its constraints
-
-* :meth:`cw_set(**kwargs)`, updates entity's attributes and/or relation with the
- corresponding values given named parameters. To set a relation where this
- entity is the object of the relation, use `reverse_<relation>` as argument
- name. Values may be an entity, a list of entities, or None (meaning that all
- relations of the given type from or to this object should be deleted).
-
-* :meth:`copy_relations(ceid)`, copies the relations of the entities having the eid
- given in the parameters on the current entity
-
-* :meth:`cw_delete()` allows to delete the entity
-
-
-The :class:`AnyEntity` class
-----------------------------
-
-To provide a specific behavior for each entity, we can define a class
-inheriting from `cubicweb.entities.AnyEntity`. In general, we define this class
-in `mycube.entities` module (or in a submodule if we want to split code among
-multiple files) so that it will be available on both server and client side.
-
-The class `AnyEntity` is a sub-class of Entity that add methods to it,
-and helps specializing (by further subclassing) the handling of a
-given entity type.
-
-Most methods defined for `AnyEntity`, in addition to `Entity`, add
-support for the `Dublin Core`_ metadata.
-
-.. _`Dublin Core`: http://dublincore.org/
-
-`Standard meta-data (Dublin Core)`:
-
-* :meth:`dc_title()`, returns a unicode string corresponding to the
- meta-data `Title` (used by default is the first non-meta attribute
- of the entity schema)
-
-* :meth:`dc_long_title()`, same as dc_title but can return a more
- detailed title
-
-* :meth:`dc_description(format='text/plain')`, returns a unicode string
- corresponding to the meta-data `Description` (looks for a
- description attribute by default)
-
-* :meth:`dc_authors()`, returns a unicode string corresponding to the meta-data
- `Authors` (owners by default)
-
-* :meth:`dc_creator()`, returns a unicode string corresponding to the
- creator of the entity
-
-* :meth:`dc_date(date_format=None)`, returns a unicode string corresponding to
- the meta-data `Date` (update date by default)
-
-* :meth:`dc_type(form='')`, returns a string to display the entity type by
- specifying the preferred form (`plural` for a plural form)
-
-* :meth:`dc_language()`, returns the language used by the entity
-
-Inheritance
------------
-
-When describing a data model, entities can inherit from other entities as is
-common in object-oriented programming.
-
-You have the possibility to redefine whatever pleases you, as follow:
-
-.. sourcecode:: python
-
- from cubes.OTHER_CUBE import entities
-
- class EntityExample(entities.EntityExample):
-
- def dc_long_title(self):
- return '%s (%s)' % (self.name, self.description)
-
-The most specific entity definition will always the one used by the
-ORM. For instance, the new EntityExample above in mycube replaces the
-one in OTHER_CUBE. These types are stored in the `etype` section of
-the `vregistry`.
-
-Notice this is different than yams schema inheritance, which is an
-experimental undocumented feature.
-
-
-Application logic
------------------
-
-While a lot of custom behaviour and application logic can be
-implemented using entity classes, the programmer must be aware that
-adding new attributes and method on an entity class adds may shadow
-schema-level attribute or relation definitions.
-
-To keep entities clean (mostly data structures plus a few universal
-methods such as listed above), one should use `adapters` (see
-:ref:`adapters`).
--- a/doc/book/en/devrepo/entityclasses/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-Data as objects
-===============
-
-In this chapter, we will introduce the objects that are used to handle
-the logic associated to the data stored in the database.
-
-.. toctree::
- :maxdepth: 1
-
- data-as-objects
- load-sort
- adapters
- application-logic
--- a/doc/book/en/devrepo/entityclasses/load-sort.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-
-.. _FetchAttrs:
-
-Loaded attributes and default sorting management
-````````````````````````````````````````````````
-
-* The class attribute `fetch_attrs` allows to define in an entity class a list of
- names of attributes that should be automatically loaded when entities of this
- type are fetched from the database using ORM methods retrieving entity of this
- type (such as :meth:`related` and :meth:`unrelated`). You can also put relation
- names in there, but we are limited to *subject relations of cardinality `?` or
- `1`*.
-
-* The :meth:`cw_fetch_order` and :meth:`cw_fetch_unrelated_order` class methods
- are respectively responsible to control how entities will be sorted when:
-
- - retrieving all entities of a given type, or entities related to another
-
- - retrieving a list of entities for use in drop-down lists enabling relations
- creation in the editing view of an entity
-
-By default entities will be listed on their modification date descending,
-i.e. you'll get entities recently modified first. While this is usually a good
-default in drop-down list, you'll probably want to change `cw_fetch_order`.
-
-This may easily be done using the :func:`~cubicweb.entities.fetch_config`
-function, which simplifies the definition of attributes to load and sorting by
-returning a list of attributes to pre-load (considering automatically the
-attributes of `AnyEntity`) and a sorting function as described below:
-
-.. autofunction:: cubicweb.entities.fetch_config
-
-In you want something else (such as sorting on the result of a registered
-procedure), here is the prototype of those methods:
-
-
-.. automethod:: cubicweb.entity.Entity.cw_fetch_order
-
-.. automethod:: cubicweb.entity.Entity.cw_fetch_unrelated_order
-
--- a/doc/book/en/devrepo/fti.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-.. _fti:
-
-Full Text Indexing in CubicWeb
-------------------------------
-
-When an attribute is tagged as *fulltext-indexable* in the datamodel,
-CubicWeb will automatically trigger hooks to update the internal
-fulltext index (i.e the ``appears`` SQL table) each time this attribute
-is modified.
-
-CubicWeb also provides a ``db-rebuild-fti`` command to rebuild the whole
-fulltext on demand:
-
-.. sourcecode:: bash
-
- cubicweb@esope~$ cubicweb db-rebuild-fti my_tracker_instance
-
-You can also rebuild the fulltext index for a given set of entity types:
-
-.. sourcecode:: bash
-
- cubicweb@esope~$ cubicweb db-rebuild-fti my_tracker_instance Ticket Version
-
-In the above example, only fulltext index of entity types ``Ticket`` and ``Version``
-will be rebuilt.
-
-
-Standard FTI process
-~~~~~~~~~~~~~~~~~~~~
-
-Considering an entity type ``ET``, the default *fti* process is to :
-
-1. fetch all entities of type ``ET``
-
-2. for each entity, adapt it to ``IFTIndexable`` (see
- :class:`~cubicweb.entities.adapters.IFTIndexableAdapter`)
-
-3. call
- :meth:`~cubicweb.entities.adapters.IFTIndexableAdapter.get_words` on
- the adapter which is supposed to return a dictionary *weight* ->
- *list of words* as expected by
- :meth:`~logilab.database.fti.FTIndexerMixIn.index_object`. The
- tokenization of each attribute value is done by
- :meth:`~logilab.database.fti.tokenize`.
-
-
-See :class:`~cubicweb.entities.adapters.IFTIndexableAdapter` for more documentation.
-
-
-Yams and ``fulltext_container``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is possible in the datamodel to indicate that fulltext-indexed
-attributes defined for an entity type will be used to index not the
-entity itself but a related entity. This is especially useful for
-composite entities. Let's take a look at (a simplified version of)
-the base schema defined in CubicWeb (see :mod:`cubicweb.schemas.base`):
-
-.. sourcecode:: python
-
- class CWUser(WorkflowableEntityType):
- login = String(required=True, unique=True, maxsize=64)
- upassword = Password(required=True)
-
- class EmailAddress(EntityType):
- address = String(required=True, fulltextindexed=True,
- indexed=True, unique=True, maxsize=128)
-
-
- class use_email_relation(RelationDefinition):
- name = 'use_email'
- subject = 'CWUser'
- object = 'EmailAddress'
- cardinality = '*?'
- composite = 'subject'
-
-
-The schema above states that there is a relation between ``CWUser`` and ``EmailAddress``
-and that the ``address`` field of ``EmailAddress`` is fulltext indexed. Therefore,
-in your application, if you use fulltext search to look for an email address, CubicWeb
-will return the ``EmailAddress`` itself. But the objects we'd like to index
-are more likely to be the associated ``CWUser`` than the ``EmailAddress`` itself.
-
-The simplest way to achieve that is to tag the ``use_email`` relation in
-the datamodel:
-
-.. sourcecode:: python
-
- class use_email(RelationType):
- fulltext_container = 'subject'
-
-
-Customizing how entities are fetched during ``db-rebuild-fti``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-``db-rebuild-fti`` will call the
-:meth:`~cubicweb.entities.AnyEntity.cw_fti_index_rql_queries` class
-method on your entity type.
-
-.. automethod:: cubicweb.entities.AnyEntity.cw_fti_index_rql_queries
-
-Now, suppose you've got a _huge_ table to index, you probably don't want to
-get all entities at once. So here's a simple customized example that will
-process block of 10000 entities:
-
-.. sourcecode:: python
-
-
- class MyEntityClass(AnyEntity):
- __regid__ = 'MyEntityClass'
-
- @classmethod
- def cw_fti_index_rql_queries(cls, req):
- # get the default RQL method and insert LIMIT / OFFSET instructions
- base_rql = super(SearchIndex, cls).cw_fti_index_rql_queries(req)[0]
- selected, restrictions = base_rql.split(' WHERE ')
- rql_template = '%s ORDERBY X LIMIT %%(limit)s OFFSET %%(offset)s WHERE %s' % (
- selected, restrictions)
- # count how many entities you'll have to index
- count = req.execute('Any COUNT(X) WHERE X is MyEntityClass')[0][0]
- # iterate by blocks of 10000 entities
- chunksize = 10000
- for offset in xrange(0, count, chunksize):
- print 'SENDING', rql_template % {'limit': chunksize, 'offset': offset}
- yield rql_template % {'limit': chunksize, 'offset': offset}
-
-Since you have access to ``req``, you can more or less fetch whatever you want.
-
-
-Customizing :meth:`~cubicweb.entities.adapters.IFTIndexableAdapter.get_words`
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-You can also customize the FTI process by providing your own ``get_words()``
-implementation:
-
-.. sourcecode:: python
-
- from cubicweb.entities.adapters import IFTIndexableAdapter
-
- class SearchIndexAdapter(IFTIndexableAdapter):
- __regid__ = 'IFTIndexable'
- __select__ = is_instance('MyEntityClass')
-
- def fti_containers(self, _done=None):
- """this should yield any entity that must be considered to
- fulltext-index self.entity
-
- CubicWeb's default implementation will look for yams'
- ``fulltex_container`` property.
- """
- yield self.entity
- yield self.entity.some_related_entity
-
-
- def get_words(self):
- # implement any logic here
- # see http://www.postgresql.org/docs/9.1/static/textsearch-controls.html
- # for the actual signification of 'C'
- return {'C': ['any', 'word', 'I', 'want']}
--- a/doc/book/en/devrepo/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-.. _Part2:
-
-----------------------
-Repository development
-----------------------
-
-This part is about developing applications with the *CubicWeb*
-framework. It is not concerned with the web system, which is a
-separate layer and has its own whole chapter.
-
-.. toctree::
- :maxdepth: 2
- :numbered:
-
- cubes/index
- vreg.rst
- datamodel/index
- entityclasses/index
- devcore/index
- repo/index
- testing.rst
- migration.rst
- profiling.rst
- fti.rst
- dataimport
--- a/doc/book/en/devrepo/migration.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _migration:
-
-Migration
-=========
-
-One of the main design goals of *CubicWeb* was to support iterative and agile
-development. For this purpose, multiple actions are provided to facilitate the
-improvement of an instance, and in particular to handle the changes to be
-applied to the data model, without loosing existing data.
-
-The current version of a cube (and of cubicweb itself) is provided in the file
-`__pkginfo__.py` as a tuple of 3 integers.
-
-Migration scripts management
-----------------------------
-
-Migration scripts has to be located in the directory `migration` of your
-cube and named accordingly:
-
-::
-
- <version n° X.Y.Z>[_<description>]_<mode>.py
-
-in which :
-
-* X.Y.Z is the model version number to which the script enables to migrate.
-
-* *mode* (between the last "_" and the extension ".py") is used for
- distributed installation. It indicates to which part
- of the application (RQL server, web server) the script applies.
- Its value could be :
-
- * `common`, applies to the RQL server as well as the web server and updates
- files on the hard drive (configuration files migration for example).
-
- * `web`, applies only to the web server and updates files on the hard drive.
-
- * `repository`, applies only to the RQL server and updates files on the
- hard drive.
-
- * `Any`, applies only to the RQL server and updates data in the database
- (schema and data migration for example).
-
-Again in the directory `migration`, the file `depends.map` allows to indicate
-that for the migration to a particular model version, you always have to first
-migrate to a particular *CubicWeb* version. This file can contain comments (lines
-starting with `#`) and a dependency is listed as follows: ::
-
- <model version n° X.Y.Z> : <cubicweb version n° X.Y.Z>
-
-For example: ::
-
- 0.12.0: 2.26.0
- 0.13.0: 2.27.0
- # 0.14 works with 2.27 <= cubicweb <= 2.28 at least
- 0.15.0: 2.28.0
-
-Base context
-------------
-
-The following identifiers are pre-defined in migration scripts:
-
-* `config`, instance configuration
-
-* `interactive_mode`, boolean indicating that the script is executed in
- an interactive mode or not
-
-* `versions_map`, dictionary of migrated versions (key are cubes
- names, including 'cubicweb', values are (from version, to version)
-
-* `confirm(question)`, function asking the user and returning true
- if the user answers yes, false otherwise (always returns true in
- non-interactive mode)
-
-* `_()` is equivalent to `unicode` allowing to flag the strings to
- internationalize in the migration scripts.
-
-In the `repository` scripts, the following identifiers are also defined:
-
-* `commit(ask_confirm=True)`, request confirming and executing a "commit"
-
-* `schema`, instance schema (readen from the database)
-
-* `fsschema`, installed schema on the file system (e.g. schema of
- the updated model and cubicweb)
-
-* `repo`, repository object
-
-* `session`, repository session object
-
-
-New cube dependencies
----------------------
-
-If your code depends on some new cubes, you have to add them in a migration
-script by using:
-
-* `add_cube(cube, update_database=True)`, add a cube.
-* `add_cubes(cubes, update_database=True)`, add a list of cubes.
-
-The `update_database` parameter is telling if the database schema
-should be updated or if only the relevant persistent property should be
-inserted (for the case where a new cube has been extracted from an
-existing one, so the new cube schema is actually already in there).
-
-If some of the added cubes are already used by an instance, they'll simply be
-silently skipped.
-
-
-Schema migration
-----------------
-The following functions for schema migration are available in `repository`
-scripts:
-
-* `add_attribute(etype, attrname, attrtype=None, commit=True)`, adds a new
- attribute to an existing entity type. If the attribute type is not specified,
- then it is extracted from the updated schema.
-
-* `drop_attribute(etype, attrname, commit=True)`, removes an attribute from an
- existing entity type.
-
-* `rename_attribute(etype, oldname, newname, commit=True)`, renames an attribute
-
-* `add_entity_type(etype, auto=True, commit=True)`, adds a new entity type.
- If `auto` is True, all the relations using this entity type and having a known
- entity type on the other hand will automatically be added.
-
-* `drop_entity_type(etype, commit=True)`, removes an entity type and all the
- relations using it.
-
-* `rename_entity_type(oldname, newname, commit=True)`, renames an entity type
-
-* `add_relation_type(rtype, addrdef=True, commit=True)`, adds a new relation
- type. If `addrdef` is True, all the relations definitions of this type will
- be added.
-
-* `drop_relation_type(rtype, commit=True)`, removes a relation type and all the
- definitions of this type.
-
-* `rename_relation_type(oldname, newname, commit=True)`, renames a relation type.
-
-* `add_relation_definition(subjtype, rtype, objtype, commit=True)`, adds a new
- relation definition.
-
-* `drop_relation_definition(subjtype, rtype, objtype, commit=True)`, removes
- a relation definition.
-
-* `sync_schema_props_perms(ertype=None, syncperms=True, syncprops=True, syncrdefs=True, commit=True)`,
- synchronizes properties and/or permissions on:
- - the whole schema if ertype is None
- - an entity or relation type schema if ertype is a string
- - a relation definition if ertype is a 3-uple (subject, relation, object)
-
-* `change_relation_props(subjtype, rtype, objtype, commit=True, **kwargs)`, changes
- properties of a relation definition by using the named parameters of the properties
- to change.
-
-* `set_widget(etype, rtype, widget, commit=True)`, changes the widget used for the
- relation <rtype> of entity type <etype>.
-
-* `set_size_constraint(etype, rtype, size, commit=True)`, changes the size constraints
- for the relation <rtype> of entity type <etype>.
-
-Data migration
---------------
-The following functions for data migration are available in `repository` scripts:
-
-* `rql(rql, kwargs=None, cachekey=None, ask_confirm=True)`, executes an arbitrary RQL
- query, either to interrogate or update. A result set object is returned.
-
-* `add_entity(etype, *args, **kwargs)`, adds a new entity of the given type.
- The attribute and relation values are specified as named positional
- arguments.
-
-Workflow creation
------------------
-
-The following functions for workflow creation are available in `repository`
-scripts:
-
-* `add_workflow(label, workflowof, initial=False, commit=False, **kwargs)`, adds a new workflow
- for a given type(s)
-
-You can find more details about workflows in the chapter :ref:`Workflow` .
-
-Configuration migration
------------------------
-
-The following functions for configuration migration are available in all
-scripts:
-
-* `option_renamed(oldname, newname)`, indicates that an option has been renamed
-
-* `option_group_change(option, oldgroup, newgroup)`, indicates that an option does not
- belong anymore to the same group.
-
-* `option_added(oldname, newname)`, indicates that an option has been added.
-
-* `option_removed(oldname, newname)`, indicates that an option has been deleted.
-
-The `config` variable is an object which can be used to access the
-configuration values, for reading and updating, with a dictionary-like
-syntax.
-
-Example 1: migration script changing the variable 'sender-addr' in
-all-in-one.conf. The script also checks that in that the instance is
-configured with a known value for that variable, and only updates the
-value in that case.
-
-.. sourcecode:: python
-
- wrong_addr = 'cubicweb@loiglab.fr' # known wrong address
- fixed_addr = 'cubicweb@logilab.fr'
- configured_addr = config.get('sender-addr')
- # check that the address has not been hand fixed by a sysadmin
- if configured_addr == wrong_addr:
- config['sender-addr'] = fixed-addr
- config.save()
-
-Example 2: checking the value of the database backend driver, which
-can be useful in case you need to issue backend-dependent raw SQL
-queries in a migration script.
-
-.. sourcecode:: python
-
- dbdriver = config.sources()['system']['db-driver']
- if dbdriver == "sqlserver2005":
- # this is now correctly handled by CW :-)
- sql('ALTER TABLE cw_Xxxx ALTER COLUMN cw_name varchar(64) NOT NULL;')
- commit()
- else: # postgresql
- sync_schema_props_perms(ertype=('Xxxx', 'name', 'String'),
- syncperms=False)
-
-
-Others migration functions
---------------------------
-Those functions are only used for low level operations that could not be
-accomplished otherwise or to repair damaged databases during interactive
-session. They are available in `repository` scripts:
-
-* `sql(sql, args=None, ask_confirm=True)`, executes an arbitrary SQL query on the system source
-* `add_entity_type_table(etype, commit=True)`
-* `add_relation_type_table(rtype, commit=True)`
-* `uninline_relation(rtype, commit=True)`
-
-
-[FIXME] Add explanation on how to use cubicweb-ctl shell
--- a/doc/book/en/devrepo/profiling.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-.. _PROFILING:
-
-Profiling and performance
-=========================
-
-If you feel that one of your pages takes more time than it should to be
-generated, chances are that you're making too many RQL queries. Obviously,
-there are other reasons but experience tends to show this is the first thing to
-track down. Luckily, CubicWeb provides a configuration option to log RQL
-queries. In your ``all-in-one.conf`` file, set the **query-log-file** option::
-
- # web application query log file
- query-log-file=/home/user/myapp-rql.log
-
-Then restart your application, reload your page and stop your application.
-The file ``myapp-rql.log`` now contains the list of RQL queries that were
-executed during your test. It's a simple text file containing lines such as::
-
- Any A WHERE X eid %(x)s, X lastname A {'x': 448} -- (0.002 sec, 0.010 CPU sec)
- Any A WHERE X eid %(x)s, X firstname A {'x': 447} -- (0.002 sec, 0.000 CPU sec)
-
-The structure of each line is::
-
- <RQL QUERY> <QUERY ARGS IF ANY> -- <TIME SPENT>
-
-CubicWeb also provides the **exlog** command to examine and summarize data found
-in such a file:
-
-.. sourcecode:: sh
-
- $ cubicweb-ctl exlog /home/user/myapp-rql.log
- 0.07 50 Any A WHERE X eid %(x)s, X firstname A {}
- 0.05 50 Any A WHERE X eid %(x)s, X lastname A {}
- 0.01 1 Any X,AA ORDERBY AA DESC WHERE E eid %(x)s, E employees X, X modification_date AA {}
- 0.01 1 Any X WHERE X eid %(x)s, X owned_by U, U eid %(u)s {, }
- 0.01 1 Any B,T,P ORDERBY lower(T) WHERE B is Bookmark,B title T, B path P, B bookmarked_by U, U eid %(x)s {}
- 0.01 1 Any A,B,C,D WHERE A eid %(x)s,A name B,A creation_date C,A modification_date D {}
-
-This command sorts and uniquifies queries so that it's easy to see where
-is the hot spot that needs optimization.
-
-Do not neglect to set the **fetch_attrs** attribute you can define in your
-entity classes because it can greatly reduce the number of queries executed (see
-:ref:`FetchAttrs`).
-
-You should also know about the **profile** option in the ``all-in-on.conf``. If
-set, this option will make your application run in an `hotshot`_ session and
-store the results in the specified file.
-
-.. _hotshot: http://docs.python.org/library/hotshot.html#module-hotshot
-
-Last but no least, if you're using the PostgreSQL database backend, VACUUMing
-your database can significantly improve the performance of the queries (by
-updating the statistics used by the query optimizer). Nowadays, this is done
-automatically from time to time, but if you've just imported a large amount of
-data in your db, you will want to vacuum it (with the analyse option on). Read
-the documentation of your database for more information.
--- a/doc/book/en/devrepo/repo/hooks.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,279 +0,0 @@
-.. -*- coding: utf-8 -*-
-.. _hooks:
-
-Hooks and Operations
-====================
-
-.. autodocstring:: cubicweb.server.hook
-
-
-Example using dataflow hooks
-----------------------------
-
-We will use a very simple example to show hooks usage. Let us start with the
-following schema.
-
-.. sourcecode:: python
-
- class Person(EntityType):
- age = Int(required=True)
-
-We would like to add a range constraint over a person's age. Let's write an hook
-(supposing yams can not handle this nativly, which is wrong). It shall be placed
-into `mycube/hooks.py`. If this file were to grow too much, we can easily have a
-`mycube/hooks/... package` containing hooks in various modules.
-
-.. sourcecode:: python
-
- from cubicweb import ValidationError
- from cubicweb.predicates import is_instance
- from cubicweb.server.hook import Hook
-
- class PersonAgeRange(Hook):
- __regid__ = 'person_age_range'
- __select__ = Hook.__select__ & is_instance('Person')
- events = ('before_add_entity', 'before_update_entity')
-
- def __call__(self):
- if 'age' in self.entity.cw_edited:
- if 0 <= self.entity.age <= 120:
- return
- msg = self._cw._('age must be between 0 and 120')
- raise ValidationError(self.entity.eid, {'age': msg})
-
-In our example the base `__select__` is augmented with an `is_instance` selector
-matching the desired entity type.
-
-The `events` tuple is used specify that our hook should be called before the
-entity is added or updated.
-
-Then in the hook's `__call__` method, we:
-
-* check if the 'age' attribute is edited
-* if so, check the value is in the range
-* if not, raise a validation error properly
-
-Now Let's augment our schema with new `Company` entity type with some relation to
-`Person` (in 'mycube/schema.py').
-
-.. sourcecode:: python
-
- class Company(EntityType):
- name = String(required=True)
- boss = SubjectRelation('Person', cardinality='1*')
- subsidiary_of = SubjectRelation('Company', cardinality='*?')
-
-
-We would like to constrain the company's bosses to have a minimum (legal)
-age. Let's write an hook for this, which will be fired when the `boss` relation
-is established (still supposing we could not specify that kind of thing in the
-schema).
-
-.. sourcecode:: python
-
- class CompanyBossLegalAge(Hook):
- __regid__ = 'company_boss_legal_age'
- __select__ = Hook.__select__ & match_rtype('boss')
- events = ('before_add_relation',)
-
- def __call__(self):
- boss = self._cw.entity_from_eid(self.eidto)
- if boss.age < 18:
- msg = self._cw._('the minimum age for a boss is 18')
- raise ValidationError(self.eidfrom, {'boss': msg})
-
-.. Note::
-
- We use the :class:`~cubicweb.server.hook.match_rtype` selector to select the
- proper relation type.
-
- The essential difference with respect to an entity hook is that there is no
- self.entity, but `self.eidfrom` and `self.eidto` hook attributes which
- represent the subject and object **eid** of the relation.
-
-Suppose we want to check that there is no cycle by the `subsidiary_of`
-relation. This is best achieved in an operation since all relations are likely to
-be set at commit time.
-
-.. sourcecode:: python
-
- from cubicweb.server.hook import Hook, DataOperationMixIn, Operation, match_rtype
-
- def check_cycle(self, session, eid, rtype, role='subject'):
- parents = set([eid])
- parent = session.entity_from_eid(eid)
- while parent.related(rtype, role):
- parent = parent.related(rtype, role)[0]
- if parent.eid in parents:
- msg = session._('detected %s cycle' % rtype)
- raise ValidationError(eid, {rtype: msg})
- parents.add(parent.eid)
-
-
- class CheckSubsidiaryCycleOp(Operation):
-
- def precommit_event(self):
- check_cycle(self.session, self.eidto, 'subsidiary_of')
-
-
- class CheckSubsidiaryCycleHook(Hook):
- __regid__ = 'check_no_subsidiary_cycle'
- __select__ = Hook.__select__ & match_rtype('subsidiary_of')
- events = ('after_add_relation',)
-
- def __call__(self):
- CheckSubsidiaryCycleOp(self._cw, eidto=self.eidto)
-
-
-Like in hooks, :exc:`~cubicweb.ValidationError` can be raised in operations. Other
-exceptions are usually programming errors.
-
-In the above example, our hook will instantiate an operation each time the hook
-is called, i.e. each time the `subsidiary_of` relation is set. There is an
-alternative method to schedule an operation from a hook, using the
-:func:`get_instance` class method.
-
-.. sourcecode:: python
-
- from cubicweb.server.hook import set_operation
-
- class CheckSubsidiaryCycleHook(Hook):
- __regid__ = 'check_no_subsidiary_cycle'
- events = ('after_add_relation',)
- __select__ = Hook.__select__ & match_rtype('subsidiary_of')
-
- def __call__(self):
- CheckSubsidiaryCycleOp.get_instance(self._cw).add_data(self.eidto)
-
- class CheckSubsidiaryCycleOp(DataOperationMixIn, Operation):
-
- def precommit_event(self):
- for eid in self.get_data():
- check_cycle(self.session, eid, self.rtype)
-
-
-Here, we call :func:`set_operation` so that we will simply accumulate eids of
-entities to check at the end in a single `CheckSubsidiaryCycleOp`
-operation. Value are stored in a set associated to the
-'subsidiary_cycle_detection' transaction data key. The set initialization and
-operation creation are handled nicely by :func:`set_operation`.
-
-A more realistic example can be found in the advanced tutorial chapter
-:ref:`adv_tuto_security_propagation`.
-
-
-Inter-instance communication
-----------------------------
-
-If your application consists of several instances, you may need some means to
-communicate between them. Cubicweb provides a publish/subscribe mechanism
-using ØMQ_. In order to use it, use
-:meth:`~cubicweb.server.cwzmq.ZMQComm.add_subscription` on the
-`repo.app_instances_bus` object. The `callback` will get the message (as a
-list). A message can be sent by calling
-:meth:`~cubicweb.server.cwzmq.ZMQComm.publish` on `repo.app_instances_bus`.
-The first element of the message is the topic which is used for filtering and
-dispatching messages.
-
-.. _ØMQ: http://www.zeromq.org/
-
-.. sourcecode:: python
-
- class FooHook(hook.Hook):
- events = ('server_startup',)
- __regid__ = 'foo_startup'
-
- def __call__(self):
- def callback(msg):
- self.info('received message: %s', ' '.join(msg))
- self.repo.app_instances_bus.add_subscription('hello', callback)
-
-.. sourcecode:: python
-
- def do_foo(self):
- actually_do_foo()
- self._cw.repo.app_instances_bus.publish(['hello', 'world'])
-
-The `zmq-address-pub` configuration variable contains the address used
-by the instance for sending messages, e.g. `tcp://*:1234`. The
-`zmq-address-sub` variable contains a comma-separated list of addresses
-to listen on, e.g. `tcp://localhost:1234, tcp://192.168.1.1:2345`.
-
-
-Hooks writing tips
-------------------
-
-Reminder
-~~~~~~~~
-
-You should never use the `entity.foo = 42` notation to update an entity. It will
-not do what you expect (updating the database). Instead, use the
-:meth:`~cubicweb.entity.Entity.cw_set` method or direct access to entity's
-:attr:`cw_edited` attribute if you're writing a hook for 'before_add_entity' or
-'before_update_entity' event.
-
-
-How to choose between a before and an after event ?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`before_*` hooks give you access to the old attribute (or relation)
-values. You can also intercept and update edited values in the case of
-entity modification before they reach the database.
-
-Else the question is: should I need to do things before or after the actual
-modification ? If the answer is "it doesn't matter", use an 'after' event.
-
-
-Validation Errors
-~~~~~~~~~~~~~~~~~
-
-When a hook which is responsible to maintain the consistency of the
-data model detects an error, it must use a specific exception named
-:exc:`~cubicweb.ValidationError`. Raising anything but a (subclass of)
-:exc:`~cubicweb.ValidationError` is a programming error. Raising it
-entails aborting the current transaction.
-
-This exception is used to convey enough information up to the user
-interface. Hence its constructor is different from the default Exception
-constructor. It accepts, positionally:
-
-* an entity eid (**not the entity itself**),
-
-* a dict whose keys represent attribute (or relation) names and values
- an end-user facing message (hence properly translated) relating the
- problem.
-
-.. sourcecode:: python
-
- raise ValidationError(earth.eid, {'sea_level': self._cw._('too high'),
- 'temperature': self._cw._('too hot')})
-
-
-Checking for object created/deleted in the current transaction
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In hooks, you can use the
-:meth:`~cubicweb.server.session.Session.added_in_transaction` or
-:meth:`~cubicweb.server.session.Session.deleted_in_transaction` of the session
-object to check if an eid has been created or deleted during the hook's
-transaction.
-
-This is useful to enable or disable some stuff if some entity is being added or
-deleted.
-
-.. sourcecode:: python
-
- if self._cw.deleted_in_transaction(self.eidto):
- return
-
-
-Peculiarities of inlined relations
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Relations which are defined in the schema as `inlined` (see :ref:`RelationType`
-for details) are inserted in the database at the same time as entity attributes.
-
-This may have some side effect, for instance when creating an entity
-and setting an inlined relation in the same rql query, then at
-`before_add_relation` time, the relation will already exist in the
-database (it is otherwise not the case).
--- a/doc/book/en/devrepo/repo/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Repository customization
-++++++++++++++++++++++++
-.. toctree::
- :maxdepth: 1
-
- sessions
- hooks
- notifications
- tasks
-
-
--- a/doc/book/en/devrepo/repo/notifications.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Notifications management
-========================
-
-CubicWeb provides a machinery to ease notifications handling. To use it for a
-notification:
-
-* write a view inheriting from
- :class:`~cubicweb.sobjects.notification.NotificationView`. The usual view api
- is used to generated the email (plain text) content, and additional
- :meth:`~cubicweb.sobjects.notification.NotificationView.subject` and
- :meth:`~cubicweb.sobjects.notification.NotificationView.recipients` methods
- are used to build the email's subject and
- recipients. :class:`NotificationView` provides default implementation for both
- methods.
-
-* write a hook for event that should trigger this notification, select the view
- (without rendering it), and give it to
- :func:`cubicweb.hooks.notification.notify_on_commit` so that the notification
- will be sent if the transaction succeed.
-
-
-.. XXX explain recipient finder and provide example
-
-API details
-~~~~~~~~~~~
-.. autoclass:: cubicweb.sobjects.notification.NotificationView
-.. autofunction:: cubicweb.hooks.notification.notify_on_commit
--- a/doc/book/en/devrepo/repo/sessions.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,318 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Sessions
-========
-
-Sessions are objects linked to an authenticated user. The `Session.new_cnx`
-method returns a new Connection linked to that session.
-
-Connections
-===========
-
-Connections provide the `.execute` method to query the data sources, along with
-`.commit` and `.rollback` methods for transaction management.
-
-Kinds of connections
---------------------
-
-There are two kinds of connections.
-
-* `normal connections` are the most common: they are related to users and
- carry security checks coming with user credentials
-
-* `internal connections` have all the powers; they are also used in only a
- few situations where you don't already have an adequate session at
- hand, like: user authentication, data synchronisation in
- multi-source contexts
-
-Normal connections are typically named `_cw` in most appobjects or
-sometimes just `session`.
-
-Internal connections are available from the `Repository` object and are
-to be used like this:
-
-.. sourcecode:: python
-
- with self.repo.internal_cnx() as cnx:
- do_stuff_with(cnx)
- cnx.commit()
-
-Connections should always be used as context managers, to avoid leaks.
-
-
-Python/RQL API
-~~~~~~~~~~~~~~
-
-The Python API developped to interface with RQL is inspired from the standard db-api,
-but since `execute` returns its results directly, there is no `cursor` concept.
-
-.. sourcecode:: python
-
- execute(rqlstring, args=None, build_descr=True)
-
-:rqlstring: the RQL query to execute (unicode)
-:args: if the query contains substitutions, a dictionary containing the values to use
-
-The `Connection` object owns the methods `commit` and `rollback`. You
-*should never need to use them* during the development of the web
-interface based on the *CubicWeb* framework as it determines the end
-of the transaction depending on the query execution success. They are
-however useful in other contexts such as tests or custom controllers.
-
-.. note::
-
- If a query generates an error related to security (:exc:`Unauthorized`) or to
- integrity (:exc:`ValidationError`), the transaction can still continue but you
- won't be able to commit it, a rollback will be necessary to start a new
- transaction.
-
- Also, a rollback is automatically done if an error occurs during commit.
-
-.. note::
-
- A :exc:`ValidationError` has a `entity` attribute. In CubicWeb,
- this atttribute is set to the entity's eid (not a reference to the
- entity itself).
-
-Executing RQL queries from a view or a hook
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When you're within code of the web interface, the Connection is handled by the
-request object. You should not have to access it directly, but use the
-`execute` method directly available on the request, eg:
-
-.. sourcecode:: python
-
- rset = self._cw.execute(rqlstring, kwargs)
-
-Similarly, on the server side (eg in hooks), there is no request object (since
-you're directly inside the data-server), so you'll have to use the execute method
-of the Connection object.
-
-Proper usage of `.execute`
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's say you want to get T which is in configuration C, this translates to:
-
-.. sourcecode:: python
-
- self._cw.execute('Any T WHERE T in_conf C, C eid %s' % entity.eid)
-
-But it must be written in a syntax that will benefit from the use
-of a cache on the RQL server side:
-
-.. sourcecode:: python
-
- self._cw.execute('Any T WHERE T in_conf C, C eid %(x)s', {'x': entity.eid})
-
-The syntax tree is built once for the "generic" RQL and can be re-used
-with a number of different eids. The rql IN operator is an exception
-to this rule.
-
-.. sourcecode:: python
-
- self._cw.execute('Any T WHERE T in_conf C, C name IN (%s)'
- % ','.join(['foo', 'bar']))
-
-Alternatively, some of the common data related to an entity can be
-obtained from the `entity.related()` method (which is used under the
-hood by the ORM when you use attribute access notation on an entity to
-get a relation. The initial request would then be translated to:
-
-.. sourcecode:: python
-
- entity.related('in_conf', 'object')
-
-Additionally this benefits from the fetch_attrs policy (see :ref:`FetchAttrs`)
-optionally defined on the class element, which says which attributes must be
-also loaded when the entity is loaded through the ORM.
-
-.. _resultset:
-
-The `ResultSet` API
-~~~~~~~~~~~~~~~~~~~
-
-ResultSet instances are a very commonly manipulated object. They have
-a rich API as seen below, but we would like to highlight a bunch of
-methods that are quite useful in day-to-day practice:
-
-* `__str__()` (applied by `print`) gives a very useful overview of both
- the underlying RQL expression and the data inside; unavoidable for
- debugging purposes
-
-* `printable_rql()` returns a well formed RQL expression as a
- string; it is very useful to build views
-
-* `entities()` returns a generator on all entities of the result set
-
-* `get_entity(row, col)` gets the entity at row, col coordinates; one
- of the most used result set methods
-
-.. autoclass:: cubicweb.rset.ResultSet
- :members:
-
-
-Authentication and management of sessions
------------------------------------------
-
-The authentication process is a ballet involving a few dancers:
-
-* through its `get_session` method the top-level application object (the
- `CubicWebPublisher`) will open a session whenever a web request
- comes in; it asks the `session manager` to open a session (giving
- the web request object as context) using `open_session`
-
- * the session manager asks its authentication manager (which is a
- `component`) to authenticate the request (using `authenticate`)
-
- * the authentication manager asks, in order, to its authentication
- information retrievers, a login and an opaque object containing
- other credentials elements (calling `authentication_information`),
- giving the request object each time
-
- * the default retriever (named `LoginPasswordRetriever`)
- will in turn defer login and password fetching to the request
- object (which, depending on the authentication mode (`cookie`
- or `http`), will do the appropriate things and return a login
- and a password)
-
- * the authentication manager, on success, asks the `Repository`
- object to connect with the found credentials (using `connect`)
-
- * the repository object asks authentication to all of its
- sources which support the `CWUser` entity with the given
- credentials; when successful it can build the cwuser entity,
- from which a regular `Session` object is made; it returns the
- session id
-
- * the source in turn will delegate work to an authentifier
- class that defines the ultimate `authenticate` method (for
- instance the native source will query the database against
- the provided credentials)
-
- * the authentication manager, on success, will call back _all_
- retrievers with `authenticated` and return its authentication
- data (on failure, it will try the anonymous login or, if the
- configuration forbids it, raise an `AuthenticationError`)
-
-Writing authentication plugins
-------------------------------
-
-Sometimes CubicWeb's out-of-the-box authentication schemes (cookie and
-http) are not sufficient. Nowadays there is a plethora of such schemes
-and the framework cannot provide them all, but as the sequence above
-shows, it is extensible.
-
-Two levels have to be considered when writing an authentication
-plugin: the web client and the repository.
-
-We invented a scenario where it makes sense to have a new plugin in
-each side: some middleware will do pre-authentication and under the
-right circumstances add a new HTTP `x-foo-user` header to the query
-before it reaches the CubicWeb instance. For a concrete example of
-this, see the `trustedauth`_ cube.
-
-.. _`trustedauth`: http://www.cubicweb.org/project/cubicweb-trustedauth
-
-Repository authentication plugins
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-On the repository side, it is possible to register a source
-authentifier using the following kind of code:
-
-.. sourcecode:: python
-
- from cubicweb.server.sources import native
-
- class FooAuthentifier(native.LoginPasswordAuthentifier):
- """ a source authentifier plugin
- if 'foo' in authentication information, no need to check
- password
- """
- auth_rql = 'Any X WHERE X is CWUser, X login %(login)s'
-
- def authenticate(self, session, login, **kwargs):
- """return CWUser eid for the given login
- if this account is defined in this source,
- else raise `AuthenticationError`
- """
- session.debug('authentication by %s', self.__class__.__name__)
- if 'foo' not in kwargs:
- return super(FooAuthentifier, self).authenticate(session, login, **kwargs)
- try:
- rset = session.execute(self.auth_rql, {'login': login})
- return rset[0][0]
- except Exception, exc:
- session.debug('authentication failure (%s)', exc)
- raise AuthenticationError('foo user is unknown to us')
-
-Since repository authentifiers are not appobjects, we have to register
-them through a `server_startup` hook.
-
-.. sourcecode:: python
-
- class ServerStartupHook(hook.Hook):
- """ register the foo authenticator """
- __regid__ = 'fooauthenticatorregisterer'
- events = ('server_startup',)
-
- def __call__(self):
- self.debug('registering foo authentifier')
- self.repo.system_source.add_authentifier(FooAuthentifier())
-
-Web authentication plugins
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. sourcecode:: python
-
- class XFooUserRetriever(authentication.LoginPasswordRetriever):
- """ authenticate by the x-foo-user http header
- or just do normal login/password authentication
- """
- __regid__ = 'x-foo-user'
- order = 0
-
- def authentication_information(self, req):
- """retrieve authentication information from the given request, raise
- NoAuthInfo if expected information is not found
- """
- self.debug('web authenticator building auth info')
- try:
- login = req.get_header('x-foo-user')
- if login:
- return login, {'foo': True}
- else:
- return super(XFooUserRetriever, self).authentication_information(self, req)
- except Exception, exc:
- self.debug('web authenticator failed (%s)', exc)
- raise authentication.NoAuthInfo()
-
- def authenticated(self, retriever, req, cnx, login, authinfo):
- """callback when return authentication information have opened a
- repository connection successfully. Take care req has no session
- attached yet, hence req.execute isn't available.
-
- Here we set a flag on the request to indicate that the user is
- foo-authenticated. Can be used by a selector
- """
- self.debug('web authenticator running post authentication callback')
- cnx.foo_user = authinfo.get('foo')
-
-In the `authenticated` method we add (in an admitedly slightly hackish
-way) an attribute to the connection object. This, in turn, can be used
-to build a selector dispatching on the fact that the user was
-preauthenticated or not.
-
-.. sourcecode:: python
-
- @objectify_selector
- def foo_authenticated(cls, req, rset=None, **kwargs):
- if hasattr(req.cnx, 'foo_user') and req.foo_user:
- return 1
- return 0
-
-Full Session and Connection API
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. autoclass:: cubicweb.server.session.Session
-.. autoclass:: cubicweb.server.session.Connection
--- a/doc/book/en/devrepo/repo/tasks.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tasks
-=========
-
-[WRITE ME]
-
-* repository tasks
-
--- a/doc/book/en/devrepo/testing.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,559 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Tests
-=====
-
-Unit tests
-----------
-
-The *CubicWeb* framework provides the
-:class:`cubicweb.devtools.testlib.CubicWebTC` test base class .
-
-Tests shall be put into the mycube/test directory. Additional test
-data shall go into mycube/test/data.
-
-It is much advised to write tests concerning entities methods,
-actions, hooks and operations, security. The
-:class:`~cubicweb.devtools.testlib.CubicWebTC` base class has
-convenience methods to help test all of this.
-
-In the realm of views, automatic tests check that views are valid
-XHTML. See :ref:`automatic_views_tests` for details.
-
-Most unit tests need a live database to work against. This is achieved
-by CubicWeb using automatically sqlite (bundled with Python, see
-http://docs.python.org/library/sqlite3.html) as a backend.
-
-The database is stored in the mycube/test/tmpdb,
-mycube/test/tmpdb-template files. If it does not (yet) exist, it will
-be built automatically when the test suite starts.
-
-.. warning::
-
- Whenever the schema changes (new entities, attributes, relations)
- one must delete these two files. Changes concerned only with entity
- or relation type properties (constraints, cardinalities,
- permissions) and generally dealt with using the
- `sync_schema_props_perms()` function of the migration environment do
- not need a database regeneration step.
-
-.. _hook_test:
-
-Unit test by example
-````````````````````
-
-We start with an example extracted from the keyword cube (available
-from http://www.cubicweb.org/project/cubicweb-keyword).
-
-.. sourcecode:: python
-
- from cubicweb.devtools.testlib import CubicWebTC
- from cubicweb import ValidationError
-
- class ClassificationHooksTC(CubicWebTC):
-
- def setup_database(self):
- with self.admin_access.repo_cnx() as cnx:
- group_etype = cnx.find('CWEType', name='CWGroup').one()
- c1 = cnx.create_entity('Classification', name=u'classif1',
- classifies=group_etype)
- user_etype = cnx.find('CWEType', name='CWUser').one()
- c2 = cnx.create_entity('Classification', name=u'classif2',
- classifies=user_etype)
- self.kw1eid = cnx.create_entity('Keyword', name=u'kwgroup', included_in=c1).eid
- cnx.commit()
-
- def test_cannot_create_cycles(self):
- with self.admin_access.repo_cnx() as cnx:
- kw1 = cnx.entity_from_eid(self.kw1eid)
- # direct obvious cycle
- with self.assertRaises(ValidationError):
- kw1.cw_set(subkeyword_of=kw1)
- cnx.rollback()
- # testing indirect cycles
- kw3 = cnx.execute('INSERT Keyword SK: SK name "kwgroup2", SK included_in C, '
- 'SK subkeyword_of K WHERE C name "classif1", K eid %(k)s'
- {'k': kw1}).get_entity(0,0)
- kw3.cw_set(reverse_subkeyword_of=kw1)
- self.assertRaises(ValidationError, cnx.commit)
-
-The test class defines a :meth:`setup_database` method which populates the
-database with initial data. Each test of the class runs with this
-pre-populated database.
-
-The test case itself checks that an Operation does its job of
-preventing cycles amongst Keyword entities.
-
-The `create_entity` method of connection (or request) objects allows
-to create an entity. You can link this entity to other entities, by
-specifying as argument, the relation name, and the entity to link, as
-value. In the above example, the `Classification` entity is linked to
-a `CWEtype` via the relation `classifies`. Conversely, if you are
-creating a `CWEtype` entity, you can link it to a `Classification`
-entity, by adding `reverse_classifies` as argument.
-
-.. note::
-
- the :meth:`commit` method is not called automatically. You have to
- call it explicitly if needed (notably to test operations). It is a
- good practice to regenerate entities with :meth:`entity_from_eid`
- after a commit to avoid request cache effects.
-
-You can see an example of security tests in the
-:ref:`adv_tuto_security`.
-
-It is possible to have these tests run continuously using `apycot`_.
-
-.. _apycot: http://www.cubicweb.org/project/apycot
-
-.. _securitytest:
-
-Managing connections or users
-+++++++++++++++++++++++++++++
-
-Since unit tests are done with the SQLITE backend and this does not
-support multiple connections at a time, you must be careful when
-simulating security, changing users.
-
-By default, tests run with a user with admin privileges. Connections
-using these credentials are accessible through the `admin_access` object
-of the test classes.
-
-The `repo_cnx()` method returns a connection object that can be used as a
-context manager:
-
-.. sourcecode:: python
-
- # admin_access is a pre-cooked session wrapping object
- # it is built with:
- # self.admin_access = self.new_access('admin')
- with self.admin_access.repo_cnx() as cnx:
- cnx.execute(...)
- self.create_user(cnx, login='user1')
- cnx.commit()
-
- user1access = self.new_access('user1')
- with user1access.web_request() as req:
- req.execute(...)
- req.cnx.commit()
-
-On exit of the context manager, a rollback is issued, which releases
-the connection. Don't forget to issue the `cnx.commit()` calls!
-
-.. warning::
-
- Do not use references kept to the entities created with a
- connection from another one!
-
-Email notifications tests
-`````````````````````````
-
-When running tests, potentially generated e-mails are not really sent
-but are found in the list `MAILBOX` of module
-:mod:`cubicweb.devtools.testlib`.
-
-You can test your notifications by analyzing the contents of this list, which
-contains objects with two attributes:
-
-* `recipients`, the list of recipients
-* `msg`, email.Message object
-
-Let us look at a simple example from the ``blog`` cube.
-
-.. sourcecode:: python
-
- from cubicweb.devtools.testlib import CubicWebTC, MAILBOX
-
- class BlogTestsCubicWebTC(CubicWebTC):
- """test blog specific behaviours"""
-
- def test_notifications(self):
- with self.admin_access.web_request() as req:
- cubicweb_blog = req.create_entity('Blog', title=u'cubicweb',
- description=u'cubicweb is beautiful')
- blog_entry_1 = req.create_entity('BlogEntry', title=u'hop',
- content=u'cubicweb hop')
- blog_entry_1.cw_set(entry_of=cubicweb_blog)
- blog_entry_2 = req.create_entity('BlogEntry', title=u'yes',
- content=u'cubicweb yes')
- blog_entry_2.cw_set(entry_of=cubicweb_blog)
- self.assertEqual(len(MAILBOX), 0)
- req.cnx.commit()
- self.assertEqual(len(MAILBOX), 2)
- mail = MAILBOX[0]
- self.assertEqual(mail.subject, '[data] hop')
- mail = MAILBOX[1]
- self.assertEqual(mail.subject, '[data] yes')
-
-Visible actions tests
-`````````````````````
-
-It is easy to write unit tests to test actions which are visible to
-a user or to a category of users. Let's take an example in the
-`conference cube`_.
-
-.. _`conference cube`: http://www.cubicweb.org/project/cubicweb-conference
-.. sourcecode:: python
-
- class ConferenceActionsTC(CubicWebTC):
-
- def setup_database(self):
- with self.admin_access.repo_cnx() as cnx:
- self.confeid = cnx.create_entity('Conference',
- title=u'my conf',
- url_id=u'conf',
- start_on=date(2010, 1, 27),
- end_on = date(2010, 1, 29),
- call_open=True,
- reverse_is_chair_at=chair,
- reverse_is_reviewer_at=reviewer).eid
-
- def test_admin(self):
- with self.admin_access.web_request() as req:
- rset = req.find('Conference').one()
- self.assertListEqual(self.pactions(req, rset),
- [('workflow', workflow.WorkflowActions),
- ('edit', confactions.ModifyAction),
- ('managepermission', actions.ManagePermissionsAction),
- ('addrelated', actions.AddRelatedActions),
- ('delete', actions.DeleteAction),
- ('generate_badge_action', badges.GenerateBadgeAction),
- ('addtalkinconf', confactions.AddTalkInConferenceAction)
- ])
- self.assertListEqual(self.action_submenu(req, rset, 'addrelated'),
- [(u'add Track in_conf Conference object',
- u'http://testing.fr/cubicweb/add/Track'
- u'?__linkto=in_conf%%3A%(conf)s%%3Asubject&'
- u'__redirectpath=conference%%2Fconf&'
- u'__redirectvid=' % {'conf': self.confeid}),
- ])
-
-You just have to execute a rql query corresponding to the view you want to test,
-and to compare the result of
-:meth:`~cubicweb.devtools.testlib.CubicWebTC.pactions` with the list of actions
-that must be visible in the interface. This is a list of tuples. The first
-element is the action's `__regid__`, the second the action's class.
-
-To test actions in a submenu, you just have to test the result of
-:meth:`~cubicweb.devtools.testlib.CubicWebTC.action_submenu` method. The last
-parameter of the method is the action's category. The result is a list of
-tuples. The first element is the action's title, and the second element the
-action's url.
-
-
-.. _automatic_views_tests:
-
-Automatic views testing
------------------------
-
-This is done automatically with the :class:`cubicweb.devtools.testlib.AutomaticWebTest`
-class. At cube creation time, the mycube/test/test_mycube.py file
-contains such a test. The code here has to be uncommented to be
-usable, without further modification.
-
-The ``auto_populate`` method uses a smart algorithm to create
-pseudo-random data in the database, thus enabling the views to be
-invoked and tested.
-
-Depending on the schema, hooks and operations constraints, it is not
-always possible for the automatic auto_populate to proceed.
-
-It is possible of course to completely redefine auto_populate. A
-lighter solution is to give hints (fill some class attributes) about
-what entities and relations have to be skipped by the auto_populate
-mechanism. These are:
-
-* `no_auto_populate`, may contain a list of entity types to skip
-* `ignored_relations`, may contain a list of relation types to skip
-* `application_rql`, may contain a list of rql expressions that
- auto_populate cannot guess by itself; these must yield resultsets
- against which views may be selected.
-
-.. warning::
-
- Take care to not let the imported `AutomaticWebTest` in your test module
- namespace, else both your subclass *and* this parent class will be run.
-
-Cache heavy database setup
--------------------------------
-
-Some test suites require a complex setup of the database that takes
-seconds (or even minutes) to complete. Doing the whole setup for each
-individual test makes the whole run very slow. The ``CubicWebTC``
-class offer a simple way to prepare a specific database once for
-multiple tests. The `test_db_id` class attribute of your
-``CubicWebTC`` subclass must be set to a unique identifier and the
-:meth:`pre_setup_database` class method must build the cached content. As
-the :meth:`pre_setup_database` method is not garanteed to be called
-every time a test method is run, you must not set any class attribute
-to be used during test *there*. Databases for each `test_db_id` are
-automatically created if not already in cache. Clearing the cache is
-up to the user. Cache files are found in the :file:`data/database`
-subdirectory of your test directory.
-
-.. warning::
-
- Take care to always have the same :meth:`pre_setup_database`
- function for all classes with a given `test_db_id` otherwise your
- tests will have unpredictable results depending on the first
- encountered one.
-
-
-Testing on a real-life database
--------------------------------
-
-The ``CubicWebTC`` class uses the `cubicweb.devtools.ApptestConfiguration`
-configuration class to setup its testing environment (database driver,
-user password, application home, and so on). The `cubicweb.devtools`
-module also provides a `RealDatabaseConfiguration`
-class that will read a regular cubicweb sources file to fetch all
-this information but will also prevent the database to be initalized
-and reset between tests.
-
-For a test class to use a specific configuration, you have to set
-the `_config` class attribute on the class as in:
-
-.. sourcecode:: python
-
- from cubicweb.devtools import RealDatabaseConfiguration
- from cubicweb.devtools.testlib import CubicWebTC
-
- class BlogRealDatabaseTC(CubicWebTC):
- _config = RealDatabaseConfiguration('blog',
- sourcefile='/path/to/realdb_sources')
-
- def test_blog_rss(self):
- with self.admin_access.web_request() as req:
- rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, '
- 'B created_by U, U login "logilab", B creation_date D')
- self.view('rss', rset, req=req)
-
-
-Testing with other cubes
-------------------------
-
-Sometimes a small component cannot be tested all by itself, so one
-needs to specify other cubes to be used as part of the the unit test
-suite. This is handled by the ``bootstrap_cubes`` file located under
-``mycube/test/data``. One example from the `preview` cube::
-
- card, file, preview
-
-The format is:
-
-* possibly several empy lines or lines starting with ``#`` (comment lines)
-* one line containing a comma-separated list of cube names.
-
-It is also possible to add a ``schema.py`` file in
-``mycube/test/data``, which will be used by the testing framework,
-therefore making new entity types and relations available to the
-tests.
-
-Literate programming
---------------------
-
-CubicWeb provides some literate programming capabilities. The :ref:`cubicweb-ctl`
-`shell` command accepts different file formats. If your file ends with `.txt`
-or `.rst`, the file will be parsed by :mod:`doctest.testfile` with CubicWeb's
-:ref:`migration` API enabled in it.
-
-Create a `scenario.txt` file in the `test/` directory and fill with some content.
-Refer to the :mod:`doctest.testfile` `documentation`_.
-
-.. _documentation: http://docs.python.org/library/doctest.html
-
-Then, you can run it directly by::
-
- $ cubicweb-ctl shell <cube_instance> test/scenario.txt
-
-When your scenario file is ready, put it in a new test case to be able to run
-it automatically.
-
-.. sourcecode:: python
-
- from os.path import dirname, join
- from logilab.common.testlib import unittest_main
- from cubicweb.devtools.testlib import CubicWebTC
-
- class AcceptanceTC(CubicWebTC):
-
- def test_scenario(self):
- self.assertDocTestFile(join(dirname(__file__), 'scenario.txt'))
-
- if __name__ == '__main__':
- unittest_main()
-
-Skipping a scenario
-```````````````````
-
-If you want to set up initial conditions that you can't put in your unit test
-case, you have to use a :exc:`KeyboardInterrupt` exception only because of the
-way :mod:`doctest` module will catch all the exceptions internally.
-
- >>> if condition_not_met:
- ... raise KeyboardInterrupt('please, check your fixture.')
-
-Passing paramaters
-``````````````````
-Using extra arguments to parametrize your scenario is possible by prepending them
-by double dashes.
-
-Please refer to the `cubicweb-ctl shell --help` usage.
-
-.. important::
- Your scenario file must be utf-8 encoded.
-
-Test APIS
----------
-
-Using Pytest
-````````````
-
-The `pytest` utility (shipping with `logilab-common`_, which is a
-mandatory dependency of CubicWeb) extends the Python unittest
-functionality and is the preferred way to run the CubicWeb test
-suites. Bare unittests also work the usual way.
-
-.. _logilab-common: http://www.logilab.org/project/logilab-common
-
-To use it, you may:
-
-* just launch `pytest` in your cube to execute all tests (it will
- discover them automatically)
-* launch `pytest unittest_foo.py` to execute one test file
-* launch `pytest unittest_foo.py bar` to execute all test methods and
- all test cases whose name contains `bar`
-
-Additionally, the `-x` option tells pytest to exit at the first error
-or failure. The `-i` option tells pytest to drop into pdb whenever an
-exception occurs in a test.
-
-When the `-x` option has been used and the run stopped on a test, it
-is possible, after having fixed the test, to relaunch pytest with the
-`-R` option to tell it to start testing again from where it previously
-failed.
-
-Using the `TestCase` base class
-```````````````````````````````
-
-The base class of CubicWebTC is logilab.common.testlib.TestCase, which
-provides a lot of convenient assertion methods.
-
-.. autoclass:: logilab.common.testlib.TestCase
- :members:
-
-CubicWebTC API
-``````````````
-.. autoclass:: cubicweb.devtools.testlib.CubicWebTC
- :members:
-
-
-What you need to know about request and session
------------------------------------------------
-
-.. image:: ../images/request_session.png
-
-First, remember to think that some code run on a client side, some
-other on the repository side. More precisely:
-
-* client side: web interface, raw repoapi connection (cubicweb-ctl shell for
- instance);
-
-* repository side: RQL query execution, that may trigger hooks and operation.
-
-The client interacts with the repository through a repoapi connection.
-
-
-.. note::
-
- These distinctions are going to disappear in cubicweb 3.21 (if not
- before).
-
-A repoapi connection is tied to a session in the repository. The connection and
-request objects are inaccessible from repository code / the session object is
-inaccessible from client code (theoretically at least).
-
-The web interface provides a request class. That `request` object provides
-access to all cubicweb resources, eg:
-
-* the registry (which itself provides access to the schema and the
- configuration);
-
-* an underlying repoapi connection (when using req.execute, you actually call the
- repoapi);
-
-* other specific resources depending on the client type (url generation according
- to base url, form parameters, etc.).
-
-
-A `session` provides an api similar to a request regarding RQL execution and
-access to global resources (registry and all), but also has the following
-responsibilities:
-
-* handle transaction data, that will live during the time of a single
- transaction. This includes the database connections that will be used to
- execute RQL queries.
-
-* handle persistent data that may be used across different (web) requests
-
-* security and hooks control (not possible through a request)
-
-
-The `_cw` attribute
-```````````````````
-The `_cw` attribute available on every application object provides access to all
-cubicweb resources, i.e.:
-
-- For code running on the client side (eg web interface view), `_cw` is a request
- instance.
-
-- For code running on the repository side (hooks and operation), `_cw` is a
- Connection or Session instance.
-
-
-Beware some views may be called with a session (e.g. notifications) or with a
-request.
-
-
-Request, session and transaction
-````````````````````````````````
-
-In the web interface, an HTTP request is handled by a single request, which will
-be thrown away once the response is sent.
-
-The web publisher handles the transaction:
-
-* commit / rollback is done automatically
-
-* you should not commit / rollback explicitly, except if you really
- need it
-
-Let's detail the process:
-
-1. an incoming RQL query comes from a client to the web stack
-
-2. the web stack opens an authenticated database connection for the
- request, which is associated to a user session
-
-3. the query is executed (through the repository connection)
-
-4. this query may trigger hooks. Hooks and operations may execute some rql queries
- through `cnx.execute`.
-
-5. the repository gets the result of the query in 1. If it was a RQL read query,
- the database connection is released. If it was a write query, the connection
- is then tied to the session until the transaction is commited or rolled back.
-
-6. results are sent back to the client
-
-This implies several things:
-
-* when using a request, or code executed in hooks, this database
- connection handling is totally transparent
-
-* however, take care when writing tests: you are usually faking /
- testing both the server and the client side, so you have to decide
- when to use RepoAccess.client_cnx or RepoAccess.repo_cnx. Ask
- yourself "where will the code I want to test be running, client or
- repository side?". The response is usually: use a repo (since the
- "client connection" concept is going away in a couple of releases).
--- a/doc/book/en/devrepo/vreg.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-The Registry, selectors and application objects
-===============================================
-
-This chapter deals with some of the core concepts of the |cubicweb| framework
-which make it different from other frameworks (and maybe not easy to
-grasp at a first glance). To be able to do advanced development with
-|cubicweb| you need a good understanding of what is explained below.
-
-This chapter goes deep into details. You don't have to remember them
-all but keep it in mind so you can go back there later.
-
-An overview of AppObjects, the VRegistry and Selectors is given in the
-:ref:`VRegistryIntro` chapter.
-
-.. autodocstring:: cubicweb.cwvreg
-.. autodocstring:: cubicweb.predicates
-.. automodule:: cubicweb.appobject
-
-Base predicates
----------------
-
-Predicates are scoring functions that are called by the registry to tell whenever
-an appobject can be selected in a given context. Predicates may be chained
-together using operators to build a selector. A selector is the glue that tie
-views to the data model or whatever input context. Using them appropriately is an
-essential part of the construction of well behaved cubes.
-
-Of course you may have to write your own set of predicates as your needs grows
-and you get familiar with the framework (see :ref:`CustomPredicates`).
-
-Here is a description of generic predicates provided by CubicWeb that should suit
-most of your needs.
-
-Bare predicates
-~~~~~~~~~~~~~~~
-Those predicates are somewhat dumb, which doesn't mean they're not (very) useful.
-
-.. autoclass:: cubicweb.appobject.yes
-.. autoclass:: cubicweb.predicates.match_kwargs
-.. autoclass:: cubicweb.predicates.appobject_selectable
-.. autoclass:: cubicweb.predicates.adaptable
-.. autoclass:: cubicweb.predicates.configuration_values
-
-
-Result set predicates
-~~~~~~~~~~~~~~~~~~~~~
-Those predicates are looking for a result set in the context ('rset' argument or
-the input context) and match or not according to its shape. Some of these
-predicates have different behaviour if a particular cell of the result set is
-specified using 'row' and 'col' arguments of the input context or not.
-
-.. autoclass:: cubicweb.predicates.none_rset
-.. autoclass:: cubicweb.predicates.any_rset
-.. autoclass:: cubicweb.predicates.nonempty_rset
-.. autoclass:: cubicweb.predicates.empty_rset
-.. autoclass:: cubicweb.predicates.one_line_rset
-.. autoclass:: cubicweb.predicates.multi_lines_rset
-.. autoclass:: cubicweb.predicates.multi_columns_rset
-.. autoclass:: cubicweb.predicates.paginated_rset
-.. autoclass:: cubicweb.predicates.sorted_rset
-.. autoclass:: cubicweb.predicates.one_etype_rset
-.. autoclass:: cubicweb.predicates.multi_etypes_rset
-
-
-Entity predicates
-~~~~~~~~~~~~~~~~~
-Those predicates are looking for either an `entity` argument in the input context,
-or entity found in the result set ('rset' argument or the input context) and
-match or not according to entity's (instance or class) properties.
-
-.. autoclass:: cubicweb.predicates.non_final_entity
-.. autoclass:: cubicweb.predicates.is_instance
-.. autoclass:: cubicweb.predicates.score_entity
-.. autoclass:: cubicweb.predicates.rql_condition
-.. autoclass:: cubicweb.predicates.relation_possible
-.. autoclass:: cubicweb.predicates.partial_relation_possible
-.. autoclass:: cubicweb.predicates.has_related_entities
-.. autoclass:: cubicweb.predicates.partial_has_related_entities
-.. autoclass:: cubicweb.predicates.has_permission
-.. autoclass:: cubicweb.predicates.has_add_permission
-.. autoclass:: cubicweb.predicates.has_mimetype
-.. autoclass:: cubicweb.predicates.is_in_state
-.. autofunction:: cubicweb.predicates.on_fire_transition
-
-
-Logged user predicates
-~~~~~~~~~~~~~~~~~~~~~~
-Those predicates are looking for properties of the user issuing the request.
-
-.. autoclass:: cubicweb.predicates.match_user_groups
-
-
-Web request predicates
-~~~~~~~~~~~~~~~~~~~~~~
-Those predicates are looking for properties of *web* request, they can not be
-used on the data repository side.
-
-.. autoclass:: cubicweb.predicates.no_cnx
-.. autoclass:: cubicweb.predicates.anonymous_user
-.. autoclass:: cubicweb.predicates.authenticated_user
-.. autoclass:: cubicweb.predicates.match_form_params
-.. autoclass:: cubicweb.predicates.match_search_state
-.. autoclass:: cubicweb.predicates.match_context_prop
-.. autoclass:: cubicweb.predicates.match_context
-.. autoclass:: cubicweb.predicates.match_view
-.. autoclass:: cubicweb.predicates.primary_view
-.. autoclass:: cubicweb.predicates.contextual
-.. autoclass:: cubicweb.predicates.specified_etype_implements
-.. autoclass:: cubicweb.predicates.attribute_edited
-.. autoclass:: cubicweb.predicates.match_transition
-
-
-Other predicates
-~~~~~~~~~~~~~~~~
-.. autoclass:: cubicweb.predicates.match_exception
-.. autoclass:: cubicweb.predicates.debug_mode
-
-You'll also find some other (very) specific predicates hidden in other modules
-than :mod:`cubicweb.predicates`.
--- a/doc/book/en/devweb/ajax.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-.. _ajax:
-
-Ajax
-----
-
-CubicWeb provides a few helpers to facilitate *javascript <-> python* communications.
-
-You can, for instance, register some python functions that will become
-callable from javascript through ajax calls. All the ajax URLs are handled
-by the :class:`cubicweb.web.views.ajaxcontroller.AjaxController` controller.
-
-.. automodule:: cubicweb.web.views.ajaxcontroller
--- a/doc/book/en/devweb/controllers.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-.. _controllers:
-
-Controllers
------------
-
-Overview
-++++++++
-
-Controllers are responsible for taking action upon user requests
-(loosely following the terminology of the MVC meta pattern).
-
-The following controllers are provided out-of-the box in CubicWeb. We
-list them by category. They are all defined in
-(:mod:`cubicweb.web.views.basecontrollers`).
-
-`Browsing`:
-
-* the View controller is associated with most browsing actions within a
- CubicWeb application: it always instantiates a
- :ref:`the_main_template_layout` and lets the ResultSet/Views dispatch system
- build up the whole content; it handles :exc:`ObjectNotFound` and
- :exc:`NoSelectableObject` errors that may bubble up to its entry point, in an
- end-user-friendly way (but other programming errors will slip through)
-
-* the JSonpController is a wrapper around the ``ViewController`` that
- provides jsonp_ services. Padding can be specified with the
- ``callback`` request parameter. Only *jsonexport* / *ejsonexport*
- views can be used. If another ``vid`` is specified, it will be
- ignored and replaced by *jsonexport*. Request is anonymized
- to avoid returning sensitive data and reduce the risks of CSRF attacks;
-
-* the Login/Logout controllers make effective user login or logout
- requests
-
-
-.. _jsonp: http://en.wikipedia.org/wiki/JSONP
-
-`Edition`:
-
-* the Edit controller (see :ref:`edit_controller`) handles CRUD
- operations in response to a form being submitted; it works in close
- association with the Forms, to which it delegates some of the work
-
-* the ``Form validator controller`` provides form validation from Ajax
- context, using the Edit controller, to implement the classic form
- handling loop (user edits, hits `submit/apply`, validation occurs
- server-side by way of the Form validator controller, and the UI is
- decorated with failure information, either global or per-field ,
- until it is valid)
-
-`Other`:
-
-* the ``SendMail controller`` (web/views/basecontrollers.py) is reponsible
- for outgoing email notifications
-
-* the MailBugReport controller (web/views/basecontrollers.py) allows
- to quickly have a `reportbug` feature in one's application
-
-* the :class:`cubicweb.web.views.ajaxcontroller.AjaxController`
- (:mod:`cubicweb.web.views.ajaxcontroller`) provides
- services for Ajax calls, typically using JSON as a serialization format
- for input, and sometimes using either JSON or XML for output. See
- :ref:`ajax` chapter for more information.
-
-
-Registration
-++++++++++++
-
-All controllers (should) live in the 'controllers' namespace within
-the global registry.
-
-Concrete controllers
-++++++++++++++++++++
-
-Most API details should be resolved by source code inspection, as the
-various controllers have differing goals. See for instance the
-:ref:`edit_controller` chapter.
-
-:mod:`cubicweb.web.controller` contains the top-level abstract
-Controller class and its unimplemented entry point
-`publish(rset=None)` method.
-
-A handful of helpers are also provided there:
-
-* process_rql builds a result set from an rql query typically issued
- from the browser (and available through _cw.form['rql'])
-
-* validate_cache will force cache validation handling with respect to
- the HTTP Cache directives (that were typically originally issued
- from a previous server -> client response); concrete Controller
- implementations dealing with HTTP (thus, for instance, not the
- SendMail controller) may very well call this in their publication
- process.
--- a/doc/book/en/devweb/css.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-CSS Stylesheet
----------------
-Conventions
-~~~~~~~~~~~
-
-.. XXX external_resources variable
-.. naming convention
-.. request.add_css
-
-
-Extending / overriding existing styles
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-We cannot modify the order in which the application is reading the CSS. In
-the case we want to create new CSS style, the best is to define it a in a new
-CSS located under ``myapp/data/`` and use those new styles while writing
-customized views and templates.
-
-If you want to modify an existing CSS styling property, you will have to use
-``!important`` declaration to override the existing property. The application
-apply a higher priority on the default CSS and you can not change that.
-Customized CSS will not be read first.
-
-
-CubicWeb stylesheets
-~~~~~~~~~~~~~~~~~~~~
-
-.. XXX explain diffenrent files and main classes
--- a/doc/book/en/devweb/edition/dissection.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,316 +0,0 @@
-
-.. _form_dissection:
-
-Dissection of an entity form
-----------------------------
-
-This is done (again) with a vanilla instance of the `tracker`_
-cube. We will populate the database with a bunch of entities and see
-what kind of job the automatic entity form does.
-
-.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker
-
-Populating the database
-~~~~~~~~~~~~~~~~~~~~~~~
-
-We should start by setting up a bit of context: a project with two
-unpublished versions, and a ticket linked to the project and the first
-version.
-
-.. sourcecode:: python
-
- >>> p = rql('INSERT Project P: P name "cubicweb"')
- >>> for num in ('0.1.0', '0.2.0'):
- ... rql('INSERT Version V: V num "%s", V version_of P WHERE P eid %%(p)s' % num, {'p': p[0][0]})
- ...
- <resultset 'INSERT Version V: V num "0.1.0", V version_of P WHERE P eid %(p)s' (1 rows): [765L] (('Version',))>
- <resultset 'INSERT Version V: V num "0.2.0", V version_of P WHERE P eid %(p)s' (1 rows): [766L] (('Version',))>
- >>> t = rql('INSERT Ticket T: T title "let us write more doc", T done_in V, '
- 'T concerns P WHERE V num "0.1.0"', P eid %(p)s', {'p': p[0][0]})
- >>> commit()
-
-Now let's see what the edition form builds for us.
-
-.. sourcecode:: python
-
- >>> cnx.use_web_compatible_requests('http://fakeurl.com')
- >>> req = cnx.request()
- >>> form = req.vreg['forms'].select('edition', req, rset=rql('Ticket T'))
- >>> html = form.render()
-
-.. note::
-
- In order to play interactively with web side application objects, we have to
- cheat a bit to have request object that will looks like HTTP request object, by
- calling :meth:`use_web_compatible_requests()` on the connection.
-
-This creates an automatic entity form. The ``.render()`` call yields
-an html (unicode) string. The html output is shown below (with
-internal fieldset omitted).
-
-Looking at the html output
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The form enveloppe
-''''''''''''''''''
-
-.. sourcecode:: html
-
- <div class="iformTitle"><span>main informations</span></div>
- <div class="formBody">
- <form action="http://crater:9999/validateform" method="post" enctype="application/x-www-form-urlencoded"
- id="entityForm" onsubmit="return freezeFormButtons('entityForm');"
- class="entityForm" target="eformframe">
- <div id="progress">validating...</div>
- <fieldset>
- <input name="__form_id" type="hidden" value="edition" />
- <input name="__errorurl" type="hidden" value="http://perdu.com#entityForm" />
- <input name="__domid" type="hidden" value="entityForm" />
- <input name="__type:763" type="hidden" value="Ticket" />
- <input name="eid" type="hidden" value="763" />
- <input name="__maineid" type="hidden" value="763" />
- <input name="_cw_edited_fields:763" type="hidden"
- value="concerns-subject,done_in-subject,priority-subject,type-subject,title-subject,description-subject,__type,_cw_generic_field" />
- ...
- </fieldset>
- <iframe width="0px" height="0px" name="eformframe" id="eformframe" src="javascript: void(0);"></iframe>
- </form>
- </div>
-
-The main fieldset encloses a set of hidden fields containing various
-metadata, that will be used by the `edit controller` to process it
-back correctly.
-
-The `freezeFormButtons(...)` javascript callback defined on the
-``onlick`` event of the form element prevents accidental multiple
-clicks in a row.
-
-The ``action`` of the form is mapped to the ``validateform`` controller
-(situated in :mod:`cubicweb.web.views.basecontrollers`).
-
-A full explanation of the validation loop is given in
-:ref:`validation_process`.
-
-.. _attributes_section:
-
-The attributes section
-''''''''''''''''''''''
-
-We can have a look at some of the inner nodes of the form. Some fields
-are omitted as they are redundant for our purposes.
-
-.. sourcecode:: html
-
- <fieldset class="default">
- <table class="attributeForm">
- <tr class="title_subject_row">
- <th class="labelCol"><label class="required" for="title-subject:763">title</label></th>
- <td>
- <input id="title-subject:763" maxlength="128" name="title-subject:763" size="45"
- tabindex="1" type="text" value="let us write more doc" />
- </td>
- </tr>
- ... (description field omitted) ...
- <tr class="priority_subject_row">
- <th class="labelCol"><label class="required" for="priority-subject:763">priority</label></th>
- <td>
- <select id="priority-subject:763" name="priority-subject:763" size="1" tabindex="4">
- <option value="important">important</option>
- <option selected="selected" value="normal">normal</option>
- <option value="minor">minor</option>
- </select>
- <div class="helper">importance</div>
- </td>
- </tr>
- ... (type field omitted) ...
- <tr class="concerns_subject_row">
- <th class="labelCol"><label class="required" for="concerns-subject:763">concerns</label></th>
- <td>
- <select id="concerns-subject:763" name="concerns-subject:763" size="1" tabindex="6">
- <option selected="selected" value="760">Foo</option>
- </select>
- </td>
- </tr>
- <tr class="done_in_subject_row">
- <th class="labelCol"><label for="done_in-subject:763">done in</label></th>
- <td>
- <select id="done_in-subject:763" name="done_in-subject:763" size="1" tabindex="7">
- <option value="__cubicweb_internal_field__"></option>
- <option selected="selected" value="761">Foo 0.1.0</option>
- <option value="762">Foo 0.2.0</option>
- </select>
- <div class="helper">version in which this ticket will be / has been done</div>
- </td>
- </tr>
- </table>
- </fieldset>
-
-
-Note that the whole form layout has been computed by the form
-renderer. It is the renderer which produces the table
-structure. Otherwise, the fields html structure is emitted by their
-associated widget.
-
-While it is called the `attributes` section of the form, it actually
-contains attributes and *mandatory relations*. For each field, we
-observe:
-
-* a dedicated row with a specific class, such as ``title_subject_row``
- (responsability of the form renderer)
-
-* an html widget (input, select, ...) with:
-
- * an id built from the ``rtype-role:eid`` pattern
-
- * a name built from the same pattern
-
- * possible values or preselected options
-
-The relations section
-'''''''''''''''''''''
-
-.. sourcecode:: html
-
- <fieldset class="This ticket :">
- <legend>This ticket :</legend>
- <table class="attributeForm">
- <tr class="_cw_generic_field_None_row">
- <td colspan="2">
- <table id="relatedEntities">
- <tr><th> </th><td> </td></tr>
- <tr id="relationSelectorRow_763" class="separator">
- <th class="labelCol">
- <select id="relationSelector_763" tabindex="8"
- onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,763);">
- <option value="">select a relation</option>
- <option value="appeared_in_subject">appeared in</option>
- <option value="custom_workflow_subject">custom workflow</option>
- <option value="depends_on_object">dependency of</option>
- <option value="depends_on_subject">depends on</option>
- <option value="identical_to_subject">identical to</option>
- <option value="see_also_subject">see also</option>
- </select>
- </th>
- <td id="unrelatedDivs_763"></td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </fieldset>
-
-The optional relations are grouped into a drop-down combo
-box. Selection of an item triggers a javascript function which will:
-
-* show already related entities in the div of id `relatedentities`
- using a two-colown layout, with an action to allow deletion of
- individual relations (there are none in this example)
-
-* provide a relation selector in the div of id `relationSelector_EID`
- to allow the user to set up relations and trigger dynamic action on
- the last div
-
-* fill the div of id `unrelatedDivs_EID` with a dynamically computed
- selection widget allowing direct selection of an unrelated (but
- relatable) entity or a switch towards the `search mode` of
- |cubicweb| which allows full browsing and selection of an entity
- using a dedicated action situated in the left column boxes.
-
-
-The buttons zone
-''''''''''''''''
-
-Finally comes the buttons zone.
-
-.. sourcecode:: html
-
- <table width="100%">
- <tbody>
- <tr>
- <td align="center">
- <button class="validateButton" tabindex="9" type="submit" value="validate">
- <img alt="OK_ICON" src="http://myapp/datafd8b5d92771209ede1018a8d5da46a37/ok.png" />
- validate
- </button>
- </td>
- <td style="align: right; width: 50%;">
- <button class="validateButton"
- onclick="postForm('__action_apply', 'button_apply', 'entityForm')"
- tabindex="10" type="button" value="apply">
- <img alt="APPLY_ICON" src="http://myapp/datafd8b5d92771209ede1018a8d5da46a37/plus.png" />
- apply
- </button>
- <button class="validateButton"
- onclick="postForm('__action_cancel', 'button_cancel', 'entityForm')"
- tabindex="11" type="button" value="cancel">
- <img alt="CANCEL_ICON" src="http://myapp/datafd8b5d92771209ede1018a8d5da46a37/cancel.png" />
- cancel
- </button>
- </td>
- </tr>
- </tbody>
- </table>
-
-The most notable artifacts here are the ``postForm(...)`` calls
-defined on click events on these buttons. This function basically
-submits the form.
-
-.. _validation_process:
-
-The form validation process
----------------------------
-
-Validation loop
-~~~~~~~~~~~~~~~
-
-On form submission, the form.action is invoked. Basically, the
-``validateform`` controller is called and its output lands in the
-specified ``target``, an invisible ``<iframe>`` at the end of the
-form.
-
-Hence, the main page is not replaced, only the iframe contents. The
-``validateform`` controller only outputs a tiny javascript fragment
-which is then immediately executed.
-
-.. sourcecode:: html
-
- <iframe width="0px" height="0px" name="eformframe" id="eformframe" src="javascript: void(0);">
- <script type="text/javascript">
- window.parent.handleFormValidationResponse('entityForm', null, null,
- [false, [2164, {"name-subject": "required field"}], null],
- null);
- </script>
- </iframe>
-
-The ``window.parent`` part ensures the javascript function is called
-on the right context (that is: the form element). We will describe its
-parameters:
-
-* first comes the form id (`entityForm`)
-
-* then two optional callbacks for the success and failure case
-
-* an array containing:
-
- * a boolean which indicates status (success or failure), and then, on error:
-
- * an array structured as ``[eid, {'rtype-role': 'error msg'}, ...]``
-
- * on success:
-
- * a url (string) representing the next thing to jump to
-
-Given the array structure described above, it is quite simple to
-manipulate the DOM to show the errors at appropriate places.
-
-Explanation
-~~~~~~~~~~~
-
-This mecanism may seem a bit overcomplicated but we have to deal with
-two realities:
-
-* in the (strict) XHTML world, there are no iframes (hence the dynamic
- inclusion, tolerated by Firefox)
-
-* no (or not all) browser(s) support file input field handling through
- ajax.
--- a/doc/book/en/devweb/edition/editcontroller.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-.. _edit_controller:
-
-The `edit controller`
----------------------
-
-It can be found in (:mod:`cubicweb.web.views.editcontroller`). This
-controller processes data received from an html form to create or
-update entities.
-
-Edition handling
-~~~~~~~~~~~~~~~~
-
-The parameters related to entities to edit are specified as follows
-(first seen in :ref:`attributes_section`)::
-
- <rtype-role>:<entity eid>
-
-where entity eid could be a letter in case of an entity to create. We
-name those parameters as *qualified*.
-
-* Retrieval of entities to edit is done by using the forms parameters
- `eid` and `__type`
-
-* For all the attributes and the relations of an entity to edit
- (attributes and relations are handled a bit differently but these
- details are not much relevant here) :
-
- * using the ``rtype``, ``role`` and ``__type`` information, fetch
- an appropriate field instance
-
- * check if the field has been modified (if not, proceed to the next
- relation)
-
- * build an rql expression to update the entity
-
-At the end, all rql expressions are executed.
-
-* For each entity to edit:
-
- * if a qualified parameter `__linkto` is specified, its value has
- to be a string (or a list of strings) such as: ::
-
- <relation type>:<eids>:<target>
-
- where <target> is either `subject` or `object` and each eid could
- be separated from the others by a `_`. Target specifies if the
- *edited entity* is subject or object of the relation and each
- relation specified will be inserted.
-
- * if a qualified parameter `__clone_eid` is specified for an entity, the
- relations of the specified entity passed as value of this parameter are
- copied on the edited entity.
-
- * if a qualified parameter `__delete` is specified, its value must be
- a string or a list of string such as follows: ::
-
- <subjects eids>:<relation type>:<objects eids>
-
- where each eid subject or object can be seperated from the other
- by `_`. Each specified relation will be deleted.
-
-
-* If no entity is edited but the form contains the parameters `__linkto`
- and `eid`, this one is interpreted by using the value specified for `eid`
- to designate the entity on which to add the relations.
-
-.. note::
-
- * if the parameter `__action_delete` is found, all the entities specified
- as to be edited will be deleted.
-
- * if the parameter `__action_cancel` is found, no action is completed.
-
- * if the parameter `__action_apply` is found, the editing is
- applied normally but the redirection is done on the form (see
- :ref:`RedirectionControl`).
-
- * if no entity is found to be edited and if there is no parameter
- `__action_delete`, `__action_cancel`, `__linkto`, `__delete` or
- `__insert`, an error is raised.
-
- * using the parameter `__message` in the form will allow to use its value
- as a message to provide the user once the editing is completed.
-
-
-.. _RedirectionControl:
-
-Redirection control
-~~~~~~~~~~~~~~~~~~~
-Once editing is completed, there is still an issue left: where should we go
-now? If nothing is specified, the controller will do his job but it does not
-mean we will be happy with the result. We can control that by using the
-following parameters:
-
-* `__redirectpath`: path of the URL (relative to the root URL of the site,
- no form parameters
-
-* `__redirectparams`: forms parameters to add to the path
-
-* `__redirectrql`: redirection RQL request
-
-* `__redirectvid`: redirection view identifier
-
-* `__errorurl`: initial form URL, used for redirecting in case a validation
- error is raised during editing. If this one is not specified, an error page
- is displayed instead of going back to the form (which is, if necessary,
- responsible for displaying the errors)
-
-* `__form_id`: initial view form identifier, used if `__action_apply` is
- found
-
-In general we use either `__redirectpath` and `__redirectparams` or
-`__redirectrql` and `__redirectvid`.
--- a/doc/book/en/devweb/edition/examples.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,232 +0,0 @@
-Examples
---------
-
-(Automatic) Entity form
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Looking at some cubes available on the `cubicweb forge`_ we find some
-with form manipulation. The following example comes from the the
-`conference`_ cube. It extends the change state form for the case
-where a ``Talk`` entity is getting into ``submitted`` state. The goal
-is to select reviewers for the submitted talk.
-
-.. _`cubicweb forge`: http://www.cubicweb.org/view?rql=Any+P+ORDERBY+N+WHERE+P+name+LIKE+%22cubicweb-%25%22%2C+P+is+Project%2C+P+name+N
-.. _`conference`: http://www.cubicweb.org/project/cubicweb-conference
-
-.. sourcecode:: python
-
- from cubicweb.web import formfields as ff, formwidgets as fwdgs
- class SendToReviewerStatusChangeView(ChangeStateFormView):
- __select__ = (ChangeStateFormView.__select__ &
- is_instance('Talk') &
- rql_condition('X in_state S, S name "submitted"'))
-
- def get_form(self, entity, transition, **kwargs):
- form = super(SendToReviewerStatusChangeView, self).get_form(entity, transition, **kwargs)
- relation = ff.RelationField(name='reviews', role='object',
- eidparam=True,
- label=_('select reviewers'),
- widget=fwdgs.Select(multiple=True))
- form.append_field(relation)
- return form
-
-Simple extension of a form can be done from within the `FormView`
-wrapping the form. FormView instances have a handy ``get_form`` method
-that returns the form to be rendered. Here we add a ``RelationField``
-to the base state change form.
-
-One notable point is the ``eidparam`` argument: it tells both the
-field and the ``edit controller`` that the field is linked to a
-specific entity.
-
-It is hence entirely possible to add ad-hoc fields that will be
-processed by some specialized instance of the edit controller.
-
-
-Ad-hoc fields form
-~~~~~~~~~~~~~~~~~~
-
-We want to define a form doing something else than editing an entity. The idea is
-to propose a form to send an email to entities in a resultset which implements
-:class:`IEmailable`. Let's take a simplified version of what you'll find in
-:mod:`cubicweb.web.views.massmailing`.
-
-Here is the source code:
-
-.. sourcecode:: python
-
- def sender_value(form, field):
- return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email())
-
- def recipient_choices(form, field):
- return [(e.get_email(), e.eid)
- for e in form.cw_rset.entities()
- if e.get_email()]
-
- def recipient_value(form, field):
- return [e.eid for e in form.cw_rset.entities()
- if e.get_email()]
-
- class MassMailingForm(forms.FieldsForm):
- __regid__ = 'massmailing'
-
- needs_js = ('cubicweb.widgets.js',)
- domid = 'sendmail'
- action = 'sendmail'
-
- sender = ff.StringField(widget=TextInput({'disabled': 'disabled'}),
- label=_('From:'),
- value=sender_value)
-
- recipient = ff.StringField(widget=CheckBox(),
- label=_('Recipients:'),
- choices=recipient_choices,
- value=recipients_value)
-
- subject = ff.StringField(label=_('Subject:'), max_length=256)
-
- mailbody = ff.StringField(widget=AjaxWidget(wdgtype='TemplateTextField',
- inputid='mailbody'))
-
- form_buttons = [ImgButton('sendbutton', "javascript: $('#sendmail').submit()",
- _('send email'), 'SEND_EMAIL_ICON'),
- ImgButton('cancelbutton', "javascript: history.back()",
- stdmsgs.BUTTON_CANCEL, 'CANCEL_EMAIL_ICON')]
-
-Let's detail what's going on up there. Our form will hold four fields:
-
-* a sender field, which is disabled and will simply contains the user's name and
- email
-
-* a recipients field, which will be displayed as a list of users in the context
- result set with checkboxes so user can still choose who will receive his mailing
- by checking or not the checkboxes. By default all of them will be checked since
- field's value return a list containing same eids as those returned by the
- vocabulary function.
-
-* a subject field, limited to 256 characters (hence we know a
- :class:`~cubicweb.web.formwidgets.TextInput` will be used, as explained in
- :class:`~cubicweb.web.formfields.StringField`)
-
-* a mailbody field. This field use an ajax widget, defined in `cubicweb.widgets.js`,
- and whose definition won't be shown here. Notice though that we tell this form
- need this javascript file by using `needs_js`
-
-Last but not least, we add two buttons control: one to post the form using
-javascript (`$('#sendmail')` being the jQuery call to get the element with DOM id
-set to 'sendmail', which is our form DOM id as specified by its `domid`
-attribute), another to cancel the form which will go back to the previous page
-using another javascript call. Also we specify an image to use as button icon as a
-resource identifier (see :ref:`uiprops`) given as last argument to
-:class:`cubicweb.web.formwidgets.ImgButton`.
-
-To see this form, we still have to wrap it in a view. This is pretty simple:
-
-.. sourcecode:: python
-
- class MassMailingFormView(form.FormViewMixIn, EntityView):
- __regid__ = 'massmailing'
- __select__ = is_instance(IEmailable) & authenticated_user()
-
- def call(self):
- form = self._cw.vreg['forms'].select('massmailing', self._cw,
- rset=self.cw_rset)
- form.render(w=self.w)
-
-As you see, we simply define a view with proper selector so it only apply to a
-result set containing :class:`IEmailable` entities, and so that only users in the
-managers or users group can use it. Then in the `call()` method for this view we
-simply select the above form and call its `.render()` method with our output
-stream as argument.
-
-When this form is submitted, a controller with id 'sendmail' will be called (as
-specified using `action`). This controller will be responsible to actually send
-the mail to specified recipients.
-
-Here is what it looks like:
-
-.. sourcecode:: python
-
- class SendMailController(Controller):
- __regid__ = 'sendmail'
- __select__ = (authenticated_user() &
- match_form_params('recipient', 'mailbody', 'subject'))
-
- def publish(self, rset=None):
- body = self._cw.form['mailbody']
- subject = self._cw.form['subject']
- eids = self._cw.form['recipient']
- # eids may be a string if only one recipient was specified
- if isinstance(eids, basestring):
- rset = self._cw.execute('Any X WHERE X eid %(x)s', {'x': eids})
- else:
- rset = self._cw.execute('Any X WHERE X eid in (%s)' % (','.join(eids)))
- recipients = list(rset.entities())
- msg = format_mail({'email' : self._cw.user.get_email(),
- 'name' : self._cw.user.dc_title()},
- recipients, body, subject)
- if not self._cw.vreg.config.sendmails([(msg, recipients)]):
- msg = self._cw._('could not connect to the SMTP server')
- else:
- msg = self._cw._('emails successfully sent')
- raise Redirect(self._cw.build_url(__message=msg))
-
-
-The entry point of a controller is the publish method. In that case we simply get
-back post values in request's `form` attribute, get user instances according
-to eids found in the 'recipient' form value, and send email after calling
-:func:`format_mail` to get a proper email message. If we can't send email or
-if we successfully sent email, we redirect to the index page with proper message
-to inform the user.
-
-Also notice that our controller has a selector that deny access to it
-to anonymous users (we don't want our instance to be used as a spam
-relay), but also checks if the expected parameters are specified in
-forms. That avoids later defensive programming (though it's not enough
-to handle all possible error cases).
-
-To conclude our example, suppose we wish a different form layout and that existent
-renderers are not satisfying (we would check that first of course :). We would then
-have to define our own renderer:
-
-.. sourcecode:: python
-
- class MassMailingFormRenderer(formrenderers.FormRenderer):
- __regid__ = 'massmailing'
-
- def _render_fields(self, fields, w, form):
- w(u'<table class="headersform">')
- for field in fields:
- if field.name == 'mailbody':
- w(u'</table>')
- w(u'<div id="toolbar">')
- w(u'<ul>')
- for button in form.form_buttons:
- w(u'<li>%s</li>' % button.render(form))
- w(u'</ul>')
- w(u'</div>')
- w(u'<div>')
- w(field.render(form, self))
- w(u'</div>')
- else:
- w(u'<tr>')
- w(u'<td class="hlabel">%s</td>' %
- self.render_label(form, field))
- w(u'<td class="hvalue">')
- w(field.render(form, self))
- w(u'</td></tr>')
-
- def render_buttons(self, w, form):
- pass
-
-We simply override the `_render_fields` and `render_buttons` method of the base form renderer
-to arrange fields as we desire it: here we'll have first a two columns table with label and
-value of the sender, recipients and subject field (form order respected), then form controls,
-then a div containing the textarea for the email's content.
-
-To bind this renderer to our form, we should add to our form definition above:
-
-.. sourcecode:: python
-
- form_renderer_id = 'massmailing'
-
--- a/doc/book/en/devweb/edition/form.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,377 +0,0 @@
-.. _webform:
-
-HTML form construction
-----------------------
-
-CubicWeb provides the somewhat usual form / field / widget / renderer abstraction
-to provide generic building blocks which will greatly help you in building forms
-properly integrated with CubicWeb (coherent display, error handling, etc...),
-while keeping things as flexible as possible.
-
-A ``form`` basically only holds a set of ``fields``, and has te be bound to a
-``renderer`` which is responsible to layout them. Each field is bound to a
-``widget`` that will be used to fill in value(s) for that field (at form
-generation time) and 'decode' (fetch and give a proper Python type to) values
-sent back by the browser.
-
-The ``field`` should be used according to the type of what you want to edit.
-E.g. if you want to edit some date, you'll have to use the
-:class:`cubicweb.web.formfields.DateField`. Then you can choose among multiple
-widgets to edit it, for instance :class:`cubicweb.web.formwidgets.TextInput` (a
-bare text field), :class:`~cubicweb.web.formwidgets.DateTimePicker` (a simple
-calendar) or even :class:`~cubicweb.web.formwidgets.JQueryDatePicker` (the JQuery
-calendar). You can of course also write your own widget.
-
-Exploring the available forms
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-A small excursion into a |cubicweb| shell is the quickest way to
-discover available forms (or application objects in general).
-
-.. sourcecode:: python
-
- >>> from pprint import pprint
- >>> pprint( session.vreg['forms'] )
- {'base': [<class 'cubicweb.web.views.forms.FieldsForm'>,
- <class 'cubicweb.web.views.forms.EntityFieldsForm'>],
- 'changestate': [<class 'cubicweb.web.views.workflow.ChangeStateForm'>,
- <class 'cubes.tracker.views.forms.VersionChangeStateForm'>],
- 'composite': [<class 'cubicweb.web.views.forms.CompositeForm'>,
- <class 'cubicweb.web.views.forms.CompositeEntityForm'>],
- 'deleteconf': [<class 'cubicweb.web.views.editforms.DeleteConfForm'>],
- 'edition': [<class 'cubicweb.web.views.autoform.AutomaticEntityForm'>,
- <class 'cubicweb.web.views.workflow.TransitionEditionForm'>,
- <class 'cubicweb.web.views.workflow.StateEditionForm'>],
- 'logform': [<class 'cubicweb.web.views.basetemplates.LogForm'>],
- 'massmailing': [<class 'cubicweb.web.views.massmailing.MassMailingForm'>],
- 'muledit': [<class 'cubicweb.web.views.editforms.TableEditForm'>],
- 'sparql': [<class 'cubicweb.web.views.sparql.SparqlForm'>]}
-
-
-The two most important form families here (for all practical purposes) are `base`
-and `edition`. Most of the time one wants alterations of the
-:class:`AutomaticEntityForm` to generate custom forms to handle edition of an
-entity.
-
-The Automatic Entity Form
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: cubicweb.web.views.autoform
-
-Anatomy of a choices function
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's have a look at the `ticket_done_in_choices` function given to
-the `choices` parameter of the relation tag that is applied to the
-('Ticket', 'done_in', '*') relation definition, as it is both typical
-and sophisticated enough. This is a code snippet from the `tracker`_
-cube.
-
-.. _`tracker`: http://www.cubicweb.org/project/cubicweb-tracker
-
-The ``Ticket`` entity type can be related to a ``Project`` and a
-``Version``, respectively through the ``concerns`` and ``done_in``
-relations. When a user is about to edit a ticket, we want to fill the
-combo box for the ``done_in`` relation with values pertinent with
-respect to the context. The important context here is:
-
-* creation or modification (we cannot fetch values the same way in
- either case)
-
-* ``__linkto`` url parameter given in a creation context
-
-.. sourcecode:: python
-
- from cubicweb.web import formfields
-
- def ticket_done_in_choices(form, field):
- entity = form.edited_entity
- # first see if its specified by __linkto form parameters
- linkedto = form.linked_to[('done_in', 'subject')]
- if linkedto:
- return linkedto
- # it isn't, get initial values
- vocab = field.relvoc_init(form)
- veid = None
- # try to fetch the (already or pending) related version and project
- if not entity.has_eid():
- peids = form.linked_to[('concerns', 'subject')]
- peid = peids and peids[0]
- else:
- peid = entity.project.eid
- veid = entity.done_in and entity.done_in[0].eid
- if peid:
- # we can complete the vocabulary with relevant values
- rschema = form._cw.vreg.schema['done_in'].rdef('Ticket', 'Version')
- rset = form._cw.execute(
- 'Any V, VN ORDERBY version_sort_value(VN) '
- 'WHERE V version_of P, P eid %(p)s, V num VN, '
- 'V in_state ST, NOT ST name "published"', {'p': peid}, 'p')
- vocab += [(v.view('combobox'), v.eid) for v in rset.entities()
- if rschema.has_perm(form._cw, 'add', toeid=v.eid)
- and v.eid != veid]
- return vocab
-
-The first thing we have to do is fetch potential values from the ``__linkto`` url
-parameter that is often found in entity creation contexts (the creation action
-provides such a parameter with a predetermined value; for instance in this case,
-ticket creation could occur in the context of a `Version` entity). The
-:class:`~cubicweb.web.formfields.RelationField` field class provides a
-:meth:`~cubicweb.web.formfields.RelationField.relvoc_linkedto` method that gets a
-list suitably filled with vocabulary values.
-
-.. sourcecode:: python
-
- linkedto = field.relvoc_linkedto(form)
- if linkedto:
- return linkedto
-
-Then, if no ``__linkto`` argument was given, we must prepare the vocabulary with
-an initial empty value (because `done_in` is not mandatory, we must allow the
-user to not select a verson) and already linked values. This is done with the
-:meth:`~cubicweb.web.formfields.RelationField.relvoc_init` method.
-
-.. sourcecode:: python
-
- vocab = field.relvoc_init(form)
-
-But then, we have to give more: if the ticket is related to a project,
-we should provide all the non published versions of this project
-(`Version` and `Project` can be related through the `version_of`
-relation). Conversely, if we do not know yet the project, it would not
-make sense to propose all existing versions as it could potentially
-lead to incoherences. Even if these will be caught by some
-RQLConstraint, it is wise not to tempt the user with error-inducing
-candidate values.
-
-The "ticket is related to a project" part must be decomposed as:
-
-* this is a new ticket which is created is the context of a project
-
-* this is an already existing ticket, linked to a project (through the
- `concerns` relation)
-
-* there is no related project (quite unlikely given the cardinality of
- the `concerns` relation, so it can only mean that we are creating a
- new ticket, and a project is about to be selected but there is no
- ``__linkto`` argument)
-
-.. note::
-
- the last situation could happen in several ways, but of course in a
- polished application, the paths to ticket creation should be
- controlled so as to avoid a suboptimal end-user experience
-
-Hence, we try to fetch the related project.
-
-.. sourcecode:: python
-
- veid = None
- if not entity.has_eid():
- peids = form.linked_to[('concerns', 'subject')]
- peid = peids and peids[0]
- else:
- peid = entity.project.eid
- veid = entity.done_in and entity.done_in[0].eid
-
-We distinguish between entity creation and entity modification using
-the ``Entity.has_eid()`` method, which returns `False` on creation. At
-creation time the only way to get a project is through the
-``__linkto`` parameter. Notice that we fetch the version in which the
-ticket is `done_in` if any, for later.
-
-.. note::
-
- the implementation above assumes that if there is a ``__linkto``
- parameter, it is only about a project. While it makes sense most of
- the time, it is not an absolute. Depending on how an entity creation
- action action url is built, several outcomes could be possible
- there
-
-If the ticket is already linked to a project, fetching it is
-trivial. Then we add the relevant version to the initial vocabulary.
-
-.. sourcecode:: python
-
- if peid:
- rschema = form._cw.vreg.schema['done_in'].rdef('Ticket', 'Version')
- rset = form._cw.execute(
- 'Any V, VN ORDERBY version_sort_value(VN) '
- 'WHERE V version_of P, P eid %(p)s, V num VN, '
- 'V in_state ST, NOT ST name "published"', {'p': peid})
- vocab += [(v.view('combobox'), v.eid) for v in rset.entities()
- if rschema.has_perm(form._cw, 'add', toeid=v.eid)
- and v.eid != veid]
-
-.. warning::
-
- we have to defend ourselves against lack of a project eid. Given
- the cardinality of the `concerns` relation, there *must* be a
- project, but this rule can only be enforced at validation time,
- which will happen of course only after form subsmission
-
-Here, given a project eid, we complete the vocabulary with all
-unpublished versions defined in the project (sorted by number) for
-which the current user is allowed to establish the relation.
-
-
-Building self-posted form with custom fields/widgets
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Sometimes you want a form that is not related to entity edition. For those,
-you'll have to handle form posting by yourself. Here is a complete example on how
-to achieve this (and more).
-
-Imagine you want a form that selects a month period. There are no proper
-field/widget to handle this in CubicWeb, so let's start by defining them:
-
-.. sourcecode:: python
-
- # let's have the whole import list at the beginning, even those necessary for
- # subsequent snippets
- from logilab.common import date
- from logilab.mtconverter import xml_escape
- from cubicweb.view import View
- from cubicweb.predicates import match_kwargs
- from cubicweb.web import RequestError, ProcessFormError
- from cubicweb.web import formfields as fields, formwidgets as wdgs
- from cubicweb.web.views import forms, calendar
-
- class MonthSelect(wdgs.Select):
- """Custom widget to display month and year. Expect value to be given as a
- date instance.
- """
-
- def format_value(self, form, field, value):
- return u'%s/%s' % (value.year, value.month)
-
- def process_field_data(self, form, field):
- val = super(MonthSelect, self).process_field_data(form, field)
- try:
- year, month = val.split('/')
- year = int(year)
- month = int(month)
- return date.date(year, month, 1)
- except ValueError:
- raise ProcessFormError(
- form._cw._('badly formated date string %s') % val)
-
-
- class MonthPeriodField(fields.CompoundField):
- """custom field composed of two subfields, 'begin_month' and 'end_month'.
-
- It expects to be used on form that has 'mindate' and 'maxdate' in its
- extra arguments, telling the range of month to display.
- """
-
- def __init__(self, *args, **kwargs):
- kwargs.setdefault('widget', wdgs.IntervalWidget())
- super(MonthPeriodField, self).__init__(
- [fields.StringField(name='begin_month',
- choices=self.get_range, sort=False,
- value=self.get_mindate,
- widget=MonthSelect()),
- fields.StringField(name='end_month',
- choices=self.get_range, sort=False,
- value=self.get_maxdate,
- widget=MonthSelect())], *args, **kwargs)
-
- @staticmethod
- def get_range(form, field):
- mindate = date.todate(form.cw_extra_kwargs['mindate'])
- maxdate = date.todate(form.cw_extra_kwargs['maxdate'])
- assert mindate <= maxdate
- _ = form._cw._
- months = []
- while mindate <= maxdate:
- label = '%s %s' % (_(calendar.MONTHNAMES[mindate.month - 1]),
- mindate.year)
- value = field.widget.format_value(form, field, mindate)
- months.append( (label, value) )
- mindate = date.next_month(mindate)
- return months
-
- @staticmethod
- def get_mindate(form, field):
- return form.cw_extra_kwargs['mindate']
-
- @staticmethod
- def get_maxdate(form, field):
- return form.cw_extra_kwargs['maxdate']
-
- def process_posted(self, form):
- for field, value in super(MonthPeriodField, self).process_posted(form):
- if field.name == 'end_month':
- value = date.last_day(value)
- yield field, value
-
-
-Here we first define a widget that will be used to select the beginning and the
-end of the period, displaying months like '<month> YYYY' but using 'YYYY/mm' as
-actual value.
-
-We then define a field that will actually hold two fields, one for the beginning
-and another for the end of the period. Each subfield uses the widget we defined
-earlier, and the outer field itself uses the standard
-:class:`IntervalWidget`. The field adds some logic:
-
-* a vocabulary generation function `get_range`, used to populate each sub-field
-
-* two 'value' functions `get_mindate` and `get_maxdate`, used to tell to
- subfields which value they should consider on form initialization
-
-* overriding of `process_posted`, called when the form is being posted, so that
- the end of the period is properly set to the last day of the month.
-
-Now, we can define a very simple form:
-
-.. sourcecode:: python
-
- class MonthPeriodSelectorForm(forms.FieldsForm):
- __regid__ = 'myform'
- __select__ = match_kwargs('mindate', 'maxdate')
-
- form_buttons = [wdgs.SubmitButton()]
- form_renderer_id = 'onerowtable'
- period = MonthPeriodField()
-
-
-where we simply add our field, set a submit button and use a very simple renderer
-(try others!). Also we specify a selector that ensures form will have arguments
-necessary to our field.
-
-Now, we need a view that will wrap the form and handle post when it occurs,
-simply displaying posted values in the page:
-
-.. sourcecode:: python
-
- class SelfPostingForm(View):
- __regid__ = 'myformview'
-
- def call(self):
- mindate, maxdate = date.date(2010, 1, 1), date.date(2012, 1, 1)
- form = self._cw.vreg['forms'].select(
- 'myform', self._cw, mindate=mindate, maxdate=maxdate, action='')
- try:
- posted = form.process_posted()
- self.w(u'<p>posted values %s</p>' % xml_escape(repr(posted)))
- except RequestError: # no specified period asked
- pass
- form.render(w=self.w, formvalues=self._cw.form)
-
-
-Notice usage of the :meth:`process_posted` method, that will return a dictionary
-of typed values (because they have been processed by the field). In our case, when
-the form is posted you should see a dictionary with 'begin_month' and 'end_month'
-as keys with the selected dates as value (as a python `date` object).
-
-
-APIs
-~~~~
-
-.. automodule:: cubicweb.web.formfields
-.. automodule:: cubicweb.web.formwidgets
-.. automodule:: cubicweb.web.views.forms
-.. automodule:: cubicweb.web.views.formrenderers
-
-
--- a/doc/book/en/devweb/edition/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-Edition control
-===============
-
-This chapter covers the editing capabilities of |cubicweb|. It
-explains html Form construction, the Edit Controller and their
-interactions.
-
-
-.. toctree::
- :maxdepth: 2
-
- form
- dissection
- editcontroller
- examples
--- a/doc/book/en/devweb/facets.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-The facets system
------------------
-
-Facets allow to restrict searches according to some user friendly criterias.
-CubicWeb has a builtin `facet`_ system to define restrictions `filters`_ really
-as easily as possible.
-
-Here is an exemple of the facets rendering picked from our
-http://www.cubicweb.org web site:
-
-.. image:: ../images/facet_overview.png
-
-Facets will appear on each page presenting more than one entity that may be
-filtered according to some known criteria.
-
-Base classes for facets
-~~~~~~~~~~~~~~~~~~~~~~~
-.. automodule:: cubicweb.web.facet
-
-
-.. _facet: http://en.wikipedia.org/wiki/Faceted_browser
-.. _filters: http://www.cubicweb.org/blogentry/154152
-
--- a/doc/book/en/devweb/httpcaching.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-HTTP cache management
-=====================
-
-.. automodule:: cubicweb.web.httpcache
-
-Cache policies
---------------
-.. autoclass:: cubicweb.web.httpcache.NoHTTPCacheManager
-.. autoclass:: cubicweb.web.httpcache.MaxAgeHTTPCacheManager
-.. autoclass:: cubicweb.web.httpcache.EtagHTTPCacheManager
-.. autoclass:: cubicweb.web.httpcache.EntityHTTPCacheManager
-
-Exception
----------
-.. autoexception:: cubicweb.web.httpcache.NoEtag
-
-Helper functions
-----------------
-.. autofunction:: cubicweb.web.httpcache.set_http_cache_headers
-
-.. NOT YET AVAILABLE IN STABLE autofunction:: cubicweb.web.httpcache.lastmodified
--- a/doc/book/en/devweb/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-Web side development
-====================
-
-In this chapter, we will describe the core APIs for web development in
-the *CubicWeb* framework.
-
-.. toctree::
- :maxdepth: 2
-
- publisher
- controllers
- request
- searchbar
- views/index
- rtags
- ajax
- js
- css
- edition/index
- facets
- internationalization
- property
- httpcaching
- resource
--- a/doc/book/en/devweb/internationalization.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _internationalization:
-
-Internationalization
----------------------
-
-Cubicweb fully supports the internalization of its content and interface.
-
-Cubicweb's interface internationalization is based on the translation project `GNU gettext`_.
-
-.. _`GNU gettext`: http://www.gnu.org/software/gettext/
-
-Cubicweb' internalization involves two steps:
-
-* in your Python code and cubicweb-tal templates : mark translatable strings
-
-* in your instance : handle the translation catalog, edit translations
-
-String internationalization
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-User defined string
-```````````````````
-
-In the Python code and cubicweb-tal templates translatable strings can be
-marked in one of the following ways :
-
- * by using the *built-in* function `_`:
-
- .. sourcecode:: python
-
- class PrimaryView(EntityView):
- """the full view of an non final entity"""
- __regid__ = 'primary'
- title = _('primary')
-
- OR
-
- * by using the equivalent request's method:
-
- .. sourcecode:: python
-
- class NoResultView(View):
- """default view when no result has been found"""
- __regid__ = 'noresult'
-
- def call(self, **kwargs):
- self.w(u'<div class="searchMessage"><strong>%s</strong></div>\n'
- % self._cw._('No result matching query'))
-
-The goal of the *built-in* function `_` is only **to mark the
-translatable strings**, it will only return the string to translate
-itself, but not its translation (it's actually another name for the
-`unicode` builtin).
-
-In the other hand the request's method `self._cw._` is also meant to
-retrieve the proper translation of translation strings in the
-requested language.
-
-Finally you can also use the `__` attribute of request object to get a
-translation for a string *which should not itself added to the catalog*,
-usually in case where the actual msgid is created by string interpolation ::
-
- self._cw.__('This %s' % etype)
-
-In this example ._cw.__` is used instead of ._cw._` so we don't have 'This %s' in
-messages catalogs.
-
-Translations in cubicweb-tal template can also be done with TAL tags
-`i18n:content` and `i18n:replace`.
-
-If you need to add messages on top of those that can be found in the source,
-you can create a file named `i18n/static-messages.pot`.
-
-You could put there messages not found in the python sources or
-overrides for some messages of used cubes.
-
-Generated string
-````````````````
-
-We do not need to mark the translation strings of entities/relations used by a
-particular instance's schema as they are generated automatically. String for
-various actions are also generated.
-
-For exemple the following schema:
-
-.. sourcecode:: python
-
-
- class EntityA(EntityType):
- relation_a2b = SubjectRelation('EntityB')
-
- class EntityB(EntityType):
- pass
-
-May generate the following message ::
-
- add EntityA relation_a2b EntityB subject
-
-This message will be used in views of ``EntityA`` for creation of a new
-``EntityB`` with a preset relation ``relation_a2b`` between the current
-``EntityA`` and the new ``EntityB``. The opposite message ::
-
- add EntityA relation_a2b EntityB object
-
-Is used for similar creation of an ``EntityA`` from a view of ``EntityB``. The
-title of they respective creation form will be ::
-
- creating EntityB (EntityA %(linkto)s relation_a2b EntityB)
-
- creating EntityA (EntityA relation_a2b %(linkto)s EntityA)
-
-In the translated string you can use ``%(linkto)s`` for reference to the source
-``entity``.
-
-Handling the translation catalog
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Once the internationalization is done in your code, you need to populate and
-update the translation catalog. Cubicweb provides the following commands for this
-purpose:
-
-
-* `i18ncubicweb` updates Cubicweb framework's translation
- catalogs. Unless you actually work on the framework itself, you
- don't need to use this command.
-
-* `i18ncube` updates the translation catalogs of *one particular cube*
- (or of all cubes). After this command is executed you must update
- the translation files *.po* in the "i18n" directory of your
- cube. This command will of course not remove existing translations
- still in use. It will mark unused translation but not remove them.
-
-* `i18ninstance` recompiles the translation catalogs of *one particular
- instance* (or of all instances) after the translation catalogs of
- its cubes have been updated. This command is automatically
- called every time you create or update your instance. The compiled
- catalogs (*.mo*) are stored in the i18n/<lang>/LC_MESSAGES of
- instance where `lang` is the language identifier ('en' or 'fr'
- for exemple).
-
-
-Example
-```````
-
-You have added and/or modified some translation strings in your cube
-(after creating a new view or modifying the cube's schema for exemple).
-To update the translation catalogs you need to do:
-
-1. `cubicweb-ctl i18ncube <cube>`
-2. Edit the <cube>/i18n/xxx.po files and add missing translations (empty `msgstr`)
-3. `hg ci -m "updated i18n catalogs"`
-4. `cubicweb-ctl i18ninstance <myinstance>`
-
-Editing po files
-~~~~~~~~~~~~~~~~
-
-Using a PO aware editor
-````````````````````````
-
-Many tools exist to help maintain .po (PO) files. Common editors or
-development environment provides modes for these. One can also find
-dedicated PO files editor, such as `poedit`_.
-
-.. _`poedit`: http://www.poedit.net/
-
-While usage of such a tool is commendable, PO files are perfectly
-editable with a (unicode aware) plain text editor. It is also useful
-to know their structure for troubleshooting purposes.
-
-Structure of a PO file
-``````````````````````
-
-In this section, we selectively quote passages of the `GNU gettext`_
-manual chapter on PO files, available there::
-
- http://www.gnu.org/software/hello/manual/gettext/PO-Files.html
-
-One PO file entry has the following schematic structure::
-
- white-space
- # translator-comments
- #. extracted-comments
- #: reference...
- #, flag...
- #| msgid previous-untranslated-string
- msgid untranslated-string
- msgstr translated-string
-
-
-A simple entry can look like this::
-
- #: lib/error.c:116
- msgid "Unknown system error"
- msgstr "Error desconegut del sistema"
-
-It is also possible to have entries with a context specifier. They
-look like this::
-
- white-space
- # translator-comments
- #. extracted-comments
- #: reference...
- #, flag...
- #| msgctxt previous-context
- #| msgid previous-untranslated-string
- msgctxt context
- msgid untranslated-string
- msgstr translated-string
-
-
-The context serves to disambiguate messages with the same
-untranslated-string. It is possible to have several entries with the
-same untranslated-string in a PO file, provided that they each have a
-different context. Note that an empty context string and an absent
-msgctxt line do not mean the same thing.
-
-Contexts and CubicWeb
-`````````````````````
-
-CubicWeb PO files have both non-contextual and contextual msgids.
-
-Contextual entries are automatically used in some cases. For instance,
-entity.dc_type(), eschema.display_name(req) or display_name(etype,
-req, form, context) methods/function calls will use them.
-
-It is also possible to explicitly use the with _cw.pgettext(context,
-msgid).
--- a/doc/book/en/devweb/js.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,394 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Javascript
-----------
-
-*CubicWeb* uses quite a bit of javascript in its user interface and
-ships with jquery (1.3.x) and parts of the jquery UI library, plus a
-number of homegrown files and also other third party libraries.
-
-All javascript files are stored in cubicweb/web/data/. There are
-around thirty js files there. In a cube it goes to data/.
-
-Obviously one does not want javascript pieces to be loaded all at
-once, hence the framework provides a number of mechanisms and
-conventions to deal with javascript resources.
-
-Conventions
-~~~~~~~~~~~
-
-It is good practice to name cube specific js files after the name of
-the cube, like this : 'cube.mycube.js', so as to avoid name clashes.
-
-.. XXX external_resources variable (which needs love)
-
-Server-side Javascript API
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Javascript resources are typically loaded on demand, from views. The
-request object (available as self._cw from most application objects,
-for instance views and entities objects) has a few methods to do that:
-
-* `add_js(self, jsfiles, localfile=True)` which takes a sequence of
- javascript files and writes proper entries into the HTML header
- section. The localfile parameter allows to declare resources which
- are not from web/data (for instance, residing on a content delivery
- network).
-
-* `add_onload(self, jscode)` which adds one raw javascript code
- snippet inline in the html headers. This is quite useful for setting
- up early jQuery(document).ready(...) initialisations.
-
-Javascript events
-~~~~~~~~~~~~~~~~~
-
-* ``server-response``: this event is triggered on HTTP responses (both
- standard and ajax). The two following extra parameters are passed
- to callbacks :
-
- - ``ajax``: a boolean that says if the reponse was issued by an
- ajax request
-
- - ``node``: the DOM node returned by the server in case of an
- ajax request, otherwise the document itself for standard HTTP
- requests.
-
-Important javascript AJAX APIS
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* `asyncRemoteExec` and `remoteExec` are the base building blocks for
- doing arbitrary async (resp. sync) communications with the server
-
-* `reloadComponent` is a convenience function to replace a DOM node
- with server supplied content coming from a specific registry (this
- is quite handy to refresh the content of some boxes for instances)
-
-* `jQuery.fn.loadxhtml` is an important extension to jQuery which
- allows proper loading and in-place DOM update of xhtml views. It is
- suitably augmented to trigger necessary events, and process CubicWeb
- specific elements such as the facet system, fckeditor, etc.
-
-
-A simple example with asyncRemoteExec
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-On the python side, we have to define an
-:class:`cubicweb.web.views.ajaxcontroller.AjaxFunction` object. The
-simplest way to do that is to use the
-:func:`cubicweb.web.views.ajaxcontroller.ajaxfunc` decorator (for more
-details on this, refer to :ref:`ajax`).
-
-.. sourcecode: python
-
- from cubicweb.web.views.ajaxcontroller import ajaxfunc
-
- # serialize output to json to get it back easily on the javascript side
- @ajaxfunc(output_type='json')
- def js_say_hello(self, name):
- return u'hello %s' % name
-
-On the javascript side, we do the asynchronous call. Notice how it
-creates a `deferred` object. Proper treatment of the return value or
-error handling has to be done through the addCallback and addErrback
-methods.
-
-.. sourcecode: javascript
-
- function asyncHello(name) {
- var deferred = asyncRemoteExec('say_hello', name);
- deferred.addCallback(function (response) {
- alert(response);
- });
- deferred.addErrback(function (error) {
- alert('something fishy happened');
- });
- }
-
- function syncHello(name) {
- alert( remoteExec('say_hello', name) );
- }
-
-Anatomy of a reloadComponent call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`reloadComponent` allows to dynamically replace some DOM node with new
-elements. It has the following signature:
-
-* `compid` (mandatory) is the name of the component to be reloaded
-
-* `rql` (optional) will be used to generate a result set given as
- argument to the selected component
-
-* `registry` (optional) defaults to 'components' but can be any other
- valid registry name
-
-* `nodeid` (optional) defaults to compid + 'Component' but can be any
- explicitly specified DOM node id
-
-* `extraargs` (optional) should be a dictionary of values that will be
- given to the cell_call method of the component
-
-A simple reloadComponent example
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The server side implementation of `reloadComponent` is the
-:func:`cubicweb.web.views.ajaxcontroller.component` *AjaxFunction* appobject.
-
-The following function implements a two-steps method to delete a
-standard bookmark and refresh the UI, while keeping the UI responsive.
-
-.. sourcecode:: javascript
-
- function removeBookmark(beid) {
- d = asyncRemoteExec('delete_bookmark', beid);
- d.addCallback(function(boxcontent) {
- reloadComponent('bookmarks_box', '', 'boxes', 'bookmarks_box');
- document.location.hash = '#header';
- updateMessage(_("bookmark has been removed"));
- });
- }
-
-`reloadComponent` is called with the id of the bookmark box as
-argument, no rql expression (because the bookmarks display is actually
-independant of any dataset context), a reference to the 'boxes'
-registry (which hosts all left, right and contextual boxes) and
-finally an explicit 'bookmarks_box' nodeid argument that stipulates
-the target DOM node.
-
-Anatomy of a loadxhtml call
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-`jQuery.fn.loadxhtml` is an important extension to jQuery which allows
-proper loading and in-place DOM update of xhtml views. The existing
-`jQuery.load`_ function does not handle xhtml, hence the addition. The
-API of loadxhtml is roughly similar to that of `jQuery.load`_.
-
-.. _`jQuery.load`: http://api.jquery.com/load/
-
-
-* `url` (mandatory) should be a complete url (typically referencing
- the :class:`cubicweb.web.views.ajaxcontroller.AjaxController`,
- but this is not strictly mandatory)
-
-* `data` (optional) is a dictionary of values given to the
- controller specified through an `url` argument; some keys may have a
- special meaning depending on the choosen controller (such as `fname`
- for the JSonController); the `callback` key, if present, must refer
- to a function to be called at the end of loadxhtml (more on this
- below)
-
-* `reqtype` (optional) specifies the request method to be used (get or
- post); if the argument is 'post', then the post method is used,
- otherwise the get method is used
-
-* `mode` (optional) is one of `replace` (the default) which means the
- loaded node will replace the current node content, `swap` to replace
- the current node with the loaded node, and `append` which will
- append the loaded node to the current node content
-
-About the `callback` option:
-
-* it is called with two parameters: the current node, and a list
- containing the loaded (and post-processed node)
-
-* whenever it returns another function, this function is called in
- turn with the same parameters as above
-
-This mechanism allows callback chaining.
-
-
-A simple example with loadxhtml
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here we are concerned with the retrieval of a specific view to be
-injected in the live DOM. The view will be of course selected
-server-side using an entity eid provided by the client side.
-
-.. sourcecode:: python
-
- from cubicweb.web.views.ajaxcontroller import ajaxfunc
-
- @ajaxfunc(output_type='xhtml')
- def frob_status(self, eid, frobname):
- entity = self._cw.entity_from_eid(eid)
- return entity.view('frob', name=frobname)
-
-.. sourcecode:: javascript
-
- function updateSomeDiv(divid, eid, frobname) {
- var params = {fname:'frob_status', eid: eid, frobname:frobname};
- jQuery('#'+divid).loadxhtml(JSON_BASE_URL, params, 'post');
- }
-
-In this example, the url argument is the base json url of a cube
-instance (it should contain something like
-`http://myinstance/ajax?`). The actual AjaxController method name is
-encoded in the `params` dictionary using the `fname` key.
-
-A more real-life example
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-A frequent need of Web 2 applications is the delayed (or demand
-driven) loading of pieces of the DOM. This is typically achieved using
-some preparation of the initial DOM nodes, jQuery event handling and
-proper use of loadxhtml.
-
-We present here a skeletal version of the mecanism used in CubicWeb
-and available in web/views/tabs.py, in the `LazyViewMixin` class.
-
-.. sourcecode:: python
-
- def lazyview(self, vid, rql=None):
- """ a lazy version of wview """
- w = self.w
- self._cw.add_js('cubicweb.lazy.js')
- urlparams = {'vid' : vid, 'fname' : 'view'}
- if rql is not None:
- urlparams['rql'] = rql
- w(u'<div id="lazy-%s" cubicweb:loadurl="%s">' % (
- vid, xml_escape(self._cw.build_url('json', **urlparams))))
- w(u'</div>')
- self._cw.add_onload(u"""
- jQuery('#lazy-%(vid)s').bind('%(event)s', function() {
- loadNow('#lazy-%(vid)s');});"""
- % {'event': 'load_%s' % vid, 'vid': vid})
-
-This creates a `div` with a specific event associated to it.
-
-The full version deals with:
-
-* optional parameters such as an entity eid, an rset
-
-* the ability to further reload the fragment
-
-* the ability to display a spinning wheel while the fragment is still
- not loaded
-
-* handling of browsers that do not support ajax (search engines,
- text-based browsers such as lynx, etc.)
-
-The javascript side is quite simple, due to loadxhtml awesomeness.
-
-.. sourcecode:: javascript
-
- function loadNow(eltsel) {
- var lazydiv = jQuery(eltsel);
- lazydiv.loadxhtml(lazydiv.attr('cubicweb:loadurl'));
- }
-
-This is all significantly different of the previous `simple example`
-(albeit this example actually comes from real-life code).
-
-Notice how the `cubicweb:loadurl` is used to convey the url
-information. The base of this url is similar to the global javascript
-JSON_BASE_URL. According to the pattern described earlier,
-the `fname` parameter refers to the standard `js_view` method of the
-JSonController. This method renders an arbitrary view provided a view
-id (or `vid`) is provided, and most likely an rql expression yielding
-a result set against which a proper view instance will be selected.
-
-The `cubicweb:loadurl` is one of the 29 attributes extensions to XHTML
-in a specific cubicweb namespace. It is a means to pass information
-without breaking HTML nor XHTML compliance and without resorting to
-ungodly hacks.
-
-Given all this, it is easy to add a small nevertheless useful feature
-to force the loading of a lazy view (for instance, a very
-computation-intensive web page could be scinded into one fast-loading
-part and a delayed part).
-
-On the server side, a simple call to a javascript function is
-sufficient.
-
-.. sourcecode:: python
-
- def forceview(self, vid):
- """trigger an event that will force immediate loading of the view
- on dom readyness
- """
- self._cw.add_onload("triggerLoad('%s');" % vid)
-
-The browser-side definition follows.
-
-.. sourcecode:: javascript
-
- function triggerLoad(divid) {
- jQuery('#lazy-' + divd).trigger('load_' + divid);
- }
-
-
-Javascript library: overview
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-* jquery.* : jquery and jquery UI library
-
-* cubicweb.ajax.js : concentrates all ajax related facilities (it
- extends jQuery with the loahxhtml function, provides a handfull of
- high-level ajaxy operations like asyncRemoteExec, reloadComponent,
- replacePageChunk, getDomFromResponse)
-
-* cubicweb.python.js : adds a number of practical extension to stdanrd
- javascript objects (on Date, Array, String, some list and dictionary
- operations), and a pythonesque way to build classes. Defines a
- CubicWeb namespace.
-
-* cubicweb.htmlhelpers.js : a small bag of convenience functions used
- in various other cubicweb javascript resources (baseuri, progress
- cursor handling, popup login box, html2dom function, etc.)
-
-* cubicweb.widgets.js : provides a widget namespace and constructors
- and helpers for various widgets (mainly facets and timeline)
-
-* cubicweb.edition.js : used by edition forms
-
-* cubicweb.preferences.js : used by the preference form
-
-* cubicweb.facets.js : used by the facets mechanism
-
-There is also javascript support for massmailing, gmap (google maps),
-fckcwconfig (fck editor), timeline, calendar, goa (CubicWeb over
-AppEngine), flot (charts drawing), tabs and bookmarks.
-
-API
-~~~
-
-.. toctree::
- :maxdepth: 1
-
- js_api/index
-
-
-Testing javascript
-~~~~~~~~~~~~~~~~~~
-
-You with the ``cubicweb.qunit.QUnitTestCase`` can include standard Qunit tests
-inside the python unittest run . You simply have to define a new class that
-inherit from ``QUnitTestCase`` and register your javascript test file in the
-``all_js_tests`` lclass attribut. This ``all_js_tests`` is a sequence a
-3-tuple (<test_file, [<dependencies> ,] [<data_files>]):
-
-The <test_file> should contains the qunit test. <dependencies> defines the list
-of javascript file that must be imported before the test script. Dependencies
-are included their definition order. <data_files> are additional files copied in the
-test directory. both <dependencies> and <data_files> are optionnal.
-``jquery.js`` is preincluded in for all test.
-
-.. sourcecode:: python
-
- from cubicweb.qunit import QUnitTestCase
-
- class MyQUnitTest(QUnitTestCase):
-
- all_js_tests = (
- ("relative/path/to/my_simple_testcase.js",)
- ("relative/path/to/my_qunit_testcase.js",(
- "rel/path/to/dependency_1.js",
- "rel/path/to/dependency_2.js",)),
- ("relative/path/to/my_complexe_qunit_testcase.js",(
- "rel/path/to/dependency_1.js",
- "rel/path/to/dependency_2.js",
- ),(
- "rel/path/file_dependency.html",
- "path/file_dependency.json")
- ),
- )
--- a/doc/book/en/devweb/property.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-.. _cwprops:
-
-The property mecanism
----------------------
-
-.. XXX CWProperty and co
-
-
-Property API
-~~~~~~~~~~~~
-.. XXX feed me
-
-Registering and using your own property
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.. XXX feed me
--- a/doc/book/en/devweb/publisher.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-.. _publisher:
-
-Publisher
----------
-
-What happens when an HTTP request is issued ?
-
-The story begins with the ``CubicWebPublisher.main_publish``
-method. We do not get upper in the bootstrap process because it is
-dependant on the used HTTP library. With `twisted`_ however,
-``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the
-real entry point.
-
-.. _`twisted`: http://twistedmatrix.com/trac/
-
-What main_publish does:
-
-* get a controller id and a result set from the path (this is actually
- delegated to the `urlpublisher` component)
-
-* the controller is then selected (if not, this is considered an
- authorization failure and signaled as such) and called
-
-* then either a proper result is returned, in which case the
- request/connection object issues a ``commit`` and returns the result
-
-* or error handling must happen:
-
- * ``ValidationErrors`` pop up there and may lead to a redirect to a
- previously arranged url or standard error handling applies
- * an HTTP 500 error (`Internal Server Error`) is issued
-
-
-Now, let's turn to the controller. There are many of them in
-:mod:`cubicweb.web.views.basecontrollers`. We can just follow the
-default `view` controller that is selected on a `view` path. See the
-:ref:`controllers` chapter for more information on controllers.
-
-The `View` controller's entry point is the `publish` method. It does
-the following:
-
-* compute the `main` view to be applied, using either the given result
- set or building one from a user provided rql string (`rql` and `vid`
- can be forced from the url GET parameters), that is:
-
- * compute the `vid` using the result set and the schema (see
- `cubicweb.web.views.vid_from_rset`)
- * handle all error cases that could happen in this phase
-
-* do some cache management chores
-
-* select a main template (typically `TheMainTemplate`, see chapter
- :ref:`templates`)
-
-* call it with the result set and the computed view.
-
-What happens next actually depends on the template and the view, but
-in general this is the rendering phase.
-
-
-CubicWebPublisher API
-`````````````````````
-
-.. autoclass:: cubicweb.web.application.CubicWebPublisher
- :members:
--- a/doc/book/en/devweb/request.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-The `Request` class (`cubicweb.web.request`)
---------------------------------------------
-
-Overview
-````````
-
-A request instance is created when an HTTP request is sent to the web
-server. It contains informations such as form parameters,
-authenticated user, etc. It is a very prevalent object and is used
-throughout all of the framework and applications, as you'll access to
-almost every resources through it.
-
-**A request represents a user query, either through HTTP or not (we
-also talk about RQL queries on the server side for example).**
-
-Here is a non-exhaustive list of attributes and methods available on
-request objects (grouped by category):
-
-* `Browser control`:
-
- * `ie_browser`: tells if the browser belong to the Internet Explorer
- family
-
-* `User and identification`:
-
- * `user`, instance of `cubicweb.entities.authobjs.CWUser` corresponding to the
- authenticated user
-
-* `Session data handling`
-
- * `session.data` is the dictionary of the session data; it can be
- manipulated like an ordinary Python dictionary
-
-* `Edition` (utilities for edition control):
-
- * `cancel_edition`: resets error url and cleans up pending operations
- * `create_entity`: utility to create an entity (from an etype,
- attributes and relation values)
- * `datadir_url`: returns the url to the merged external resources
- (|cubicweb|'s `web/data` directory plus all `data` directories of
- used cubes)
- * `edited_eids`: returns the list of eids of entities that are
- edited under the current http request
- * `eid_rset(eid)`: utility which returns a result set from an eid
- * `entity_from_eid(eid)`: returns an entity instance from the given eid
- * `encoding`: returns the encoding of the current HTTP request
- * `ensure_ro_rql(rql)`: ensure some rql query is a data request
- * etype_rset
- * `form`, dictionary containing the values of a web form
- * `encoding`, character encoding to use in the response
- * `next_tabindex()`: returns a monotonically growing integer used to
- build the html tab index of forms
-
-* `HTTP`
-
- * `authmode`: returns a string describing the authentication mode
- (http, cookie, ...)
- * `lang`: returns the user agents/browser's language as carried by
- the http request
- * `demote_to_html()`: in the context of an XHTML compliant browser,
- this will force emission of the response as an HTML document
- (using the http content negociation)
-
-* `Cookies handling`
-
- * `get_cookie()`, returns a dictionary containing the value of the header
- HTTP 'Cookie'
- * `set_cookie(cookie, key, maxage=300)`, adds a header HTTP `Set-Cookie`,
- with a minimal 5 minutes length of duration by default (`maxage` = None
- returns a *session* cookie which will expire when the user closes the browser
- window)
- * `remove_cookie(cookie, key)`, forces a value to expire
-
-* `URL handling`
-
- * `build_url(__vid, *args, **kwargs)`: return an absolute URL using
- params dictionary key/values as URL parameters. Values are
- automatically URL quoted, and the publishing method to use may be
- specified or will be guessed.
- * `build_url_params(**kwargs)`: returns a properly prepared (quoted,
- separators, ...) string from the given parameters
- * `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
-
-* `Web resource (.css, .js files, etc.) handling`:
-
- * `add_css(cssfiles)`: adds the given list of css resources to the current
- html headers
- * `add_js(jsfiles)`: adds the given list of javascript resources to the
- current html headers
- * `add_onload(jscode)`: inject the given jscode fragment (a unicode
- string) into the current html headers, wrapped inside a
- document.ready(...) or another ajax-friendly one-time trigger event
- * `add_header(header, values)`: adds the header/value pair to the
- current html headers
- * `status_out`: control the HTTP status of the response
-
-* `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
- * `execute(*args, **kwargs)`, executes an RQL query and return the result set
- * `property_value(key)`, properties management (`CWProperty`)
- * dictionary `data` to store data to share informations between components
- *while a request is executed*
-
-Please note that this class is abstract and that a concrete implementation
-will be provided by the *frontend* web used (in particular *twisted* as of
-today). For the views or others that are executed on the server side,
-most of the interface of `Request` is defined in the session associated
-to the client.
-
-API
-```
-
-The elements we gave in overview for above are built in three layers,
-from ``cubicweb.req.RequestSessionBase``, ``cubicweb.repoapi.Connection`` and
-``cubicweb.web.ConnectionCubicWebRequestBase``.
-
-.. autoclass:: cubicweb.req.RequestSessionBase
- :members:
-
-.. autoclass:: cubicweb.repoapi.Connection
- :members:
-
-.. autoclass:: cubicweb.web.request.ConnectionCubicWebRequestBase
- :members:
--- a/doc/book/en/devweb/resource.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-.. _resources:
-
-Locate resources
-----------------
-
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_resource
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_doc_file
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.locate_all_files
-
-Static files handling
----------------------
-
-.. autoattribute:: cubicweb.web.webconfig.WebConfiguration.static_directory
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_exists
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_open
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_add
-.. automethod:: cubicweb.web.webconfig.WebConfiguration.static_file_del
-
--- a/doc/book/en/devweb/rtags.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-Configuring the user interface
-------------------------------
-
-.. _relation_tags:
-
-Relation tags
-~~~~~~~~~~~~~
-.. automodule:: cubicweb.rtags
-
-.. _uicfg:
-
-The uicfg module
-~~~~~~~~~~~~~~~~
-
-.. note::
-
- The part of uicfg that deals with primary views is in the
- :ref:`primary_view_configuration` chapter.
-
-.. automodule:: cubicweb.web.views.uicfg
-
-
-The uihelper module
-~~~~~~~~~~~~~~~~~~~
-
-.. automodule:: cubicweb.web.uihelper
-
--- a/doc/book/en/devweb/searchbar.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-.. _searchbar:
-
-RQL search bar
---------------
-
-The RQL search bar is a visual component, hidden by default, the tiny *search*
-input being enough for common use cases.
-
-An autocompletion helper is provided to help you type valid queries, both
-in terms of syntax and in terms of schema validity.
-
-.. autoclass:: cubicweb.web.views.magicsearch.RQLSuggestionsBuilder
-
-
-How search is performed
-+++++++++++++++++++++++
-
-You can use the *rql search bar* to either type RQL queries, plain text queries
-or standard shortcuts such as *<EntityType>* or *<EntityType> <attrname> <value>*.
-
-Ultimately, all queries are translated to rql since it's the only
-language understood on the server (data) side. To transform the user
-query into RQL, CubicWeb uses the so-called *magicsearch component*,
-defined in :mod:`cubicweb.web.views.magicsearch`, which in turn
-delegates to a number of query preprocessor that are responsible of
-interpreting the user query and generating corresponding RQL.
-
-The code of the main processor loop is easy to understand:
-
-.. sourcecode:: python
-
- for proc in self.processors:
- try:
- return proc.process_query(uquery, req)
- except (RQLSyntaxError, BadRQLQuery):
- pass
-
-The idea is simple: for each query processor, try to translate the
-query. If it fails, try with the next processor, if it succeeds,
-we're done and the RQL query will be executed.
-
--- a/doc/book/en/devweb/views/basetemplates.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _templates:
-
-Templates
-=========
-
-Templates are the entry point for the |cubicweb| view system. As seen
-in :ref:`views_base_class`, there are two kinds of views: the
-templatable and non-templatable.
-
-
-Non-templatable views
----------------------
-
-Non-templatable views are standalone. They are responsible for all the details
-such as setting a proper content type (or mime type), the proper document
-headers, namespaces, etc. Examples are pure xml views such as RSS or Semantic Web
-views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked Data`_, etc.), and views which generate
-binary files (pdf, excel files, etc.)
-
-.. _`SIOC`: http://sioc-project.org/
-.. _`DOAP`: http://trac.usefulinc.com/doap
-.. _`FOAF`: http://www.foaf-project.org/
-.. _`Linked Data`: http://linkeddata.org/
-
-
-To notice that a view is not templatable, you just have to set the
-view's class attribute `templatable` to `False`. In this case, it
-should set the `content_type` class attribute to the correct MIME
-type. By default, it is text/xhtml. Additionally, if your view
-generate a binary file, you have to set the view's class attribute
-`binary` to `True` too.
-
-
-Templatable views
------------------
-
-Templatable views are not concerned with such pesky details. They
-leave it to the template. Conversely, the template's main job is to:
-
-* set up the proper document header and content type
-* define the general layout of a document
-* invoke adequate views in the various sections of the document
-
-
-Look at :mod:`cubicweb.web.views.basetemplates` and you will find the base
-templates used to generate (X)HTML for your application. The most important
-template there is :class:`~cubicweb.web.views.basetemplates.TheMainTemplate`.
-
-.. _the_main_template_layout:
-
-TheMainTemplate
-~~~~~~~~~~~~~~~
-
-.. _the_main_template_sections:
-
-Layout and sections
-```````````````````
-
-A page is composed as indicated on the schema below :
-
-.. image:: ../../images/main_template.png
-
-The sections dispatches specific views:
-
-* `header`: the rendering of the header is delegated to the
- `htmlheader` view, whose default implementation can be found in
- ``basetemplates.py`` and which does the following things:
-
- * inject the favicon if there is one
- * inject the global style sheets and javascript resources
- * call and display a link to an rss component if there is one available
-
- it also sets up the page title, and fills the actual
- `header` section with top-level components, using the `header` view, which:
-
- * tries to display a logo, the name of the application and the `breadcrumbs`
- * provides a login status area
- * provides a login box (hiden by default)
-
-* `left column`: this is filled with all selectable boxes matching the
- `left` context (there is also a right column but nowadays it is
- seldom used due to bad usability)
-
-* `contentcol`: this is the central column; it is filled with:
-
- * the `rqlinput` view (hidden by default)
- * the `applmessages` component
- * the `contentheader` view which in turns dispatches all available
- content navigation components having the `navtop` context (this
- is used to navigate through entities implementing the IPrevNext
- interface)
- * the view that was given as input to the template's `call`
- method, also dealing with pagination concerns
- * the `contentfooter`
-
-* `footer`: adds all footer actions
-
-.. note::
-
- How and why a view object is given to the main template is explained
- in the :ref:`publisher` chapter.
-
-Configure the main template
-```````````````````````````
-
-You can overload some methods of the
-:class:`~cubicweb.web.views.basetemplates.TheMainTemplate`, in order to fulfil
-your needs. There are also some attributes and methods which can be defined on a
-view to modify the base template behaviour:
-
-* `paginable`: if the result set is bigger than a configurable size, your result
- page will be paginated by default. You can set this attribute to `False` to
- avoid this.
-
-* `binary`: boolean flag telling if the view generates some text or a binary
- stream. Default to False. When view generates text argument given to `self.w`
- **must be a unicode string**, encoded string otherwise.
-
-* `content_type`, view's content type, default to 'text/xhtml'
-
-* `templatable`, boolean flag telling if the view's content should be returned
- directly (when `False`) or included in the main template layout (including
- header, boxes and so on).
-
-* `page_title()`, method that should return a title that will be set as page
- title in the html headers.
-
-* `html_headers()`, method that should return a list of HTML headers to be
- included the html headers.
-
-
-You can also modify certain aspects of the main template of a page
-when building a url or setting these parameters in the req.form:
-
-* `__notemplate`, if present (whatever the value assigned), only the content view
- is returned
-
-* `__force_display`, if present and its value is not null, no pagination whatever
- the number of entities to display (e.g. similar effect as view's `paginable`
- attribute described above.
-
-* `__method`, if the result set to render contains only one entity and this
- parameter is set, it refers to a method to call on the entity by passing it the
- dictionary of the forms parameters, before going the classic way (through step
- 1 and 2 described juste above)
-
-* `vtitle`, a title to be set as <h1> of the content
-
-Other templates
-~~~~~~~~~~~~~~~
-
-There are also the following other standard templates:
-
-* :class:`cubicweb.web.views.basetemplates.LogInTemplate`
-* :class:`cubicweb.web.views.basetemplates.LogOutTemplate`
-* :class:`cubicweb.web.views.basetemplates.ErrorTemplate` specializes
- :class:`~cubicweb.web.views.basetemplates.TheMainTemplate` to do
- proper end-user output if an error occurs during the computation of
- TheMainTemplate (it is a fallback view).
--- a/doc/book/en/devweb/views/baseviews.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-Base views
-----------
-
-|cubicweb| provides a lot of standard views, that can be found in
-:mod:`cubicweb.web.views` sub-modules.
-
-A certain number of views are used to build the web interface, which apply to one
-or more entities. As other appobjects, their identifier is what distinguish them
-from each others. The most generic ones, found in
-:mod:`cubicweb.web.views.baseviews`, are described below.
-
-You'll probably want to customize one or more of the described views which are
-default, generic, implementations.
-
-
-.. automodule:: cubicweb.web.views.baseviews
-
-You will also find modules providing some specific services:
-
-.. automodule:: cubicweb.web.views.navigation
-
--- a/doc/book/en/devweb/views/boxes.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-Boxes
------
-
-(:mod:`cubicweb.web.views.boxes`)
-
-*sidebox*
- This view displays usually a side box of some related entities
- in a primary view.
-
-The action box
-~~~~~~~~~~~~~~~
-
-The ``add_related`` is an automatic menu in the action box that allows to create
-an entity automatically related to the initial entity (context in
-which the box is displayed). By default, the links generated in this
-box are computed from the schema properties of the displayed entity,
-but it is possible to explicitly specify them thanks to the
-`cubicweb.web.views.uicfg.rmode` *relation tag*:
-
-* `link`, indicates that a relation is in general created pointing
- to an existing entity and that we should not to display a link
- for this relation
-
-* `create`, indicates that a relation is in general created pointing
- to new entities and that we should display a link to create a new
- entity and link to it automatically
-
-
-If necessary, it is possible to overwrite the method
-`relation_mode(rtype, targettype, x='subject')` to dynamically
-compute a relation creation category.
-
-Please note that if at least one action belongs to the `addrelated` category,
-the automatic behavior is desactivated in favor of an explicit behavior
-(e.g. display of `addrelated` category actions only).
-
--- a/doc/book/en/devweb/views/breadcrumbs.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-Breadcrumbs
------------
-
-Breadcrumbs are a navigation component to help the user locate himself
-along a path of entities.
-
-Display
-~~~~~~~
-
-Breadcrumbs are displayed by default in the header section (see
-:ref:`the_main_template_sections`). With the default main template,
-the header section is composed by the logo, the application name,
-breadcrumbs and, at the most right, the login box. Breadcrumbs are
-displayed just next to the application name, thus they begin with a
-separator.
-
-Here is the header section of the CubicWeb's forge:
-
-.. image:: ../../images/breadcrumbs_header.png
-
-There are three breadcrumbs components defined in
-:mod:`cubicweb.web.views.ibreadcrumbs`:
-
-- `BreadCrumbEntityVComponent`: displayed for a result set with one line
- if the entity is adaptable to ``IBreadCrumbsAdapter``.
-- `BreadCrumbETypeVComponent`: displayed for a result set with more than
- one line, but with all entities of the same type which can adapt to
- ``IBreadCrumbsAdapter``.
-- `BreadCrumbAnyRSetVComponent`: displayed for any other result set.
-
-Building breadcrumbs
-~~~~~~~~~~~~~~~~~~~~
-
-The ``IBreadCrumbsAdapter`` adapter is defined in the
-:mod:`cubicweb.web.views.ibreadcrumbs` module. It specifies that an
-entity which implements this interface must have a ``breadcrumbs`` and
-a ``parent_entity`` method. A default implementation for each is
-provided. This implementation expoits the ITreeAdapter.
-
-.. note::
-
- Redefining the breadcrumbs is the hammer way to do it. Another way
- is to define an `ITreeAdapter` adapter on an entity type. If
- available, it will be used to compute breadcrumbs.
-
-Here is the API of the ``IBreadCrumbsAdapter`` class:
-
-.. automethod:: cubicweb.web.views.ibreadcrumbs.IBreadCrumbsAdapter.parent_entity
-.. automethod:: cubicweb.web.views.ibreadcrumbs.IBreadCrumbsAdapter.breadcrumbs
-
-If the breadcrumbs method return a list of entities, the
-``cubicweb.web.views.ibreadcrumbs.BreadCrumbView`` is used to display
-the elements.
-
-By default, for any entity, if recurs=True, breadcrumbs method returns
-a list of entities, else a list of a simple string.
-
-In order to see a hierarchical breadcrumbs, entities must have a
-``parent`` method which returns the parent entity. By default this
-method doesn't exist on entity, given that it can not be guessed.
--- a/doc/book/en/devweb/views/idownloadable.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-The 'download' views
-====================
-
-.. automodule:: cubicweb.web.views.idownloadable
-
-Components
-----------
-
-.. autoclass:: cubicweb.web.views.idownloadable.DownloadBox
-
-Download views
---------------
-
-.. autoclass:: cubicweb.web.views.idownloadable.DownloadView
-.. autoclass:: cubicweb.web.views.idownloadable.DownloadLinkView
-.. autoclass:: cubicweb.web.views.idownloadable.IDownloadablePrimaryView
-
-Embedded views
---------------
-
-.. autoclass:: cubicweb.web.views.idownloadable.ImageView
-.. autoclass:: cubicweb.web.views.idownloadable.EHTMLView
--- a/doc/book/en/devweb/views/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-The View system
-===============
-
-This chapter aims to describe the concept of a `view` used all along
-the development of a web application and how it has been implemented
-in |cubicweb|.
-
-
-.. toctree::
- :maxdepth: 3
-
- views
- basetemplates
- primary
- reledit
- baseviews
- startup
- boxes
- table
- xmlrss
- urlpublish
- breadcrumbs
- idownloadable
- wdoc
-
-.. editforms
-.. embedding
-
--- a/doc/book/en/devweb/views/primary.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +0,0 @@
-.. _primary_view:
-
-The Primary View
------------------
-
-By default, *CubicWeb* provides a view that fits every available
-entity type. This is the first view you might be interested in
-modifying. It is also one of the richest and most complex.
-
-It is automatically selected on a one line result set containing an
-entity.
-
-It lives in the :mod:`cubicweb.web.views.primary` module.
-
-The *primary* view is supposed to render a maximum of informations about the
-entity.
-
-.. _primary_view_layout:
-
-Layout
-``````
-
-The primary view has the following layout.
-
-.. image:: ../../images/primaryview_template.png
-
-.. _primary_view_configuration:
-
-Primary view configuration
-``````````````````````````
-
-If you want to customize the primary view of an entity, overriding the primary
-view class may not be necessary. For simple adjustments (attributes or relations
-display locations and styles), a much simpler way is to use uicfg.
-
-Attributes/relations display location
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-In the primary view, there are three sections where attributes and
-relations can be displayed (represented in pink in the image above):
-
-* 'attributes'
-* 'relations'
-* 'sideboxes'
-
-**Attributes** can only be displayed in the attributes section (default
- behavior). They can also be hidden. By default, attributes of type `Password`
- and `Bytes` are hidden.
-
-For instance, to hide the ``title`` attribute of the ``Blog`` entity:
-
-.. sourcecode:: python
-
- from cubicweb.web.views import uicfg
- uicfg.primaryview_section.tag_attribute(('Blog', 'title'), 'hidden')
-
-**Relations** can be either displayed in one of the three sections or hidden.
-
-For relations, there are two methods:
-
-* ``tag_object_of`` for modifying the primary view of the object
-* ``tag_subject_of`` for modifying the primary view of the subject
-
-These two methods take two arguments:
-
-* a triplet ``(subject, relation_name, object)``, where subject or object can be replaced with ``'*'``
-* the section name or ``hidden``
-
-.. sourcecode:: python
-
- pv_section = uicfg.primaryview_section
- # hide every relation `entry_of` in the `Blog` primary view
- pv_section.tag_object_of(('*', 'entry_of', 'Blog'), 'hidden')
-
- # display `entry_of` relations in the `relations`
- # section in the `BlogEntry` primary view
- pv_section.tag_subject_of(('BlogEntry', 'entry_of', '*'), 'relations')
-
-
-Display content
-^^^^^^^^^^^^^^^
-
-You can use ``primaryview_display_ctrl`` to customize the display of attributes
-or relations. Values of ``primaryview_display_ctrl`` are dictionaries.
-
-
-Common keys for attributes and relations are:
-
-* ``vid``: specifies the regid of the view for displaying the attribute or the relation.
-
- If ``vid`` is not specified, the default value depends on the section:
- * ``attributes`` section: 'reledit' view
- * ``relations`` section: 'autolimited' view
- * ``sideboxes`` section: 'sidebox' view
-
-* ``order``: int used to control order within a section. When not specified,
- automatically set according to order in which tags are added.
-
-* ``label``: label for the relations section or side box
-
-* ``showlabel``: boolean telling whether the label is displayed
-
-.. sourcecode:: python
-
- # let us remind the schema of a blog entry
- class BlogEntry(EntityType):
- title = String(required=True, fulltextindexed=True, maxsize=256)
- publish_date = Date(default='TODAY')
- content = String(required=True, fulltextindexed=True)
- entry_of = SubjectRelation('Blog', cardinality='?*')
-
- # now, we want to show attributes
- # with an order different from that in the schema definition
- view_ctrl = uicfg.primaryview_display_ctrl
- for index, attr in enumerate('title', 'content', 'publish_date'):
- view_ctrl.tag_attribute(('BlogEntry', attr), {'order': index})
-
-By default, relations displayed in the 'relations' section are being displayed by
-the 'autolimited' view. This view will use comma separated values, or list view
-and/or limit your rset if there is too much items in it (and generate the "view
-all" link in this case).
-
-You can control this view by setting the following values in the
-`primaryview_display_ctrl` relation tag:
-
-* `limit`, maximum number of entities to display. The value of the
- 'navigation.related-limit' cwproperty is used by default (which is 8 by default).
- If None, no limit.
-
-* `use_list_limit`, number of entities until which they should be display as a list
- (eg using the 'list' view). Below that limit, the 'csv' view is used. If None,
- display using 'csv' anyway.
-
-* `subvid`, the subview identifier (eg view that should be used of each item in the
- list)
-
-Notice you can also use the `filter` key to set up a callback taking the related
-result set as argument and returning it filtered, to do some arbitrary filtering
-that can't be done using rql for instance.
-
-
-.. sourcecode:: python
-
- pv_section = uicfg.primaryview_section
- # in `CWUser` primary view, display `created_by`
- # relations in relations section
- pv_section.tag_object_of(('*', 'created_by', 'CWUser'), 'relations')
-
- # display this relation as a list, sets the label,
- # limit the number of results and filters on comments
- def filter_comment(rset):
- return rset.filtered_rset(lambda x: x.e_schema == 'Comment')
- pv_ctrl = uicfg.primaryview_display_ctrl
- pv_ctrl.tag_object_of(('*', 'created_by', 'CWUser'),
- {'vid': 'list', 'label': _('latest comment(s):'),
- 'limit': True,
- 'filter': filter_comment})
-
-.. warning:: with the ``primaryview_display_ctrl`` rtag, the subject or the
- object of the relation is ignored for respectively ``tag_object_of`` or
- ``tag_subject_of``. To avoid warnings during execution, they should be set to
- ``'*'``.
-
-
-.. automodule:: cubicweb.web.views.primary
-
-
-Example of customization and creation
-`````````````````````````````````````
-
-We'll show you now an example of a ``primary`` view and how to customize it.
-
-If you want to change the way a ``BlogEntry`` is displayed, just
-override the method ``cell_call()`` of the view ``primary`` in
-``BlogDemo/views.py``.
-
-.. sourcecode:: python
-
- from cubicweb.predicates import is_instance
- from cubicweb.web.views.primary import Primaryview
-
- class BlogEntryPrimaryView(PrimaryView):
- __select__ = PrimaryView.__select__ & is_instance('BlogEntry')
-
- def render_entity_attributes(self, entity):
- self.w(u'<p>published on %s</p>' %
- entity.publish_date.strftime('%Y-%m-%d'))
- super(BlogEntryPrimaryView, self).render_entity_attributes(entity)
-
-
-The above source code defines a new primary view for
-``BlogEntry``. The `__reid__` class attribute is not repeated there since it
-is inherited through the `primary.PrimaryView` class.
-
-The selector for this view chains the selector of the inherited class
-with its own specific criterion.
-
-The view method ``self.w()`` is used to output data. Here `lines
-08-09` output HTML for the publication date of the entry.
-
-.. image:: ../../images/lax-book_09-new-view-blogentry_en.png
- :alt: blog entries now look much nicer
-
-Let us now improve the primary view of a blog
-
-.. sourcecode:: python
-
- from logilab.mtconverter import xml_escape
- from cubicweb.predicates import is_instance, one_line_rset
- from cubicweb.web.views.primary import Primaryview
-
- class BlogPrimaryView(PrimaryView):
- __regid__ = 'primary'
- __select__ = PrimaryView.__select__ & is_instance('Blog')
- rql = 'Any BE ORDERBY D DESC WHERE BE entry_of B, BE publish_date D, B eid %(b)s'
-
- def render_entity_relations(self, entity):
- rset = self._cw.execute(self.rql, {'b' : entity.eid})
- for entry in rset.entities():
- self.w(u'<p>%s</p>' % entry.view('inblogcontext'))
-
- class BlogEntryInBlogView(EntityView):
- __regid__ = 'inblogcontext'
- __select__ = is_instance('BlogEntry')
-
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- self.w(u'<a href="%s" title="%s">%s</a>' %
- entity.absolute_url(),
- xml_escape(entity.content[:50]),
- xml_escape(entity.description))
-
-This happens in two places. First we override the
-render_entity_relations method of a Blog's primary view. Here we want
-to display our blog entries in a custom way.
-
-At `line 10`, a simple request is made to build a result set with all
-the entities linked to the current ``Blog`` entity by the relationship
-``entry_of``. The part of the framework handling the request knows
-about the schema and infers that such entities have to be of the
-``BlogEntry`` kind and retrieves them (in the prescribed publish_date
-order).
-
-The request returns a selection of data called a result set. Result
-set objects have an .entities() method returning a generator on
-requested entities (going transparently through the `ORM` layer).
-
-At `line 13` the view 'inblogcontext' is applied to each blog entry to
-output HTML. (Note that the 'inblogcontext' view is not defined
-whatsoever in *CubicWeb*. You are absolutely free to define whole view
-families.) We juste arrange to wrap each blogentry output in a 'p'
-html element.
-
-Next, we define the 'inblogcontext' view. This is NOT a primary view,
-with its well-defined sections (title, metadata, attribtues,
-relations/boxes). All a basic view has to define is cell_call.
-
-Since views are applied to result sets which can be tables of data, we
-have to recover the entity from its (row,col)-coordinates (`line
-20`). Then we can spit some HTML.
-
-.. warning::
-
- Be careful: all strings manipulated in *CubicWeb* are actually
- unicode strings. While web browsers are usually tolerant to
- incoherent encodings they are being served, we should not abuse
- it. Hence we have to properly escape our data. The xml_escape()
- function has to be used to safely fill (X)HTML elements from Python
- unicode strings.
-
-Assuming we added entries to the blog titled `MyLife`, displaying it
-now allows to read its description and all its entries.
-
-.. image:: ../../images/lax-book_10-blog-with-two-entries_en.png
- :alt: a blog and all its entries
-
--- a/doc/book/en/devweb/views/reledit.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,149 +0,0 @@
-.. _reledit:
-
-The "Click and Edit" (also `reledit`) View
-------------------------------------------
-
-The principal way to update data through the Web UI is through the
-`modify` action on entities, which brings a full form. This is
-described in the :ref:`webform` chapter.
-
-There is however another way to perform piecewise edition of entities
-and relations, using a specific `reledit` (for *relation edition*)
-view from the :mod:`cubicweb.web.views.reledit` module.
-
-This is typically applied from the default Primary View (see
-:ref:`primary_view`) on the attributes and relation section. It makes
-small editions more convenient.
-
-Of course, this can be used customely in any other view. Here come
-some explanation about its capabilities and instructions on the way to
-use it.
-
-Using `reledit`
-***************
-
-Let's start again with a simple example:
-
-.. sourcecode:: python
-
- class Company(EntityType):
- name = String(required=True, unique=True)
- boss = SubjectRelation('Person', cardinality='1*')
- status = SubjectRelation('File', cardinality='?*', composite='subject')
-
-In some view code we might want to show these attributes/relations and
-allow the user to edit each of them in turn without having to leave
-the current page. We would write code as below:
-
-.. sourcecode:: python
-
- company.view('reledit', rtype='name', default_value='<name>') # editable name attribute
- company.view('reledit', rtype='boss') # editable boss relation
- company.view('reledit', rtype='status') # editable attribute-like relation
-
-If one wanted to edit the company from a boss's point of view, one
-would have to indicate the proper relation's role. By default the role
-is `subject`.
-
-.. sourcecode:: python
-
- person.view('reledit', rtype='boss', role='object')
-
-Each of these will provide with a different editing widget. The `name`
-attribute will obviously get a text input field. The `boss` relation
-will be edited through a selection box, allowing to pick another
-`Person` as boss. The `status` relation, given that it defines Company
-as a composite entity with one file inside, will provide additional actions
-
-* to `add` a `File` when there is one
-* to `delete` the `File` (if the cardinality allows it)
-
-Moreover, editing the relation or using the `add` action leads to an
-embedded edition/creation form allowing edition of the target entity
-(which is `File` in our example) instead of merely allowing to choose
-amongst existing files.
-
-The `reledit_ctrl` rtag
-***********************
-
-The behaviour of reledited attributes/relations can be finely
-controlled using the reledit_ctrl rtag, defined in
-:mod:`cubicweb.web.views.uicfg`.
-
-This rtag provides four control variables:
-
-* ``default_value``: alternative default value
- The default value is what is shown when there is no value.
-* ``reload``: boolean, eid (to reload to) or function taking subject
- and returning bool/eid This is useful when editing a relation (or
- attribute) that impacts the url or another parts of the current
- displayed page. Defaults to false.
-* ``rvid``: alternative view id (as str) for relation or composite
- edition Default is 'incontext' or 'csv' depending on the
- cardinality. They can also be statically changed by subclassing
- ClickAndEditFormView and redefining _one_rvid (resp. _many_rvid).
-* ``edit_target``: 'rtype' (to edit the relation) or 'related' (to
- edit the related entity) This controls whether to edit the relation
- or the target entity of the relation. Currently only one-to-one
- relations support target entity edition. By default, the 'related'
- option is taken whenever the relation is composite and one-to-one.
-
-Let's see how to use these controls.
-
-.. sourcecode:: python
-
- from logilab.mtconverter import xml_escape
- from cubicweb.web.views.uicfg import reledit_ctrl
- reledit_ctrl.tag_attribute(('Company', 'name'),
- {'reload': lambda x:x.eid,
- 'default_value': xml_escape(u'<logilab tastes better>')})
- reledit_ctrl.tag_object_of(('*', 'boss', 'Person'), {'edit_target': 'related'})
-
-The `default_value` needs to be an xml escaped unicode string.
-
-The `edit_target` tag on the `boss` relation being set to `related` will
-ensure edition of the `Person` entity instead (using a standard
-automatic form) of the association of Company and Person.
-
-Finally, the `reload` key accepts either a boolean, an eid or a
-unicode string representing a url. If an eid is provided, it will be
-internally transformed into a url. The eid/url case helps when one
-needs to reload and the current url is inappropriate. A common case is
-edition of a key attribute, which is part of the current url. If one
-user changed the Company's name from `lozilab` to `logilab`, reloading
-on http://myapp/company/lozilab would fail. Providing the entity's
-eid, then, forces to reload on something like http://myapp/company/42,
-which always work.
-
-
-Disable `reledit`
-*****************
-
-By default, `reledit` is available on attributes and relations displayed in
-the 'attribute' section of the default primary view. If you want to disable
-it for some attribute or relation, you have use `uicfg`:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.uicfg import primaryview_display_ctrl as _pvdc
- _pvdc.tag_attribute(('Company', 'name'), {'vid': 'incontext'})
-
-To deactivate it everywhere it's used automatically, you may use the code snippet
-below somewhere in your cube's views:
-
-.. sourcecode:: python
-
- from cubicweb.web.views import reledit
-
- class DeactivatedAutoClickAndEditFormView(reledit.AutoClickAndEditFormView):
- def _should_edit_attribute(self, rschema):
- return False
-
- def _should_edit_attribute(self, rschema, role):
- return False
-
- def registration_callback(vreg):
- vreg.register_and_replace(DeactivatedAutoClickAndEditFormView,
- reledit.AutoClickAndEditFormView)
-
-
--- a/doc/book/en/devweb/views/startup.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-Startup views
--------------
-
-Startup views are views requiring no context, from which you usually start
-browsing (for instance the index page). The usual selectors are
-:class:`~cubicweb.predicates.none_rset` or :class:`~logilab.common.registry.yes`.
-
-You'll find here a description of startup views provided by the framework.
-
-.. automodule:: cubicweb.web.views.startup
-
-
-Other startup views:
-
-*schema*
- A view dedicated to the display of the schema of the instance
-
-.. XXX to be continued
\ No newline at end of file
--- a/doc/book/en/devweb/views/table.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,145 +0,0 @@
-Table views
------------
-
-.. automodule:: cubicweb.web.views.tableview
-
-Example
-```````
-
-Let us take an example from the timesheet cube:
-
-.. sourcecode:: python
-
- class ActivityResourcesTable(EntityView):
- __regid__ = 'activity.resources.table'
- __select__ = is_instance('Activity')
-
- def call(self, showresource=True):
- eids = ','.join(str(row[0]) for row in self.cw_rset)
- rql = ('Any R,D,DUR,WO,DESCR,S,A, SN,RT,WT ORDERBY D DESC '
- 'WHERE '
- ' A is Activity, A done_by R, R title RT, '
- ' A diem D, A duration DUR, '
- ' A done_for WO, WO title WT, '
- ' A description DESCR, A in_state S, S name SN, '
- ' A eid IN (%s)' % eids)
- rset = self._cw.execute(rql)
- self.wview('resource.table', rset, 'null')
-
- class ResourcesTable(RsetTableView):
- __regid__ = 'resource.table'
- # notice you may wish a stricter selector to check rql's shape
- __select__ = is_instance('Resource')
- # my table headers
- headers = ['Resource', 'diem', 'duration', 'workpackage', 'description', 'state']
- # I want a table where attributes are editable (reledit inside)
- finalvid = 'editable-final'
-
- cellvids = {3: 'editable-final'}
- # display facets and actions with a menu
- layout_args = {'display_filter': 'top',
- 'add_view_actions': None}
-
-To obtain an editable table, you may specify the 'editable-table' view identifier
-using some of `cellvids`, `finalvid` or `nonfinalvid`.
-
-The previous example results in:
-
-.. image:: ../../images/views-table-shadow.png
-
-In order to activate table filter mechanism, the `display_filter` option is given
-as a layout argument. A small arrow will be displayed at the table's top right
-corner. Clicking on `show filter form` action, will display the filter form as
-below:
-
-.. image:: ../../images/views-table-filter-shadow.png
-
-By the same way, you can display additional actions for the selected entities
-by setting `add_view_actions` layout option to `True`. This will add actions
-returned by the view's :meth:`~cubicweb.web.views.tableview.TableMixIn.table_actions`.
-
-You can notice that all columns of the result set are not displayed. This is
-because of given `headers`, implying to display only columns from 0 to
-len(headers).
-
-Also Notice that the `ResourcesTable` view relies on a particular rql shape
-(which is not ensured by the way, the only checked thing is that the result set
-contains instance of the `Resource` type). That usually implies that you can't
-use this view for user specific queries (e.g. generated by facets or typed
-manually).
-
-
-So another option would be to write this view using
-:class:`~cubicweb.web.views.tableview.EntityTableView`, as below.
-
-.. sourcecode:: python
-
- class ResourcesTable(EntityTableView):
- __regid__ = 'resource.table'
- __select__ = is_instance('Resource')
- # table columns definition
- columns = ['resource', 'diem', 'duration', 'workpackage', 'description', 'in_state']
- # I want a table where attributes are editable (reledit inside)
- finalvid = 'editable-final'
- # display facets and actions with a menu
- layout_args = {'display_filter': 'top',
- 'add_view_actions': None}
-
- def workpackage_cell(entity):
- activity = entity.reverse_done_in[0]
- activity.view('reledit', rtype='done_for', role='subject', w=w)
- def workpackage_sortvalue(entity):
- activity = entity.reverse_done_in[0]
- return activity.done_for[0].sortvalue()
-
- column_renderers = {
- 'resource': MainEntityColRenderer(),
- 'workpackage': EntityTableColRenderer(
- header='Workpackage',
- renderfunc=worpackage_cell,
- sortfunc=worpackage_sortvalue,),
- 'in_state': EntityTableColRenderer(
- renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state),
- sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state),
- }
-
-Notice the following point:
-
-* `cell_<column>(w, entity)` will be searched for rendering the content of a
- cell. If not found, `column` is expected to be an attribute of `entity`.
-
-* `cell_sortvalue_<column>(entity)` should return a typed value to use for
- javascript sorting or None for not sortable columns (the default).
-
-* The :func:`etable_entity_sortvalue` decorator will set a 'sortvalue' function
- for the column containing the main entity (the one given as argument to all
- methods), which will call `entity.sortvalue()`.
-
-* You can set a column header using the :func:`etable_header_title` decorator.
- This header will be translated. If it's not an already existing msgid, think
- to mark it using `_()` (the example supposes headers are schema defined msgid).
-
-
-Pro/cons of each approach
-`````````````````````````
-:class:`EntityTableView` and :class:`RsetableView` provides basically the same
-set of features, though they don't share the same properties. Let's try to sum
-up pro and cons of each class.
-
-* `EntityTableView` view is:
-
- - more verbose, but usually easier to understand
-
- - easily extended (easy to add/remove columns for instance)
-
- - doesn't rely on a particular rset shape. Simply give it a title and will be
- listed in the 'possible views' box if any.
-
-* `RsetTableView` view is:
-
- - hard to beat to display barely a result set, or for cases where some of
- `headers`, `displaycols` or `cellvids` could be defined to enhance the table
- while you don't care about e.g. pagination or facets.
-
- - hardly extensible, as you usually have to change places where the view is
- called to modify the RQL (hence the view's result set shape).
--- a/doc/book/en/devweb/views/urlpublish.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-URL publishing
---------------
-
-(:mod:`cubicweb.web.views.urlpublishing`)
-
-.. automodule:: cubicweb.web.views.urlpublishing
-
-.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent
- :members:
-
-
-You can write your own *URLPathEvaluator* class to handle custom paths.
-For instance, if you want */my-card-id* to redirect to the corresponding
-card's primary view, you would write:
-
-.. sourcecode:: python
-
- class CardWikiidEvaluator(URLPathEvaluator):
- priority = 3 # make it be evaluated *before* RestPathEvaluator
-
- def evaluate_path(self, req, segments):
- if len(segments) != 1:
- raise PathDontMatch()
- rset = req.execute('Any C WHERE C wikiid %(w)s',
- {'w': segments[0]})
- if len(rset) == 0:
- # Raise NotFound if no card is found
- raise PathDontMatch()
- return None, rset
-
-On the other hand, you can also deactivate some of the standard
-evaluators in your final application. The only thing you have to
-do is to unregister them, for instance in a *registration_callback*
-in your cube:
-
-.. sourcecode:: python
-
- def registration_callback(vreg):
- vreg.unregister(RestPathEvaluator)
-
-You can even replace the :class:`cubicweb.web.views.urlpublishing.URLPublisherComponent`
-class if you want to customize the whole toolchain process or if you want
-to plug into an early enough extension point to control your request
-parameters:
-
-.. sourcecode:: python
-
- class SanitizerPublisherComponent(URLPublisherComponent):
- """override default publisher component to explicitly ignore
- unauthorized request parameters in anonymous mode.
- """
- unauthorized_form_params = ('rql', 'vid', '__login', '__password')
-
- def process(self, req, path):
- if req.session.anonymous_session:
- self._remove_unauthorized_params(req)
- return super(SanitizerPublisherComponent, self).process(req, path)
-
- def _remove_unauthorized_params(self, req):
- for param in req.form.keys():
- if param in self.unauthorized_form_params:
- req.form.pop(param)
-
-
- def registration_callback(vreg):
- vreg.register_and_replace(SanitizerPublisherComponent, URLPublisherComponent)
-
-
-.. autoclass:: cubicweb.web.views.urlpublishing.RawPathEvaluator
-.. autoclass:: cubicweb.web.views.urlpublishing.EidPathEvaluator
-.. autoclass:: cubicweb.web.views.urlpublishing.URLRewriteEvaluator
-.. autoclass:: cubicweb.web.views.urlpublishing.RestPathEvaluator
-.. autoclass:: cubicweb.web.views.urlpublishing.ActionPathEvaluator
-
-URL rewriting
--------------
-
-(:mod:`cubicweb.web.views.urlrewrite`)
-
-.. autoclass:: cubicweb.web.views.urlrewrite.URLRewriter
- :members:
-
-.. autoclass:: cubicweb.web.views.urlrewrite.SimpleReqRewriter
- :members:
-
-.. autoclass:: cubicweb.web.views.urlrewrite.SchemaBasedRewriter
- :members:
-
-
-``SimpleReqRewriter`` is enough for a certain number of simple cases. If it is not sufficient, ``SchemaBasedRewriter`` allows to do more elaborate things.
-
-Here is an example of ``SimpleReqRewriter`` usage with plain string:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.urlrewrite import SimpleReqRewriter
- class TrackerSimpleReqRewriter(SimpleReqRewriter):
- rules = [
- ('/versions', dict(vid='versionsinfo')),
- ]
-
-When the url is `<base_url>/versions`, the view with the __regid__ `versionsinfo` is displayed.
-
-Here is an example of ``SimpleReqRewriter`` usage with regular expressions:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.urlrewrite import (
- SimpleReqRewriter, rgx)
-
- class BlogReqRewriter(SimpleReqRewriter):
- rules = [
- (rgx('/blogentry/([a-z_]+)\.rss'),
- dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
- 'X creation_date CD, X created_by U, '
- 'U login "%(user)s"'
- % {'user': r'\1'}), vid='rss'))
- ]
-
-When a url matches the regular expression, the view with the __regid__
-`rss` which match the result set is displayed.
-
-Here is an example of ``SchemaBasedRewriter`` usage:
-
-.. sourcecode:: python
-
- from cubicweb.web.views.urlrewrite import (
- SchemaBasedRewriter, rgx, build_rset)
-
- class TrackerURLRewriter(SchemaBasedRewriter):
- rules = [
- (rgx('/project/([^/]+)/([^/]+)/tests'),
- build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
- rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
- ]
--- a/doc/book/en/devweb/views/views.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-
-.. _Views:
-
-Principles
-----------
-
-We'll start with a description of the interface providing a basic
-understanding of the available classes and methods, then detail the
-view selection principle.
-
-A `View` is an object responsible for the rendering of data from the
-model into an end-user consummable form. They typically churn out an
-XHTML stream, but there are views concerned with email other non-html
-outputs.
-
-.. _views_base_class:
-
-Discovering possible views
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is possible to configure the web user interface to have a left box
-showing all the views than can be applied to the current result set.
-
-To enable this, click on your login at the top right corner. Chose
-"user preferences", then "boxes", then "possible views box" and check
-"visible = yes" before validating your changes.
-
-The views listed there we either not selected because of a lower
-score, or they were deliberately excluded by the main template logic.
-
-
-Basic class for views
-~~~~~~~~~~~~~~~~~~~~~
-
-Class :class:`~cubicweb.view.View`
-``````````````````````````````````
-
-.. autoclass:: cubicweb.view.View
-
-The basic interface for views is as follows (remember that the result
-set has a tabular structure with rows and columns, hence cells):
-
-* `render(**context)`, render the view by calling `call` or
- `cell_call` depending on the context
-
-* `call(**kwargs)`, call the view for a complete result set or null
- (the default implementation calls `cell_call()` on each cell of the
- result set)
-
-* `cell_call(row, col, **kwargs)`, call the view for a given cell of a
- result set (`row` and `col` being integers used to access the cell)
-
-* `url()`, returns the URL enabling us to get the view with the current
- result set
-
-* `wview(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of
- identifier `__vid` on the given result set. It is possible to give a
- fallback view identifier that will be used if the requested view is
- not applicable to the result set.
-
-* `html_headers()`, returns a list of HTML headers to be set by the
- main template
-
-* `page_title()`, returns the title to use in the HTML header `title`
-
-Other basic view classes
-````````````````````````
-Here are some of the subclasses of :class:`~cubicweb.view.View` defined in :mod:`cubicweb.view`
-that are more concrete as they relate to data rendering within the application:
-
-.. autoclass:: cubicweb.view.EntityView
-.. autoclass:: cubicweb.view.StartupView
-.. autoclass:: cubicweb.view.EntityStartupView
-.. autoclass:: cubicweb.view.AnyRsetView
-
-Examples of views class
-```````````````````````
-
-- Using `templatable`, `content_type` and HTTP cache configuration
-
-.. sourcecode:: python
-
- class RSSView(XMLView):
- __regid__ = 'rss'
- title = _('rss')
- templatable = False
- content_type = 'text/xml'
- http_cache_manager = MaxAgeHTTPCacheManager
- cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
-
-
-- Using a custom selector
-
-.. sourcecode:: python
-
- class SearchForAssociationView(EntityView):
- """view called by the edition view when the user asks
- to search for something to link to the edited eid
- """
- __regid__ = 'search-associate'
- title = _('search for association')
- __select__ = one_line_rset() & match_search_state('linksearch') & is_instance('Any')
-
-
-XML views, binaries views...
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-For views generating other formats than HTML (an image generated dynamically
-for example), and which can not simply be included in the HTML page generated
-by the main template (see above), you have to:
-
-* set the attribute `templatable` of the class to `False`
-* set, through the attribute `content_type` of the class, the MIME
- type generated by the view to `application/octet-stream` or any
- relevant and more specialised mime type
-
-For views dedicated to binary content creation (like dynamically generated
-images), we have to set the attribute `binary` of the class to `True` (which
-implies that `templatable == False`, so that the attribute `w` of the view could be
-replaced by a binary flow instead of unicode).
--- a/doc/book/en/devweb/views/wdoc.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Online documentation system
-===========================
-
-.. automodule:: cubicweb.web.views.wdoc
-
-Help views
-----------
-.. autoclass:: cubicweb.web.views.wdoc.InlineHelpView
-
-Actions
--------
-.. autoclass:: cubicweb.web.views.wdoc.HelpAction
-.. autoclass:: cubicweb.web.views.wdoc.AboutAction
--- a/doc/book/en/devweb/views/xmlrss.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-.. _XmlAndRss:
-
-XML and RSS views
------------------
-
-(:mod:`cubicweb.web.views.xmlrss`)
-
-Overview
-+++++++++
-
-*rss*
- Creates a RSS/XML view and call the view `rssitem` for each entity of
- the result set.
-
-*rssitem*
- Create a RSS/XML view for each entity based on the results of the dublin core
- methods of the entity (`dc_*`)
-
-RSS Channel Example
-++++++++++++++++++++
-
-Assuming you have several blog entries, click on the title of the
-search box in the left column. A larger search box should appear. Enter:
-
-.. sourcecode:: sql
-
- Any X ORDERBY D WHERE X is BlogEntry, X creation_date D
-
-and you get a list of blog entries.
-
-Click on your login at the top right corner. Chose "user preferences",
-then "boxes", then "possible views box" and check "visible = yes"
-before validating your changes.
-
-Enter the same query in the search box and you will see the same list,
-plus a box titled "possible views" in the left column. Click on
-"entityview", then "RSS".
-
-You just applied the "RSS" view to the RQL selection you requested.
-
-That's it, you have a RSS channel for your blog.
-
-Try again with:
-
-.. sourcecode:: sql
-
- Any X ORDERBY D WHERE X is BlogEntry, X creation_date D,
- X entry_of B, B title "MyLife"
-
-Another RSS channel, but a bit more focused.
-
-A last one for the road:
-
-.. sourcecode:: sql
-
- Any C ORDERBY D WHERE C is Comment, C creation_date D LIMIT 15
-
-displayed with the RSS view, that's a channel for the last fifteen
-comments posted.
-
-[WRITE ME]
-
-* show that the RSS view can be used to display an ordered selection
- of blog entries, thus providing a RSS channel
-
-* show that a different selection (by category) means a different channel
Binary file doc/book/en/images/03-transitions-view_en.png has changed
Binary file doc/book/en/images/archi_globale.png has changed
Binary file doc/book/en/images/archi_globale_en.png has changed
Binary file doc/book/en/images/breadcrumbs_header.png has changed
Binary file doc/book/en/images/facet_date_range.png has changed
Binary file doc/book/en/images/facet_has_image.png has changed
Binary file doc/book/en/images/facet_overview.png has changed
Binary file doc/book/en/images/facet_range.png has changed
Binary file doc/book/en/images/lax-book_00-login_en.png has changed
Binary file doc/book/en/images/lax-book_01-start_en.png has changed
Binary file doc/book/en/images/lax-book_02-cookie-values_en.png has changed
Binary file doc/book/en/images/lax-book_02-create-blog_en.png has changed
Binary file doc/book/en/images/lax-book_03-list-one-blog_en.png has changed
Binary file doc/book/en/images/lax-book_03-site-config-panel_en.png has changed
Binary file doc/book/en/images/lax-book_03-state-submitted_en.png has changed
Binary file doc/book/en/images/lax-book_03-transitions-view_en.png has changed
Binary file doc/book/en/images/lax-book_04-detail-one-blog_en.png has changed
Binary file doc/book/en/images/lax-book_05-list-two-blog_en.png has changed
Binary file doc/book/en/images/lax-book_06-add-relation-entryof_en.png has changed
Binary file doc/book/en/images/lax-book_06-main-template-logo_en.png has changed
Binary file doc/book/en/images/lax-book_07-detail-one-blogentry_en.png has changed
Binary file doc/book/en/images/lax-book_08-schema_en.png has changed
Binary file doc/book/en/images/lax-book_09-new-view-blogentry_en.png has changed
Binary file doc/book/en/images/lax-book_10-blog-with-two-entries_en.png has changed
Binary file doc/book/en/images/main_template.png has changed
--- a/doc/book/en/images/main_template.svg Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="1036.6421"
- height="845.07812"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.46"
- sodipodi:docname="main_template.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape"
- version="1.0"
- inkscape:export-filename="/home/auc/cw/doc/book/en/images/main_template.png"
- inkscape:export-xdpi="60.659016"
- inkscape:export-ydpi="60.659016">
- <defs
- id="defs4">
- <inkscape:perspective
- sodipodi:type="inkscape:persp3d"
- inkscape:vp_x="0 : 526.18109 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_z="744.09448 : 526.18109 : 1"
- inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
- id="perspective10" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="0.80355603"
- inkscape:cx="510.91495"
- inkscape:cy="422.53906"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:window-width="925"
- inkscape:window-height="1168"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:snap-bbox="true" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Calque 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(162.2968,90.697922)">
- <rect
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect2439"
- width="854.37006"
- height="698.2019"
- x="20.307629"
- y="-20.575344" />
- <rect
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3301"
- width="816.3457"
- height="508.15628"
- x="31.751091"
- y="96.33345" />
- <g
- id="g3220"
- transform="matrix(1.0035394,0,0,1,0.5745006,0)">
- <rect
- y="-89.447922"
- x="-161.0468"
- height="55.714287"
- width="1031.1713"
- id="rect3240"
- style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.50000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
- <text
- id="text3264"
- y="-51.771908"
- x="757.85767"
- style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3266"
- y="-51.771908"
- x="757.85767"
- sodipodi:role="line">header</tspan></text>
- </g>
- <rect
- style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3270"
- width="167.87744"
- height="707.71222"
- x="-160.02441"
- y="-24.671618" />
- <g
- id="g2434"
- transform="matrix(0.975467,0,0,1,0.6942419,-3.6587365)">
- <rect
- y="35.365849"
- x="29.548275"
- height="55.714287"
- width="842.59979"
- id="rect3279"
- style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
- <text
- id="text3281"
- y="72.885193"
- x="681.65283"
- style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3283"
- y="72.885193"
- x="681.65283"
- sodipodi:role="line">contentheader</tspan></text>
- </g>
- <g
- id="g3170"
- transform="matrix(1.0023324,0,0,1,-2.0421673,-10.976211)">
- <rect
- y="698.6355"
- x="-158.28485"
- height="55.714287"
- width="1032.5997"
- id="rect3285"
- style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
- <text
- id="text3287"
- y="736.52045"
- x="770.28204"
- style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3289"
- y="736.52045"
- x="770.28204"
- sodipodi:role="line">footer</tspan></text>
- </g>
- <g
- id="g3211" />
- <g
- id="g3215"
- transform="matrix(0.9712065,0,0,1,0.7659296,-17.074106)">
- <rect
- style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3291"
- width="844.62012"
- height="55.714287"
- x="27.850754"
- y="629.88562" />
- <text
- id="text3293"
- y="666.60339"
- x="692.85773"
- style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3295"
- y="666.60339"
- x="692.85773"
- sodipodi:role="line">contentfooter</tspan></text>
- </g>
- <text
- xml:space="preserve"
- style="font-size:23.38711166px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="-143.67273"
- y="20.58094"
- id="text3297"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan2432"
- x="-143.67273"
- y="20.58094">left column</tspan></text>
- <text
- transform="scale(0.9876573,1.0124969)"
- id="text3175"
- y="12.071429"
- x="721.0575"
- style="font-size:23.09845161px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3177"
- y="12.071429"
- x="721.0575"
- sodipodi:role="line">contentcol</tspan></text>
- <text
- transform="scale(0.9876573,1.0124969)"
- id="text3179"
- y="126.27104"
- x="701.45959"
- style="font-size:23.09845161px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3181"
- y="126.27104"
- x="701.45959"
- sodipodi:role="line">contentmain</tspan></text>
- </g>
-</svg>
Binary file doc/book/en/images/main_template_layout.png has changed
Binary file doc/book/en/images/primaryview_template.png has changed
--- a/doc/book/en/images/primaryview_template.svg Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="1036.6421"
- height="845.07812"
- id="svg2"
- sodipodi:version="0.32"
- inkscape:version="0.46"
- sodipodi:docname="primaryview_template.svg"
- inkscape:output_extension="org.inkscape.output.svg.inkscape"
- version="1.0"
- inkscape:export-filename="/home/steph/local/fcubicweb/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="43.451603"
- inkscape:export-ydpi="43.451603">
- <defs
- id="defs4">
- <inkscape:perspective
- sodipodi:type="inkscape:persp3d"
- inkscape:vp_x="0 : 526.18109 : 1"
- inkscape:vp_y="0 : 1000 : 0"
- inkscape:vp_z="744.09448 : 526.18109 : 1"
- inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
- id="perspective10" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="0.9357135"
- inkscape:cx="518.32104"
- inkscape:cy="337.0428"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:window-width="1307"
- inkscape:window-height="1168"
- inkscape:window-x="0"
- inkscape:window-y="0" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Calque 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(162.2968,90.697922)">
- <g
- id="g3869"
- transform="matrix(1,0,0,1.0373644,0,-72.039777)"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449">
- <rect
- y="-15.840891"
- x="-159.08963"
- height="770.11017"
- width="1033.0049"
- id="rect3301"
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.90144825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
- <text
- id="text3865"
- y="19.784882"
- x="-150.07172"
- style="font-size:28.67479324px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
- xml:space="preserve"><tspan
- id="tspan3867"
- y="19.784882"
- x="-150.07172"
- sodipodi:role="line">contentmain</tspan></text>
- </g>
- <rect
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.45654476;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect2383"
- width="772.32111"
- height="43.888428"
- x="-131.1837"
- y="86.559296"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%"
- x="-122.69418"
- y="115.50363"
- id="text2385"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- x="-122.69418"
- y="115.50363"
- id="tspan3163">navcontenttop</tspan></text>
- <rect
- style="fill:#ffd5d5;fill-rule:evenodd;stroke:#000000;stroke-width:3.06523442;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3167"
- width="770.26868"
- height="203.16078"
- x="-125.88269"
- y="172.90417"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="348.26724"
- y="205.34305"
- id="text3169"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- x="348.26724"
- y="205.34305"
- id="tspan3171">render_entity_attributes()</tspan></text>
- <rect
- style="fill:#ffd5d5;fill-rule:evenodd;stroke:#000000;stroke-width:3.06523442;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3173"
- width="769.93549"
- height="237.84663"
- x="-125.03326"
- y="391.32156"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="360.99954"
- y="428.38055"
- id="text3175"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- x="360.99954"
- y="428.38055"
- id="tspan3177">render_entity_relations()</tspan></text>
- <rect
- style="fill:#ffd5d5;fill-rule:evenodd;stroke:#000000;stroke-width:2.15903592;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3185"
- width="178.93939"
- height="612.36584"
- x="667.10443"
- y="84.64225"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%"
- x="105.32364"
- y="-810.65997"
- id="text3187"
- transform="matrix(0,1,-1,0,0,0)"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- id="tspan2408">render_side_boxes()</tspan></text>
- <rect
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:3.0652349;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3191"
- width="771.97766"
- height="55.647793"
- x="-127.80586"
- y="642.0293"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="-121.22153"
- y="674.1748"
- id="text3181"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- x="-121.22153"
- y="674.1748"
- id="tspan3183">navcontentbottom</tspan></text>
- <rect
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.68198514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3881"
- width="986.90503"
- height="45.800392"
- x="-128.34428"
- y="-31.574066"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="355.60541"
- y="-2.7424495"
- id="text3883"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- x="355.60541"
- y="-2.7424495"
- id="tspan3885">render_entity_toolbox(), render_entity_title()</tspan></text>
- <rect
- style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.68198514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- id="rect3890"
- width="986.90503"
- height="45.800392"
- x="-128.87863"
- y="19.723684"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449" />
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="565.71027"
- y="50.135612"
- id="text3892"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- x="565.71027"
- y="50.135612"
- id="tspan3894">render_entity_summary()</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="87.154541"
- y="114.2578"
- id="text3899"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- id="tspan3903"
- x="87.154541"
- y="114.2578">content_navigation_components('navcontenttop')</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
- x="88.46772"
- y="675.71582"
- id="text2410"
- sodipodi:linespacing="125%"
- inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
- inkscape:export-xdpi="60.912449"
- inkscape:export-ydpi="60.912449"><tspan
- sodipodi:role="line"
- id="tspan2412"
- x="88.46772"
- y="675.71582">content_navigation_components('navcontenttop')</tspan></text>
- </g>
-</svg>
Binary file doc/book/en/images/request_session.png has changed
--- a/doc/book/en/images/request_session.svg Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="85.960938"
- height="12.382812"
- id="svg2"
- version="1.1"
- inkscape:version="0.48.3.1 r9886"
- sodipodi:docname="request_session.svg">
- <defs
- id="defs4">
- <marker
- inkscape:stockid="Arrow1Lend"
- orient="auto"
- refY="0.0"
- refX="0.0"
- id="Arrow1Lend"
- style="overflow:visible;">
- <path
- id="path3822"
- d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
- style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
- transform="scale(0.8) rotate(180) translate(12.5,0)" />
- </marker>
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="0.98994949"
- inkscape:cx="25.928992"
- inkscape:cy="-185.87004"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0"
- inkscape:window-width="958"
- inkscape:window-height="1160"
- inkscape:window-x="0"
- inkscape:window-y="38"
- inkscape:window-maximized="0"
- inkscape:snap-global="true" />
- <metadata
- id="metadata7">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-263.52249,-495.73373)">
- <rect
- style="fill:#ffffff;stroke:#000000;stroke-width:0.92460138;stroke-opacity:1"
- id="rect3773"
- width="214.15233"
- height="184.80336"
- x="57.578697"
- y="366.01306" />
- <rect
- id="rect2985"
- width="216.86372"
- height="183.54575"
- x="348.50262"
- y="367.78079"
- style="fill:#ffffff;stroke:#000000;stroke-width:0.55298227;stroke-opacity:1" />
- <text
- xml:space="preserve"
- style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="376.7869"
- y="399.80365"
- id="text3755"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3757"
- x="376.7869"
- y="399.80365">Repository</tspan></text>
- <rect
- style="fill:#ffffff;stroke:#000000;stroke-opacity:1"
- id="rect3759"
- width="144.45181"
- height="104.04572"
- x="237.38585"
- y="423.03714" />
- <text
- xml:space="preserve"
- style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="262.63968"
- y="470.51431"
- id="text3761"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3763"
- x="262.63968"
- y="470.51431">REPOAPI</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="262.63968"
- y="507.88998"
- id="text3765"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3767"
- x="262.63968"
- y="507.88998">connection</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="419.21332"
- y="509.91025"
- id="text3769"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3771"
- x="419.21332"
- y="509.91025">session</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="102.02541"
- y="397.78333"
- id="text3775"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3777"
- x="102.02541"
- y="397.78333">Client</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="116.16754"
- y="507.88995"
- id="text3779"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3781"
- x="116.16754"
- y="507.88995">request</tspan></text>
- <text
- xml:space="preserve"
- style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="361.50729"
- y="585.89832"
- id="text3802"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3804"
- x="361.50729"
- y="585.89832">database </tspan><tspan
- sodipodi:role="line"
- x="361.50729"
- y="605.89832"
- id="tspan3806">connection</tspan></text>
- <rect
- style="fill:#ffffff;stroke:#000000;stroke-width:1.48014534;stroke-opacity:1"
- id="rect3808"
- width="192.09367"
- height="58.095726"
- x="365.79443"
- y="621.50018" />
- <text
- xml:space="preserve"
- style="font-size:36px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
- x="369.5885"
- y="662.66992"
- id="text3810"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan3812"
- x="369.5885"
- y="662.66992">Database</tspan></text>
- <path
- style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:none"
- d="M 197.57252,125.76645 195.76971,55.592808"
- id="path4260"
- inkscape:connector-type="polyline"
- inkscape:connector-curvature="3"
- inkscape:connection-start="#rect3808"
- inkscape:connection-start-point="d4"
- inkscape:connection-end="#rect2985"
- inkscape:connection-end-point="d4"
- transform="translate(263.52249,495.73373)" />
- </g>
-</svg>
Binary file doc/book/en/images/server-class-diagram.png has changed
Binary file doc/book/en/images/tutos-base_blog-form_en.png has changed
Binary file doc/book/en/images/tutos-base_blog-primary-after-post-creation_en.png has changed
Binary file doc/book/en/images/tutos-base_blog-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_blogs-list_en.png has changed
Binary file doc/book/en/images/tutos-base_form-generic-relations_en.png has changed
Binary file doc/book/en/images/tutos-base_index_en.png has changed
Binary file doc/book/en/images/tutos-base_login-form_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-custom-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-default-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-community-taggable-primary_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-custom-footer_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-schema_en.png has changed
Binary file doc/book/en/images/tutos-base_myblog-siteinfo_en.png has changed
Binary file doc/book/en/images/tutos-base_schema_en.png has changed
Binary file doc/book/en/images/tutos-base_siteconfig_en.png has changed
Binary file doc/book/en/images/tutos-base_user-menu_en.png has changed
Binary file doc/book/en/images/tutos-photowebsite_background-image.png has changed
Binary file doc/book/en/images/tutos-photowebsite_boxes.png has changed
Binary file doc/book/en/images/tutos-photowebsite_breadcrumbs.png has changed
Binary file doc/book/en/images/tutos-photowebsite_facets.png has changed
Binary file doc/book/en/images/tutos-photowebsite_grey-box.png has changed
Binary file doc/book/en/images/tutos-photowebsite_index-after.png has changed
Binary file doc/book/en/images/tutos-photowebsite_index-before.png has changed
Binary file doc/book/en/images/tutos-photowebsite_login-box.png has changed
Binary file doc/book/en/images/tutos-photowebsite_prevnext.png has changed
Binary file doc/book/en/images/tutos-photowebsite_ui1.png has changed
Binary file doc/book/en/images/tutos-photowebsite_ui2.png has changed
Binary file doc/book/en/images/tutos-photowebsite_ui3.png has changed
Binary file doc/book/en/images/undo_history-view_w600.png has changed
Binary file doc/book/en/images/undo_mesage_w600.png has changed
Binary file doc/book/en/images/undo_startup-link_w600.png has changed
Binary file doc/book/en/images/views-table-filter-shadow.png has changed
Binary file doc/book/en/images/views-table-filter.png has changed
Binary file doc/book/en/images/views-table-shadow.png has changed
Binary file doc/book/en/images/views-table.png has changed
--- a/doc/book/en/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _contents:
-
-=====================================================
-|cubicweb| - The Semantic Web is a construction game!
-=====================================================
-
-|cubicweb| is a semantic web application framework, licensed under the LGPL,
-that empowers developers to efficiently build web applications by reusing
-components (called `cubes`) and following the well known object-oriented design
-principles.
-
-Its main features are:
-
-* an engine driven by the explicit :ref:`data model
- <TutosBaseCustomizingTheApplicationDataModel>` of the application,
-
-* a query language named :ref:`RQL <RQL>` similar to W3C's SPARQL,
-
-* a :ref:`selection+view <TutosBaseCustomizingTheApplicationCustomViews>`
- mechanism for semi-automatic XHTML/XML/JSON/text generation,
-
-* a library of reusable :ref:`components <Cube>` (data model and views) that
- fulfill common needs,
-
-* the power and flexibility of the Python_ programming language,
-
-* the reliability of SQL databases, LDAP directories, Subversion and Mercurial
- for storage backends.
-
-Built since 2000 from an R&D effort still continued, supporting 100,000s of
-daily visits at some production sites, |cubicweb| is a proven end to end solution
-for semantic web application development that promotes quality, reusability and
-efficiency.
-
-The unbeliever will read the :ref:`Tutorials`.
-
-The hacker will join development at the forge_.
-
-The impatient developer will move right away to :ref:`SetUpEnv` then to :ref:`ConfigEnv`.
-
-The chatter lover will join the `jabber forum`_, the `mailing-list`_ and the blog_.
-
-.. _Logilab: http://www.logilab.fr/
-.. _forge: http://www.cubicweb.org/project/
-.. _Python: http://www.python.org/
-.. _`jabber forum`: http://www.logilab.org/blogentry/6718
-.. _`mailing-list`: http://lists.cubicweb.org/mailman/listinfo/cubicweb
-.. _blog: http://www.cubicweb.org/blog/1238
-
-.. toctree::
- :maxdepth: 2
-
- intro/index
- tutorials/index
-
-.. toctree::
- :maxdepth: 3
-
- devrepo/index
- devweb/index
-
-.. toctree::
- :maxdepth: 2
-
- admin/index
- additionnal_services/index
- annexes/index
-
-See also:
-
-* the :ref:`genindex`,
-* the :ref:`modindex`,
--- a/doc/book/en/intro/concepts.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,306 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Concepts:
-
-The Core Concepts of |cubicweb|
-===============================
-
-This section defines some terms and core concepts of the |cubicweb| framework. To
-avoid confusion while reading this book, take time to go through the following
-definitions and use this section as a reference during your reading.
-
-
-.. _Cube:
-
-Cubes
------
-
-A cube is a software component made of three parts: its data model
-(:mod:`schema`), its logic (:mod:`entities`) and its user interface
-(:mod:`views`).
-
-A cube can use other cubes as building blocks and assemble them to provide a
-whole with richer functionnalities than its parts. The cubes `cubicweb-blog`_ and
-`cubicweb-comment`_ could be used to make a cube named *myblog* with commentable
-blog entries.
-
-The `CubicWeb.org Forge`_ offers a large number of cubes developed by the community
-and available under a free software license.
-
-.. note::
-
- The command :command:`cubicweb-ctl list` displays the list of available cubes.
-
-.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/
-.. _`cubicweb-blog`: http://www.cubicweb.org/project/cubicweb-blog
-.. _`cubicweb-comment`: http://www.cubicweb.org/project/cubicweb-comment
-
-
-.. _Instance:
-
-Instances
----------
-
-An instance is a runnable application installed on a computer and based on a
-cube.
-
-The instance directory contains the configuration files. Several instances can be
-created and based on the same cube. For exemple, several software forges can be
-set up on one computer system based on the `cubicweb-forge`_ cube.
-
-.. _`cubicweb-forge`: http://www.cubicweb.org/project/cubicweb-forge
-
-Instances can be of three different types: all-in-one, web engine or data
-repository. For applications that support high traffic, several web (front-end)
-and data (back-end) instances can be set-up to share the load.
-
-.. image:: ../images/archi_globale_en.png
-
-The command :command:`cubicweb-ctl list` also displays the list of instances
-installed on your system.
-
-.. note::
-
- The term application is used to refer to "something that should do something as
- a whole", eg more like a project and so can refer to an instance or to a cube,
- depending on the context. This book will try to use *application*, *cube* and
- *instance* as appropriate.
-
-
-.. _RepositoryIntro:
-
-Data Repository
----------------
-
-The data repository [1]_ encapsulates and groups an access to one or
-more data sources (including SQL databases, LDAP repositories, other
-|cubicweb| instance repositories, filesystems, Google AppEngine's
-DataStore, etc).
-
-All interactions with the repository are done using the `Relation Query Language`
-(:ref:`RQL`). The repository federates the data sources and hides them from the
-querier, which does not realize when a query spans several data sources
-and requires running sub-queries and merges to complete.
-
-Application logic can be mapped to data events happenning within the
-repository, like creation of entities, deletion of relations,
-etc. This is used for example to send email notifications when the
-state of an object changes. See :ref:`HookIntro` below.
-
-.. [1] not to be confused with a Mercurial repository or a Debian repository.
-.. _`Python Remote Objects`: http://pythonhosted.org/Pyro4/
-
-.. _WebEngineIntro:
-
-Web Engine
-----------
-
-The web engine replies to http requests and runs the user interface.
-
-By default the web engine provides a `CRUD`_ user interface based on
-the data model of the instance. Entities can be created, displayed,
-updated and deleted. As the default user interface is not very fancy,
-it is usually necessary to develop your own.
-
-It is common to run the web engine and the repository in the same
-process (see instances of type all-in-one above), but this is not a
-requirement. A repository can be set up to be accessed remotely using
-Pyro (`Python Remote Objects`_) and act as a standalone server, which
-can be directly accessed or also through a standalone web engine.
-
-.. _`CRUD`: http://en.wikipedia.org/wiki/Create,_read,_update_and_delete
-
-.. _SchemaIntro:
-
-Schema (Data Model)
--------------------
-
-The data model of a cube is described as an entity-relationship schema using a
-comprehensive language made of Python classes imported from the yams_ library.
-
-.. _yams: http://www.logilab.org/project/yams/
-
-An `entity type` defines a sequence of attributes. Attributes may be
-of the following types: `String`, `Int`, `Float`, `Boolean`, `Date`,
-`Time`, `Datetime`, `Interval`, `Password`, `Bytes`, `RichString`.
-
-A `relation type` is used to define an oriented binary relation
-between entity types. The left-hand part of a relation is named the
-`subject` and the right-hand part is named the `object`.
-
-A `relation definition` is a triple (*subject entity type*, *relation type*, *object
-entity type*) associated with a set of properties such as cardinality,
-constraints, etc.
-
-Permissions can be set on entity types or relation definition to control who
-will be able to create, read, update or delete entities and relations. Permissions
-are granted to groups (to which users may belong) or using rql expressions (if the
-rql expression returns some results, the permission is granted).
-
-Some meta-data necessary to the system are added to the data model. That includes
-entities like users and groups, the entities used to store the data model
-itself and attributes like unique identifier, creation date, creator, etc.
-
-When you create a new |cubicweb| instance, the schema is stored in the database.
-When the cubes the instance is based on evolve, they may change their data model
-and provide migration scripts that will be executed when the administrator will
-run the upgrade process for the instance.
-
-
-.. _VRegistryIntro:
-
-Registries and application objects
-----------------------------------
-
-Application objects
-~~~~~~~~~~~~~~~~~~~
-
-Besides a few core functionalities, almost every feature of the framework is
-achieved by dynamic objects (`application objects` or `appobjects`) stored in a
-two-levels registry. Each object is affected to a registry with
-an identifier in this registry. You may have more than one object sharing an
-identifier in the same registry:
-
- object's `__registry__` : object's `__regid__` : [list of app objects]
-
-In other words, the `registry` contains several (sub-)registries which hold a
-list of appobjects associated to an identifier.
-
-The base class of appobjects is :class:`cubicweb.appobject.AppObject`.
-
-Selectors
-~~~~~~~~~
-
-At runtime, appobjects can be selected in a registry according to some
-contextual information. Selection is done by comparing the *score*
-returned by each appobject's *selector*.
-
-The better the object fits the context, the higher the score. Scores
-are the glue that ties appobjects to the data model. Using them
-appropriately is an essential part of the construction of well behaved
-cubes.
-
-|cubicweb| provides a set of basic selectors that may be parametrized. Also,
-selectors can be combined with the `~` unary operator (negation) and the binary
-operators `&` and `|` (respectivly 'and' and 'or') to build more complex
-selectors. Of course complex selectors may be combined too. Last but not least, you
-can write your own selectors.
-
-The `registry`
-~~~~~~~~~~~~~~~
-
-At startup, the `registry` inspects a number of directories looking
-for compatible class definitions. After a recording process, the
-objects are assigned to registries and become available through the
-selection process.
-
-In a cube, application object classes are looked in the following modules or
-packages:
-
-- `entities`
-- `views`
-- `hooks`
-- `sobjects`
-
-There are three common ways to look up some application object from a
-registry:
-
-* get the most appropriate object by specifying an identifier and
- context objects. The object with the greatest score is
- selected. There should always be a single appobject with a greater
- score than others for a particular context.
-
-* get all objects applying to a context by specifying a registry. A
- list of objects will be returned containing the object with the
- highest score (> 0) for each identifier in that registry.
-
-* get the object within a particular registry/identifier. No selection
- process is involved: the registry will expect to find a single
- object in that cell.
-
-
-.. _RQLIntro:
-
-The RQL query language
-----------------------
-
-No need for a complicated ORM when you have a powerful data
-manipulation language.
-
-All the persistent data in a |cubicweb| instance is retrieved and
-modified using RQL (see :ref:`rql_intro`).
-
-This query language is inspired by SQL but is on a higher level in order to
-emphasize browsing relations.
-
-
-Result set
-~~~~~~~~~~
-
-Every request made (using RQL) to the data repository returns an object we call a
-Result Set. It enables easy use of the retrieved data, providing a translation
-layer between the backend's native datatypes and |cubicweb| schema's EntityTypes.
-
-Result sets provide access to the raw data, yielding either basic Python data
-types, or schema-defined high-level entities, in a straightforward way.
-
-
-.. _ViewIntro:
-
-Views
------
-
-**CubicWeb is data driven**
-
-The view system is loosely coupled to data through the selection system explained
-above. Views are application objects with a dedicated interface to 'render'
-something, eg producing some html, text, xml, pdf, or whatsover that can be
-displayed to a user.
-
-Views actually are partitioned into different kind of objects such as
-`templates`, `boxes`, `components` and proper `views`, which are more
-high-level abstraction useful to build the user interface in an object
-oriented way.
-
-
-.. _HookIntro:
-
-Hooks and operations
---------------------
-
-**CubicWeb provides an extensible data repository**
-
-The data model defined using Yams types allows to express the data
-model in a comfortable way. However several aspects of the data model
-can not be expressed there. For instance:
-
-* managing computed attributes
-
-* enforcing complicated business rules
-
-* real-world side-effects linked to data events (email notification
- being a prime example)
-
-The hook system is much like the triggers of an SQL database engine,
-except that:
-
-* it is not limited to one specific SQL backend (every one of them
- having an idiomatic way to encode triggers), nor to SQL backends at
- all (think about LDAP or a Subversion repository)
-
-* it is well-coupled to the rest of the framework
-
-Hooks are also application objects (in the `hooks` registry) and
-selected on events such as after/before add/update/delete on
-entities/relations, server startup or shutdown, etc.
-
-`Operations` may be instantiated by hooks to do further processing at different
-steps of the transaction's commit / rollback, which usually can not be done
-safely at the hook execution time.
-
-Hooks and operation are an essential building block of any moderately complicated
-cubicweb application.
-
-.. note::
- RQL queries executed in hooks and operations are *unsafe* by default, i.e. the
- read and write security is deactivated unless explicitly asked.
--- a/doc/book/en/intro/history.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-A little history...
-===================
-
-*CubicWeb* is a semantic web application framework that Logilab_ started
-developing in 2001 as an offspring of its Narval_ research project. *CubicWeb*
-is written in Python and includes a data server and a web engine.
-
-Its data server publishes data federated from different sources like
-SQL databases, LDAP directories, `VCS`_ repositories or even from other
-CubicWeb data servers.
-
-.. _`VCS`: http://en.wikipedia.org/wiki/Revision_control
-
-Its web engine was designed to let the final user control what content to select
-and how to display it. It allows one to browse the federated data sources and
-display the results with the rendering that best fits the context. This
-flexibility of the user interface gives back to the user some capabilities
-usually only accessible to application developers.
-
-*CubicWeb* has been developed by Logilab_ and used in-house for many years
-before it was first installed for its clients in 2006 as version 2.
-
-In 2008, *CubicWeb* version 3 became downloadable for free under the
-terms of the LGPL license. Its community is now steadily growing
-without hampering the fast-paced stream of changes thanks to the time
-and energy originally put in the design of the framework.
-
-
-.. _Narval: http://www.logilab.org/project/narval-moved
-.. _Logilab: http://www.logilab.fr/
--- a/doc/book/en/intro/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _Part1:
-
---------------------------
-Introduction to *CubicWeb*
---------------------------
-
-This first part of the book offers different reading path to
-discover the *CubicWeb* framework, provides a tutorial to get a quick
-overview of its features and lists its key concepts.
-
-
-.. toctree::
- :maxdepth: 2
- :numbered:
-
- history
- concepts.rst
--- a/doc/book/en/makefile Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-SRC=.
-
-# You can set these sphinx variables from the command line.
-SPHINXOPTS =
-SPHINXBUILD = sphinx-build
-PAPER =
-#BUILDDIR = build
-BUILDDIR = ../..
-CWDIR = ../../..
-JSDIR = ${CWDIR}/web/data
-JSTORST = ${CWDIR}/doc/tools/pyjsrest.py
-BUILDJS = devweb/js_api
-
-# Internal variables for sphinx
-PAPEROPT_a4 = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS = -d ${BUILDDIR}/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-
-
-.PHONY: help clean html web pickle htmlhelp latex changes linkcheck
-
-help:
- @echo "Please use \`make <target>' where <target> is one of"
- @echo " all to make standalone HTML files, developer manual and API doc"
- @echo " html to make standalone HTML files"
- @echo "--- "
- @echo " pickle to make pickle files (usable by e.g. sphinx-web)"
- @echo " htmlhelp to make HTML files and a HTML help project"
- @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
- @echo " changes to make an overview over all changed/added/deprecated items"
- @echo " linkcheck to check all external links for integrity"
-
-clean:
- rm -f *.html
- -rm -rf ${BUILDDIR}/html ${BUILDDIR}/doctrees
- -rm -rf ${BUILDJS}
-
-all: html
-
-# run sphinx ###
-html: js
- mkdir -p ${BUILDDIR}/html ${BUILDDIR}/doctrees
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) ${BUILDDIR}/html
- @echo
- @echo "Build finished. The HTML pages are in ${BUILDDIR}/html."
-
-js:
- mkdir -p ${BUILDJS}
- $(JSTORST) -p ${JSDIR} -o ${BUILDJS}
-
-pickle:
- mkdir -p ${BUILDDIR}/pickle ${BUILDDIR}/doctrees
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) ${BUILDDIR}/pickle
- @echo
- @echo "Build finished; now you can process the pickle files or run"
- @echo " sphinx-web ${BUILDDIR}/pickle"
- @echo "to start the sphinx-web server."
-
-web: pickle
-
-htmlhelp:
- mkdir -p ${BUILDDIR}/htmlhelp ${BUILDDIR}/doctrees
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) ${BUILDDIR}/htmlhelp
- @echo
- @echo "Build finished; now you can run HTML Help Workshop with the" \
- ".hhp project file in ${BUILDDIR}/htmlhelp."
-
-latex:
- mkdir -p ${BUILDDIR}/latex ${BUILDDIR}/doctrees
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) ${BUILDDIR}/latex
- @echo
- @echo "Build finished; the LaTeX files are in ${BUILDDIR}/latex."
- @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
- "run these through (pdf)latex."
-
-changes:
- mkdir -p ${BUILDDIR}/changes ${BUILDDIR}/doctrees
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) ${BUILDDIR}/changes
- @echo
- @echo "The overview file is in ${BUILDDIR}/changes."
-
-linkcheck:
- mkdir -p ${BUILDDIR}/linkcheck ${BUILDDIR}/doctrees
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) ${BUILDDIR}/linkcheck
- @echo
- @echo "Link check complete; look for any errors in the above output " \
- "or in ${BUILDDIR}/linkcheck/output.txt."
--- a/doc/book/en/tutorials/advanced/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-
-.. _TutosPhotoWebSite:
-
-Building a photo gallery with |cubicweb|
-========================================
-
-Desired features
-----------------
-
-* basically a photo gallery
-
-* photo stored on the file system and displayed dynamically through a web interface
-
-* navigation through folder (album), tags, geographical zone, people on the
- picture... using facets
-
-* advanced security (not everyone can see everything). More on this later.
-
-
-.. toctree::
- :maxdepth: 2
-
- part01_create-cube
- part02_security
- part03_bfss
- part04_ui-base
- part05_ui-advanced
-
-
--- a/doc/book/en/tutorials/advanced/part01_create-cube.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-.. _TutosPhotoWebSiteCubeCreation:
-
-Cube creation and schema definition
------------------------------------
-
-.. _adv_tuto_create_new_cube:
-
-Step 1: creating a new cube for my web site
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-One note about my development environment: I wanted to use the packaged
-version of CubicWeb and cubes while keeping my cube in my user
-directory, let's say `~src/cubes`. I achieve this by setting the
-following environment variables::
-
- CW_CUBES_PATH=~/src/cubes
- CW_MODE=user
-
-I can now create the cube which will hold custom code for this web
-site using::
-
- cubicweb-ctl newcube --directory=~/src/cubes sytweb
-
-
-.. _adv_tuto_assemble_cubes:
-
-Step 2: pick building blocks into existing cubes
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Almost everything I want to handle in my web-site is somehow already modelized in
-existing cubes that I'll extend for my need. So I'll pick the following cubes:
-
-* `folder`, containing the `Folder` entity type, which will be used as
- both 'album' and a way to map file system folders. Entities are
- added to a given folder using the `filed_under` relation.
-
-* `file`, containing `File` entity type, gallery view, and a file system import
- utility.
-
-* `zone`, containing the `Zone` entity type for hierarchical geographical
- zones. Entities (including sub-zones) are added to a given zone using the
- `situated_in` relation.
-
-* `person`, containing the `Person` entity type plus some basic views.
-
-* `comment`, providing a full commenting system allowing one to comment entity types
- supporting the `comments` relation by adding a `Comment` entity.
-
-* `tag`, providing a full tagging system as an easy and powerful way to classify
- entities supporting the `tags` relation by linking the to `Tag` entities. This
- will allows navigation into a large number of picture.
-
-Ok, now I'll tell my cube requires all this by editing :file:`cubes/sytweb/__pkginfo__.py`:
-
- .. sourcecode:: python
-
- __depends__ = {'cubicweb': '>= 3.10.0',
- 'cubicweb-file': '>= 1.9.0',
- 'cubicweb-folder': '>= 1.1.0',
- 'cubicweb-person': '>= 1.2.0',
- 'cubicweb-comment': '>= 1.2.0',
- 'cubicweb-tag': '>= 1.2.0',
- 'cubicweb-zone': None}
-
-Notice that you can express minimal version of the cube that should be used,
-`None` meaning whatever version available. All packages starting with 'cubicweb-'
-will be recognized as being cube, not bare python packages. You can still specify
-this explicitly using instead the `__depends_cubes__` dictionary which should
-contains cube's name without the prefix. So the example below would be written
-as:
-
- .. sourcecode:: python
-
- __depends__ = {'cubicweb': '>= 3.10.0'}
- __depends_cubes__ = {'file': '>= 1.9.0',
- 'folder': '>= 1.1.0',
- 'person': '>= 1.2.0',
- 'comment': '>= 1.2.0',
- 'tag': '>= 1.2.0',
- 'zone': None}
-
-If your cube is packaged for debian, it's a good idea to update the
-`debian/control` file at the same time, so you won't forget it.
-
-
-Step 3: glue everything together in my cube's schema
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-.. sourcecode:: python
-
- from yams.buildobjs import RelationDefinition
-
- class comments(RelationDefinition):
- subject = 'Comment'
- object = 'File'
- cardinality = '1*'
- composite = 'object'
-
- class tags(RelationDefinition):
- subject = 'Tag'
- object = 'File'
-
- class filed_under(RelationDefinition):
- subject = 'File'
- object = 'Folder'
-
- class situated_in(RelationDefinition):
- subject = 'File'
- object = 'Zone'
-
- class displayed_on(RelationDefinition):
- subject = 'Person'
- object = 'File'
-
-
-This schema:
-
-* allows to comment and tag on `File` entity type by adding the `comments` and
- `tags` relations. This should be all we've to do for this feature since the
- related cubes provide 'pluggable section' which are automatically displayed on
- the primary view of entity types supporting the relation.
-
-* adds a `situated_in` relation definition so that image entities can be
- geolocalized.
-
-* add a new relation `displayed_on` relation telling who can be seen on a
- picture.
-
-This schema will probably have to evolve as time goes (for security handling at
-least), but since the possibility to let a schema evolve is one of CubicWeb's
-features (and goals), we won't worry about it for now and see that later when needed.
-
-
-Step 4: creating the instance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Now that I have a schema, I want to create an instance. To
-do so using this new 'sytweb' cube, I run::
-
- cubicweb-ctl create sytweb sytweb_instance
-
-Hint: if you get an error while the database is initialized, you can
-avoid having to answer the questions again by running::
-
- cubicweb-ctl db-create sytweb_instance
-
-This will use your already configured instance and start directly from the create
-database step, thus skipping questions asked by the 'create' command.
-
-Once the instance and database are fully initialized, run ::
-
- cubicweb-ctl start sytweb_instance
-
-to start the instance, check you can connect on it, etc...
-
--- a/doc/book/en/tutorials/advanced/part02_security.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,440 +0,0 @@
-.. _TutosPhotoWebSiteSecurity:
-
-Security, testing and migration
--------------------------------
-
-This part will cover various topics:
-
-* configuring security
-* migrating existing instance
-* writing some unit tests
-
-Here is the ``read`` security model I want:
-
-* folders, files, images and comments should have one of the following visibility:
-
- - ``public``, everyone can see it
- - ``authenticated``, only authenticated users can see it
- - ``restricted``, only a subset of authenticated users can see it
-
-* managers (e.g. me) can see everything
-* only authenticated users can see people
-* everyone can see classifier entities, such as tag and zone
-
-Also, unless explicitly specified, the visibility of an image should be the same as
-its parent folder, as well as visibility of a comment should be the same as the
-commented entity. If there is no parent entity, the default visibility is
-``authenticated``.
-
-Regarding write security, that's much easier:
-* anonymous can't write anything
-* authenticated users can only add comment
-* managers will add the remaining stuff
-
-Now, let's implement that!
-
-Proper security in CubicWeb is done at the schema level, so you don't have to
-bother with it in views: users will only see what they can see automatically.
-
-.. _adv_tuto_security:
-
-Step 1: configuring security into the schema
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In schema, you can grant access according to groups, or to some RQL expressions:
-users get access if the expression returns some results. To implement the read
-security defined earlier, groups are not enough, we'll need some RQL expression. Here
-is the idea:
-
-* add a `visibility` attribute on Folder, File and Comment, which may be one of
- the value explained above
-
-* add a `may_be_read_by` relation from Folder, File and Comment to users,
- which will define who can see the entity
-
-* security propagation will be done in hook.
-
-So the first thing to do is to modify my cube's schema.py to define those
-relations:
-
-.. sourcecode:: python
-
- from yams.constraints import StaticVocabularyConstraint
-
- class visibility(RelationDefinition):
- subject = ('Folder', 'File', 'Comment')
- object = 'String'
- constraints = [StaticVocabularyConstraint(('public', 'authenticated',
- 'restricted', 'parent'))]
- default = 'parent'
- cardinality = '11' # required
-
- class may_be_read_by(RelationDefinition):
- __permissions__ = {
- 'read': ('managers', 'users'),
- 'add': ('managers',),
- 'delete': ('managers',),
- }
-
- subject = ('Folder', 'File', 'Comment',)
- object = 'CWUser'
-
-We can note the following points:
-
-* we've added a new `visibility` attribute to folder, file, image and comment
- using a `RelationDefinition`
-
-* `cardinality = '11'` means this attribute is required. This is usually hidden
- under the `required` argument given to the `String` constructor, but we can
- rely on this here (same thing for StaticVocabularyConstraint, which is usually
- hidden by the `vocabulary` argument)
-
-* the `parent` possible value will be used for visibility propagation
-
-* think to secure the `may_be_read_by` permissions, else any user can add/delete it
- by default, which somewhat breaks our security model...
-
-Now, we should be able to define security rules in the schema, based on these new
-attribute and relation. Here is the code to add to *schema.py*:
-
-.. sourcecode:: python
-
- from cubicweb.schema import ERQLExpression
-
- VISIBILITY_PERMISSIONS = {
- 'read': ('managers',
- ERQLExpression('X visibility "public"'),
- ERQLExpression('X may_be_read_by U')),
- 'add': ('managers',),
- 'update': ('managers', 'owners',),
- 'delete': ('managers', 'owners'),
- }
- AUTH_ONLY_PERMISSIONS = {
- 'read': ('managers', 'users'),
- 'add': ('managers',),
- 'update': ('managers', 'owners',),
- 'delete': ('managers', 'owners'),
- }
- CLASSIFIERS_PERMISSIONS = {
- 'read': ('managers', 'users', 'guests'),
- 'add': ('managers',),
- 'update': ('managers', 'owners',),
- 'delete': ('managers', 'owners'),
- }
-
- from cubes.folder.schema import Folder
- from cubes.file.schema import File
- from cubes.comment.schema import Comment
- from cubes.person.schema import Person
- from cubes.zone.schema import Zone
- from cubes.tag.schema import Tag
-
- Folder.__permissions__ = VISIBILITY_PERMISSIONS
- File.__permissions__ = VISIBILITY_PERMISSIONS
- Comment.__permissions__ = VISIBILITY_PERMISSIONS.copy()
- Comment.__permissions__['add'] = ('managers', 'users',)
- Person.__permissions__ = AUTH_ONLY_PERMISSIONS
- Zone.__permissions__ = CLASSIFIERS_PERMISSIONS
- Tag.__permissions__ = CLASSIFIERS_PERMISSIONS
-
-What's important in there:
-
-* `VISIBILITY_PERMISSIONS` provides read access to managers group, if
- `visibility` attribute's value is 'public', or if user (designed by the 'U'
- variable in the expression) is linked to the entity (the 'X' variable) through
- the `may_be_read_by` permission
-
-* we modify permissions of the entity types we use by importing them and
- modifying their `__permissions__` attribute
-
-* notice the `.copy()`: we only want to modify 'add' permission for `Comment`,
- not for all entity types using `VISIBILITY_PERMISSIONS`!
-
-* the remaining part of the security model is done using regular groups:
-
- - `users` is the group to which all authenticated users will belong
- - `guests` is the group of anonymous users
-
-
-.. _adv_tuto_security_propagation:
-
-Step 2: security propagation in hooks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To fullfill the requirements, we have to implement::
-
- Also, unless explicity specified, visibility of an image should be the same as
- its parent folder, as well as visibility of a comment should be the same as the
- commented entity.
-
-This kind of `active` rule will be done using CubicWeb's hook
-system. Hooks are triggered on database events such as addition of a new
-entity or relation.
-
-The tricky part of the requirement is in *unless explicitly specified*, notably
-because when the entity is added, we don't know yet its 'parent'
-entity (e.g. Folder of an File, File commented by a Comment). To handle such things,
-CubicWeb provides `Operation`, which allow to schedule things to do at commit time.
-
-In our case we will:
-
-* on entity creation, schedule an operation that will set default visibility
-
-* when a "parent" relation is added, propagate parent's visibility unless the
- child already has a visibility set
-
-Here is the code in cube's *hooks.py*:
-
-.. sourcecode:: python
-
- from cubicweb.predicates import is_instance
- from cubicweb.server import hook
-
- class SetVisibilityOp(hook.DataOperationMixIn, hook.Operation):
-
- def precommit_event(self):
- for eid in self.get_data():
- entity = self.session.entity_from_eid(eid)
- if entity.visibility == 'parent':
- entity.cw_set(visibility=u'authenticated')
-
- class SetVisibilityHook(hook.Hook):
- __regid__ = 'sytweb.setvisibility'
- __select__ = hook.Hook.__select__ & is_instance('Folder', 'File', 'Comment')
- events = ('after_add_entity',)
-
- def __call__(self):
- SetVisibilityOp.get_instance(self._cw).add_data(self.entity.eid)
-
- class SetParentVisibilityHook(hook.Hook):
- __regid__ = 'sytweb.setparentvisibility'
- __select__ = hook.Hook.__select__ & hook.match_rtype('filed_under', 'comments')
- events = ('after_add_relation',)
-
- def __call__(self):
- parent = self._cw.entity_from_eid(self.eidto)
- child = self._cw.entity_from_eid(self.eidfrom)
- if child.visibility == 'parent':
- child.cw_set(visibility=parent.visibility)
-
-Notice:
-
-* hooks are application objects, hence have selectors that should match entity or
- relation types to which the hook applies. To match a relation type, we use the
- hook specific `match_rtype` selector.
-
-* usage of `DataOperationMixIn`: instead of adding an operation for each added entity,
- DataOperationMixIn allows to create a single one and to store entity's eids to be
- processed in the transaction data. This is a good pratice to avoid heavy
- operations manipulation cost when creating a lot of entities in the same
- transaction.
-
-* the `precommit_event` method of the operation will be called at transaction's
- commit time.
-
-* in a hook, `self._cw` is the repository session, not a web request as usually
- in views
-
-* according to hook's event, you have access to different attributes on the hook
- instance. Here:
-
- - `self.entity` is the newly added entity on 'after_add_entity' events
-
- - `self.eidfrom` / `self.eidto` are the eid of the subject / object entity on
- 'after_add_relation' events (you may also get the relation type using
- `self.rtype`)
-
-The `parent` visibility value is used to tell "propagate using parent security"
-because we want that attribute to be required, so we can't use None value else
-we'll get an error before we get any chance to propagate...
-
-Now, we also want to propagate the `may_be_read_by` relation. Fortunately,
-CubicWeb provides some base hook classes for such things, so we only have to add
-the following code to *hooks.py*:
-
-.. sourcecode:: python
-
- # relations where the "parent" entity is the subject
- S_RELS = set()
- # relations where the "parent" entity is the object
- O_RELS = set(('filed_under', 'comments',))
-
- class AddEntitySecurityPropagationHook(hook.PropagateRelationHook):
- """propagate permissions when new entity are added"""
- __regid__ = 'sytweb.addentity_security_propagation'
- __select__ = (hook.PropagateRelationHook.__select__
- & hook.match_rtype_sets(S_RELS, O_RELS))
- main_rtype = 'may_be_read_by'
- subject_relations = S_RELS
- object_relations = O_RELS
-
- class AddPermissionSecurityPropagationHook(hook.PropagateRelationAddHook):
- """propagate permissions when new entity are added"""
- __regid__ = 'sytweb.addperm_security_propagation'
- __select__ = (hook.PropagateRelationAddHook.__select__
- & hook.match_rtype('may_be_read_by',))
- subject_relations = S_RELS
- object_relations = O_RELS
-
- class DelPermissionSecurityPropagationHook(hook.PropagateRelationDelHook):
- __regid__ = 'sytweb.delperm_security_propagation'
- __select__ = (hook.PropagateRelationDelHook.__select__
- & hook.match_rtype('may_be_read_by',))
- subject_relations = S_RELS
- object_relations = O_RELS
-
-* the `AddEntitySecurityPropagationHook` will propagate the relation
- when `filed_under` or `comments` relations are added
-
- - the `S_RELS` and `O_RELS` set as well as the `match_rtype_sets` selector are
- used here so that if my cube is used by another one, it'll be able to
- configure security propagation by simply adding relation to one of the two
- sets.
-
-* the two others will propagate permissions changes on parent entities to
- children entities
-
-
-.. _adv_tuto_tesing_security:
-
-Step 3: testing our security
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Security is tricky. Writing some tests for it is a very good idea. You should
-even write them first, as Test Driven Development recommends!
-
-Here is a small test case that will check the basis of our security
-model, in *test/unittest_sytweb.py*:
-
-.. sourcecode:: python
-
- from cubicweb.devtools.testlib import CubicWebTC
- from cubicweb import Binary
-
- class SecurityTC(CubicWebTC):
-
- def test_visibility_propagation(self):
- with self.admin_access.repo_cnx() as cnx:
- # create a user for later security checks
- toto = self.create_user(cnx, 'toto')
- cnx.commit()
- # init some data using the default manager connection
- folder = cnx.create_entity('Folder',
- name=u'restricted',
- visibility=u'restricted')
- photo1 = cnx.create_entity('File',
- data_name=u'photo1.jpg',
- data=Binary('xxx'),
- filed_under=folder)
- cnx.commit()
- # visibility propagation
- self.assertEquals(photo1.visibility, 'restricted')
- # unless explicitly specified
- photo2 = cnx.create_entity('File',
- data_name=u'photo2.jpg',
- data=Binary('xxx'),
- visibility=u'public',
- filed_under=folder)
- cnx.commit()
- self.assertEquals(photo2.visibility, 'public')
- with self.new_access('toto').repo_cnx() as cnx:
- # test security
- self.assertEqual(1, len(cnx.execute('File X'))) # only the public one
- self.assertEqual(0, len(cnx.execute('Folder X'))) # restricted...
- with self.admin_access.repo_cnx() as cnx:
- # may_be_read_by propagation
- folder = cnx.entity_from_eid(folder.eid)
- folder.cw_set(may_be_read_by=toto)
- cnx.commit()
- with self.new_access('toto').repo_cnx() as cnx:
- photo1 = cnx.entity_from_eid(photo1.eid)
- self.failUnless(photo1.may_be_read_by)
- # test security with permissions
- self.assertEquals(2, len(cnx.execute('File X'))) # now toto has access to photo2
- self.assertEquals(1, len(cnx.execute('Folder X'))) # and to restricted folder
-
- if __name__ == '__main__':
- from logilab.common.testlib import unittest_main
- unittest_main()
-
-It's not complete, but shows most things you'll want to do in tests: adding some
-content, creating users and connecting as them in the test, etc...
-
-To run it type:
-
-.. sourcecode:: bash
-
- $ pytest unittest_sytweb.py
- ======================== unittest_sytweb.py ========================
- -> creating tables [....................]
- -> inserting default user and default groups.
- -> storing the schema in the database [....................]
- -> database for instance data initialized.
- .
- ----------------------------------------------------------------------
- Ran 1 test in 22.547s
-
- OK
-
-
-The first execution is taking time, since it creates a sqlite database for the
-test instance. The second one will be much quicker:
-
-.. sourcecode:: bash
-
- $ pytest unittest_sytweb.py
- ======================== unittest_sytweb.py ========================
- .
- ----------------------------------------------------------------------
- Ran 1 test in 2.662s
-
- OK
-
-If you do some changes in your schema, you'll have to force regeneration of that
-database. You do that by removing the tmpdb files before running the test: ::
-
- $ rm data/database/tmpdb*
-
-
-.. Note::
- pytest is a very convenient utility used to control test execution. It is available from the `logilab-common`_ package.
-
-.. _`logilab-common`: http://www.logilab.org/project/logilab-common
-
-.. _adv_tuto_migration_script:
-
-Step 4: writing the migration script and migrating the instance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Prior to those changes, I created an instance, fed it with some data, so I
-don't want to create a new one, but to migrate the existing one. Let's see how to
-do that.
-
-Migration commands should be put in the cube's *migration* directory, in a
-file named file:`<X.Y.Z>_Any.py` ('Any' being there mostly for historical reasons).
-
-Here I'll create a *migration/0.2.0_Any.py* file containing the following
-instructions:
-
-.. sourcecode:: python
-
- add_relation_type('may_be_read_by')
- add_relation_type('visibility')
- sync_schema_props_perms()
-
-Then I update the version number in the cube's *__pkginfo__.py* to 0.2.0. And
-that's it! Those instructions will:
-
-* update the instance's schema by adding our two new relations and update the
- underlying database tables accordingly (the first two instructions)
-
-* update schema's permissions definition (the last instruction)
-
-
-To migrate my instance I simply type::
-
- cubicweb-ctl upgrade sytweb_instance
-
-You'll then be asked some questions to do the migration step by step. You should say
-YES when it asks if a backup of your database should be done, so you can get back
-to initial state if anything goes wrong...
--- a/doc/book/en/tutorials/advanced/part03_bfss.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-Storing images on the file-system
----------------------------------
-
-Step 1: configuring the BytesFileSystem storage
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To avoid cluttering my database, and to ease file manipulation, I don't want them
-to be stored in the database. I want to be able create File entities for some
-files on the server file system, where those file will be accessed to get
-entities data. To do so I've to set a custom :class:`BytesFileSystemStorage`
-storage for the File 'data' attribute, which hold the actual file's content.
-
-Since the function to register a custom storage needs to have a repository
-instance as first argument, we've to call it in a server startup hook. So I added
-in `cubes/sytweb/hooks.py` :
-
-.. sourcecode:: python
-
- from os import makedirs
- from os.path import join, exists
-
- from cubicweb.server import hook
- from cubicweb.server.sources import storages
-
- class ServerStartupHook(hook.Hook):
- __regid__ = 'sytweb.serverstartup'
- events = ('server_startup', 'server_maintenance')
-
- def __call__(self):
- bfssdir = join(self.repo.config.appdatahome, 'bfss')
- if not exists(bfssdir):
- makedirs(bfssdir)
- print 'created', bfssdir
- storage = storages.BytesFileSystemStorage(bfssdir)
- storages.set_attribute_storage(self.repo, 'File', 'data', storage)
-
-.. Note::
-
- * how we built the hook's registry identifier (`__regid__`): you can introduce
- 'namespaces' by using there python module like naming identifiers. This is
- especially important for hooks where you usually want a new custom hook, not
- overriding / specializing an existant one, but the concept may be applied to
- any application objects
-
- * we catch two events here: "server_startup" and "server_maintenance". The first
- is called on regular repository startup (eg, as a server), the other for
- maintenance task such as shell or upgrade. In both cases, we need to have
- the storage set, else we'll be in trouble...
-
- * the path given to the storage is the place where file added through the ui
- (or in the database before migration) will be located
-
- * beware that by doing this, you can't anymore write queries that will try to
- restrict on File `data` attribute. Hopefuly we don't do that usually
- on file's content or more generally on attributes for the Bytes type
-
-Now, if you've already added some photos through the web ui, you'll have to
-migrate existing data so file's content will be stored on the file-system instead
-of the database. There is a migration command to do so, let's run it in the
-cubicweb shell (in real life, you would have to put it in a migration script as we
-have seen last time):
-
-::
-
- $ cubicweb-ctl shell sytweb_instance
- entering the migration python shell
- just type migration commands or arbitrary python code and type ENTER to execute it
- type "exit" or Ctrl-D to quit the shell and resume operation
- >>> storage_changed('File', 'data')
- [........................]
-
-
-That's it. Now, files added through the web ui will have their content stored on
-the file-system, and you'll also be able to import files from the file-system as
-explained in the next part.
-
-Step 2: importing some data into the instance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Hey, we start to have some nice features, let us give a try to this new web
-site. For instance if I have a 'photos/201005WePyrenees' containing pictures for
-a particular event, I can import it to my web site by typing ::
-
- $ cubicweb-ctl fsimport -F sytweb_instance photos/201005WePyrenees/
- ** importing directory /home/syt/photos/201005WePyrenees
- importing IMG_8314.JPG
- importing IMG_8274.JPG
- importing IMG_8286.JPG
- importing IMG_8308.JPG
- importing IMG_8304.JPG
-
-.. Note::
- The -F option means that folders should be mapped, hence my photos will be
- linked to a Folder entity corresponding to the file-system folder.
-
-Let's take a look at the web ui:
-
-.. image:: ../../images/tutos-photowebsite_ui1.png
-
-Nothing different, I can't see the new folder... But remember our security model!
-By default, files are only accessible to authenticated users, and I'm looking at
-the site as anonymous, e.g. not authenticated. If I login, I can now see:
-
-.. image:: ../../images/tutos-photowebsite_ui2.png
-
-Yeah, it's there! You will notice that I can see some entities as well as
-folders and images the anonymous user can't. It just works **everywhere in the
-ui** since it's handled at the repository level, thanks to our security model.
-
-Now if I click on the recently inserted folder, I can see
-
-.. image:: ../../images/tutos-photowebsite_ui3.png
-
-Great! There is even my pictures in the folder. I can know give to this folder a
-nicer name (provided I don't intend to import from it anymore, else already
-imported photos will be reimported), change permissions, title for some pictures,
-etc... Having a good content is much more difficult than having a good web site
-;)
-
-
-Conclusion
-~~~~~~~~~~
-
-We started to see here an advanced feature of our repository: the ability
-to store some parts of our data-model into a custom storage, outside the
-database. There is currently only the :class:`BytesFileSystemStorage` available,
-but you can expect to see more coming in a near future (or write your own!).
-
-Also, we can know start to feed our web-site with some nice pictures!
-The site isn't perfect (far from it actually) but it's usable, and we can
-now start using it and improve it on the way. The Incremental Cubic Way :)
--- a/doc/book/en/tutorials/advanced/part04_ui-base.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,361 +0,0 @@
-Let's make it more user friendly
-================================
-
-
-Step 1: let's improve site's usability for our visitors
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The first thing I've noticed is that people to whom I send links to photos with
-some login/password authentication get lost, because they don't grasp they have
-to login by clicking on the 'authenticate' link. That's much probably because
-they only get a 404 when trying to access an unauthorized folder, and the site
-doesn't make clear that 1. you're not authenticated, 2. you could get more
-content by authenticating yourself.
-
-So, to improve this situation, I decided that I should:
-
-* make a login box appears for anonymous, so they see at a first glance a place
- to put the login / password information I provided
-
-* customize the 404 page, proposing to login to anonymous.
-
-Here is the code, samples from my cube's `views.py` file:
-
-.. sourcecode:: python
-
- from cubicweb.predicates import is_instance
- from cubicweb.web import component
- from cubicweb.web.views import error
- from cubicweb.predicates import anonymous_user
-
- class FourOhFour(error.FourOhFour):
- __select__ = error.FourOhFour.__select__ & anonymous_user()
-
- def call(self):
- self.w(u"<h1>%s</h1>" % self._cw._('this resource does not exist'))
- self.w(u"<p>%s</p>" % self._cw._('have you tried to login?'))
-
-
- class LoginBox(component.CtxComponent):
- """display a box containing links to all startup views"""
- __regid__ = 'sytweb.loginbox'
- __select__ = component.CtxComponent.__select__ & anonymous_user()
-
- title = _('Authenticate yourself')
- order = 70
-
- def render_body(self, w):
- cw = self._cw
- form = cw.vreg['forms'].select('logform', cw)
- form.render(w=w, table_class='', display_progress_div=False)
-
-The first class provides a new specific implementation of the default page you
-get on 404 error, to display an adapted message to anonymous user.
-
-.. Note::
-
- Thanks to the selection mecanism, it will be selected for anoymous user,
- since the additional `anonymous_user()` selector gives it a higher score than
- the default, and not for authenticated since this selector will return 0 in
- such case (hence the object won't be selectable)
-
-The second class defines a simple box, that will be displayed by default with
-boxes in the left column, thanks to default :class:`component.CtxComponent`
-selector. The HTML is written to match default CubicWeb boxes style. The code
-fetch the actual login form and render it.
-
-
-.. figure:: ../../images/tutos-photowebsite_login-box.png
- :alt: login box / 404 screenshot
-
- The login box and the custom 404 page for an anonymous visitor (translated in french)
-
-
-Step 2: providing a custom index page
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Another thing we can easily do to improve the site is... A nicer index page
-(e.g. the first page you get when accessing the web site)! The default one is
-quite intimidating (that should change in a near future). I will provide a much
-simpler index page that simply list available folders (e.g. photo albums in that
-site).
-
-.. sourcecode:: python
-
- from cubicweb.web.views import startup
-
- class IndexView(startup.IndexView):
- def call(self, **kwargs):
- self.w(u'<div>\n')
- if self._cw.cnx.anonymous_connection:
- self.w(u'<h4>%s</h4>\n' % self._cw._('Public Albums'))
- else:
- self.w(u'<h4>%s</h4>\n' % self._cw._('Albums for %s') % self._cw.user.login)
- self._cw.vreg['views'].select('tree', self._cw).render(w=self.w)
- self.w(u'</div>\n')
-
- def registration_callback(vreg):
- vreg.register_all(globals().values(), __name__, (IndexView,))
- vreg.register_and_replace(IndexView, startup.IndexView)
-
-As you can see, we override the default index view found in
-`cubicweb.web.views.startup`, geting back nothing but its identifier and selector
-since we override the top level view's `call` method.
-
-.. Note::
-
- in that case, we want our index view to **replace** the existing one. To do so
- we've to implements the `registration_callback` function, in which we tell to
- register everything in the module *but* our IndexView, then we register it
- instead of the former index view.
-
-Also, we added a title that tries to make it more evident that the visitor is
-authenticated, or not. Hopefuly people will get it now!
-
-
-.. figure:: ../../images/tutos-photowebsite_index-before.png
- :alt: default index page screenshot
-
- The default index page
-
-.. figure:: ../../images/tutos-photowebsite_index-after.png
- :alt: new index page screenshot
-
- Our simpler, less intimidating, index page (still translated in french)
-
-
-Step 3: more navigation improvments
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-There are still a few problems I want to solve...
-
-* Images in a folder are displayed in a somewhat random order. I would like to
- have them ordered by file's name (which will usually, inside a given folder,
- also result ordering photo by their date and time)
-
-* When clicking a photo from an album view, you've to get back to the gallery
- view to go to the next photo. This is pretty annoying...
-
-* Also, when viewing an image, there is no clue about the folder to which this
- image belongs to.
-
-I will first try to explain the ordering problem. By default, when accessing
-related entities by using the ORM's API, you should get them ordered according to
-the target's class `cw_fetch_order`. If we take a look at the file cube'schema,
-we can see:
-
-.. sourcecode:: python
-
- class File(AnyEntity):
- """customized class for File entities"""
- __regid__ = 'File'
- fetch_attrs, cw_fetch_order = fetch_config(['data_name', 'title'])
-
-
-By default, `fetch_config` will return a `cw_fetch_order` method that will order
-on the first attribute in the list. So, we could expect to get files ordered by
-their name. But we don't. What's up doc ?
-
-The problem is that files are related to folder using the `filed_under` relation.
-And that relation is ambiguous, eg it can lead to `File` entities, but also to
-`Folder` entities. In such case, since both entity types doesn't share the
-attribute on which we want to sort, we'll get linked entities sorted on a common
-attribute (usually `modification_date`).
-
-To fix this, we've to help the ORM. We'll do this in the method from the `ITree`
-folder's adapter, used in the folder's primary view to display the folder's
-content. Here's the code, that I've put in our cube's `entities.py` file, since
-it's more logical stuff than view stuff:
-
-.. sourcecode:: python
-
- from cubes.folder import entities as folder
-
- class FolderITreeAdapter(folder.FolderITreeAdapter):
-
- def different_type_children(self, entities=True):
- rql = self.entity.cw_related_rql(self.tree_relation,
- self.parent_role, ('File',))
- rset = self._cw.execute(rql, {'x': self.entity.eid})
- if entities:
- return list(rset.entities())
- return rset
-
- def registration_callback(vreg):
- vreg.register_and_replace(FolderITreeAdapter, folder.FolderITreeAdapter)
-
-As you can see, we simple inherit from the adapter defined in the `folder` cube,
-then we override the `different_type_children` method to give a clue to the ORM's
-`cw_related_rql` method, that is responsible to generate the rql to get entities
-related to the folder by the `filed_under` relation (the value of the
-`tree_relation` attribute). The clue is that we only want to consider the `File`
-target entity type. By doing this, we remove the ambiguity and get back a RQL
-query that correctly order files by their `data_name` attribute.
-
-
-.. Note::
-
- * As seen earlier, we want to **replace** the folder's `ITree` adapter by our
- implementation, hence the custom `registration_callback` method.
-
-
-Ouf. That one was tricky...
-
-Now the easier parts. Let's start by adding some links on the file's primary view
-to see the previous / next image in the same folder. CubicWeb's provide a
-component that do exactly that. To make it appears, one have to be adaptable to
-the `IPrevNext` interface. Here is the related code sample, extracted from our
-cube's `views.py` file:
-
-.. sourcecode:: python
-
- from cubicweb.predicates import is_instance
- from cubicweb.web.views import navigation
-
-
- class FileIPrevNextAdapter(navigation.IPrevNextAdapter):
- __select__ = is_instance('File')
-
- def previous_entity(self):
- rset = self._cw.execute('File F ORDERBY FDN DESC LIMIT 1 WHERE '
- 'X filed_under FOLDER, F filed_under FOLDER, '
- 'F data_name FDN, X data_name > FDN, X eid %(x)s',
- {'x': self.entity.eid})
- if rset:
- return rset.get_entity(0, 0)
-
- def next_entity(self):
- rset = self._cw.execute('File F ORDERBY FDN ASC LIMIT 1 WHERE '
- 'X filed_under FOLDER, F filed_under FOLDER, '
- 'F data_name FDN, X data_name < FDN, X eid %(x)s',
- {'x': self.entity.eid})
- if rset:
- return rset.get_entity(0, 0)
-
-
-The `IPrevNext` interface implemented by the adapter simply consist in the
-`previous_entity` / `next_entity` methods, that should respectivly return the
-previous / next entity or `None`. We make an RQL query to get files in the same
-folder, ordered similarly (eg by their `data_name` attribute). We set
-ascendant/descendant ordering and a strict comparison with current file's name
-(the "X" variable representing the current file).
-
-Notice that this query supposes we wont have two files of the same name in the
-same folder, else things may go wrong. Fixing this is out of the scope of this
-blog. And as I would like to have at some point a smarter, context sensitive
-previous/next entity, I'll probably never fix this query (though if I had to, I
-would probably choosing to add a constraint in the schema so that we can't add
-two files of the same name in a folder).
-
-One more thing: by default, the component will be displayed below the content
-zone (the one with the white background). You can change this in the site's
-properties through the ui, but you can also change the default value in the code
-by modifying the `context` attribute of the component:
-
-.. sourcecode:: python
-
- navigation.NextPrevNavigationComponent.context = 'navcontentbottom'
-
-.. Note::
-
- `context` may be one of 'navtop', 'navbottom', 'navcontenttop' or
- 'navcontentbottom'; the first two being outside the main content zone, the two
- others inside it.
-
-.. figure:: ../../images/tutos-photowebsite_prevnext.png
- :alt: screenshot of the previous/next entity component
-
- The previous/next entity component, at the bottom of the main content zone.
-
-Now, the only remaining stuff in my todo list is to see the file's folder. I'll use
-the standard breadcrumb component to do so. Similarly as what we've seen before, this
-component is controled by the :class:`IBreadCrumbs` interface, so we'll have to provide a custom
-adapter for `File` entity, telling the a file's parent entity is its folder:
-
-.. sourcecode:: python
-
- from cubicweb.web.views import ibreadcrumbs
-
- class FileIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter):
- __select__ = is_instance('File')
-
- def parent_entity(self):
- if self.entity.filed_under:
- return self.entity.filed_under[0]
-
-In that case, we simply use attribute notation provided by the ORM to get the
-folder in which the current file (e.g. `self.entity`) is located.
-
-.. Note::
-
- The :class:`IBreadCrumbs` interface is a `breadcrumbs` method, but the default
- :class:`IBreadCrumbsAdapter` provides a default implementation for it that will look
- at the value returned by its `parent_entity` method. It also provides a
- default implementation for this method for entities adapting to the `ITree`
- interface, but as our `File` doesn't, we've to provide a custom adapter.
-
-.. figure:: ../../images/tutos-photowebsite_breadcrumbs.png
- :alt: screenshot of the breadcrumb component
-
- The breadcrumb component when on a file entity, now displaying parent folder.
-
-
-Step 4: preparing the release and migrating the instance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Now that greatly enhanced our cube, it's time to release it to upgrade production site.
-I'll probably detail that process later, but I currently simply transfer the new code
-to the server running the web site.
-
-However, I've still today some step to respect to get things done properly...
-
-First, as I've added some translatable string, I've to run: ::
-
- $ cubicweb-ctl i18ncube sytweb
-
-To update the cube's gettext catalogs (the '.po' files under the cube's `i18n`
-directory). Once the above command is executed, I'll then update translations.
-
-To see if everything is ok on my test instance, I do: ::
-
- $ cubicweb-ctl i18ninstance sytweb
- $ cubicweb-ctl start -D sytweb
-
-The first command compile i18n catalogs (e.g. generates '.mo' files) for my test
-instance. The second command start it in debug mode, so I can open my browser and
-navigate through the web site to see if everything is ok...
-
-.. Note::
-
- In the 'cubicweb-ctl i18ncube' command, `sytweb` refers to the **cube**, while
- in the two other, it refers to the **instance** (if you can't see the
- difference, reread CubicWeb's concept chapter !).
-
-
-Once I've checked it's ok, I simply have to bump the version number in the
-`__pkginfo__` module to trigger a migration once I'll have updated the code on
-the production site. I can check then check the migration is also going fine, by
-first restoring a dump from the production site, then upgrading my test instance.
-
-To generate a dump from the production site: ::
-
- $ cubicweb-ctl db-dump sytweb
- pg_dump -Fc --username=syt --no-owner --file /home/syt/etc/cubicweb.d/sytweb/backup/tmpYIN0YI/system sytweb
- -> backup file /home/syt/etc/cubicweb.d/sytweb/backup/sytweb-2010-07-13_10-22-40.tar.gz
-
-I can now get back the dump file ('sytweb-2010-07-13_10-22-40.tar.gz') to my test
-machine (using `scp` for instance) to restore it and start migration: ::
-
- $ cubicweb-ctl db-restore sytweb sytweb-2010-07-13_10-22-40.tar.gz
- $ cubicweb-ctl upgrade sytweb
-
-You'll have to answer some questions, as we've seen in `an earlier post`_.
-
-Now that everything is tested, I can transfer the new code to the production
-server, `apt-get upgrade` cubicweb and its dependencies, and eventually
-upgrade the production instance.
-
-
-.. _`several improvments`: http://www.cubicweb.org/blogentry/1179899
-.. _`3.8`: http://www.cubicweb.org/blogentry/917107
-.. _`first blog of this series`: http://www.cubicweb.org/blogentry/824642
-.. _`an earlier post`: http://www.cubicweb.org/867464
--- a/doc/book/en/tutorials/advanced/part05_ui-advanced.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-Building my photos web site with |cubicweb| part V: let's make it even more user friendly
-=========================================================================================
-
-.. _uiprops:
-
-Step 1: tired of the default look?
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-OK... Now our site has its most desired features. But... I would like to make it look
-somewhat like *my* website. It is not www.cubicweb.org after all. Let's tackle this
-first!
-
-The first thing we can to is to change the logo. There are various way to achieve
-this. The easiest way is to put a :file:`logo.png` file into the cube's :file:`data`
-directory. As data files are looked at according to cubes order (CubicWeb
-resources coming last), that file will be selected instead of CubicWeb's one.
-
-.. Note::
- As the location for static resources are cached, you'll have to restart
- your instance for this to be taken into account.
-
-Though there are some cases where you don't want to use a :file:`logo.png` file.
-For instance if it's a JPEG file. You can still change the logo by defining in
-the cube's :file:`uiprops.py` file:
-
-.. sourcecode:: python
-
- LOGO = data('logo.jpg')
-
-The uiprops machinery is used to define some static file resources,
-such as the logo, default Javascript / CSS files, as well as CSS
-properties (we'll see that later).
-
-.. Note::
- This file is imported specifically by |cubicweb|, with a predefined name space,
- containing for instance the `data` function, telling the file is somewhere
- in a cube or CubicWeb's data directory.
-
- One side effect of this is that it can't be imported as a regular python
- module.
-
-The nice thing is that in debug mode, change to a :file:`uiprops.py` file are detected
-and then automatically reloaded.
-
-Now, as it's a photos web-site, I would like to have a photo of mine as background...
-After some trials I won't detail here, I've found a working recipe explained `here`_.
-All I've to do is to override some stuff of the default CubicWeb user interface to
-apply it as explained.
-
-The first thing to to get the ``<img/>`` tag as first element after the
-``<body>`` tag. If you know a way to avoid this by simply specifying the image
-in the CSS, tell me! The easiest way to do so is to override the
-:class:`HTMLPageHeader` view, since that's the one that is directly called once
-the ``<body>`` has been written. How did I find this? By looking in the
-:mod:`cubiweb.web.views.basetemplates` module, since I know that global page
-layouts sits there. I could also have grep the "body" tag in
-:mod:`cubicweb.web.views`... Finding this was the hardest part. Now all I need is
-to customize it to write that ``img`` tag, as below:
-
-.. sourcecode:: python
-
- class HTMLPageHeader(basetemplates.HTMLPageHeader):
- # override this since it's the easier way to have our bg image
- # as the first element following <body>
- def call(self, **kwargs):
- self.w(u'<img id="bg-image" src="%sbackground.jpg" alt="background image"/>'
- % self._cw.datadir_url)
- super(HTMLPageHeader, self).call(**kwargs)
-
-
- def registration_callback(vreg):
- vreg.register_all(globals().values(), __name__, (HTMLPageHeader))
- vreg.register_and_replace(HTMLPageHeader, basetemplates.HTMLPageHeader)
-
-
-As you may have guessed, my background image is in a :file:`background.jpg` file
-in the cube's :file:`data` directory, but there are still some things to explain
-to newcomers here:
-
-* The :meth:`call` method is there the main access point of the view. It's called by
- the view's :meth:`render` method. It is not the only access point for a view, but
- this will be detailed later.
-
-* Calling `self.w` writes something to the output stream. Except for binary views
- (which do not generate text), it *must* be passed an Unicode string.
-
-* The proper way to get a file in :file:`data` directory is to use the `datadir_url`
- attribute of the incoming request (e.g. `self._cw`).
-
-I won't explain again the :func:`registration_callback` stuff, you should understand it
-now! If not, go back to previous posts in the series :)
-
-Fine. Now all I've to do is to add a bit of CSS to get it to behave nicely (which
-is not the case at all for now). I'll put all this in a :file:`cubes.sytweb.css`
-file, stored as usual in our :file:`data` directory:
-
-.. sourcecode:: css
-
-
- /* fixed full screen background image
- * as explained on http://webdesign.about.com/od/css3/f/blfaqbgsize.htm
- *
- * syt update: set z-index=0 on the img instead of z-index=1 on div#page & co to
- * avoid pb with the user actions menu
- */
- img#bg-image {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 0;
- }
-
- div#page, table#header, div#footer {
- background: transparent;
- position: relative;
- }
-
- /* add some space around the logo
- */
- img#logo {
- padding: 5px 15px 0px 15px;
- }
-
- /* more dark font for metadata to have a chance to see them with the background
- * image
- */
- div.metadata {
- color: black;
- }
-
-You can see here stuff explained in the cited page, with only a slight modification
-explained in the comments, plus some additional rules to make things somewhat cleaner:
-
-* a bit of padding around the logo
-
-* darker metadata which appears by default below the content (the white frame in the page)
-
-To get this CSS file used everywhere in the site, I have to modify the :file:`uiprops.py` file
-introduced above:
-
-.. sourcecode:: python
-
- STYLESHEETS = sheet['STYLESHEETS'] + [data('cubes.sytweb.css')]
-
-.. Note::
- `sheet` is another predefined variable containing values defined by
- already process `:file:`uiprops.py`` file, notably the CubicWeb's one.
-
-Here we simply want our CSS in addition to CubicWeb's base CSS files, so we
-redefine the `STYLESHEETS` variable to existing CSS (accessed through the `sheet`
-variable) with our one added. I could also have done:
-
-.. sourcecode:: python
-
- sheet['STYLESHEETS'].append(data('cubes.sytweb.css'))
-
-But this is less interesting since we don't see the overriding mechanism...
-
-At this point, the site should start looking good, the background image being
-resized to fit the screen.
-
-.. image:: ../../images/tutos-photowebsite_background-image.png
-
-The final touch: let's customize CubicWeb's CSS to get less orange... By simply adding
-
-.. sourcecode:: python
-
- contextualBoxTitleBg = incontextBoxTitleBg = '#AAAAAA'
-
-and reloading the page we've just seen, we know have a nice greyed box instead of
-the orange one:
-
-.. image:: ../../images/tutos-photowebsite_grey-box.png
-
-This is because CubicWeb's CSS include some variables which are
-expanded by values defined in uiprops file. In our case we controlled the
-properties of the CSS `background` property of boxes with CSS class
-`contextualBoxTitleBg` and `incontextBoxTitleBg`.
-
-
-Step 2: configuring boxes
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Boxes present to the user some ways to use the application. Let's first do a few
-user interface tweaks in our :file:`views.py` file:
-
-.. sourcecode:: python
-
- from cubicweb.predicates import none_rset
- from cubicweb.web.views import bookmark
- from cubes.zone import views as zone
- from cubes.tag import views as tag
-
- # change bookmarks box selector so it's only displayed on startup views
- bookmark.BookmarksBox.__select__ = bookmark.BookmarksBox.__select__ & none_rset()
- # move zone box to the left instead of in the context frame and tweak its order
- zone.ZoneBox.context = 'left'
- zone.ZoneBox.order = 100
- # move tags box to the left instead of in the context frame and tweak its order
- tag.TagsBox.context = 'left'
- tag.TagsBox.order = 102
- # hide similarity box, not interested
- tag.SimilarityBox.visible = False
-
-The idea is to move all boxes in the left column, so we get more space for the
-photos. Now, serious things: I want a box similar to the tags box but to handle
-the `Person displayed_on File` relation. We can do this simply by adding a
-:class:`AjaxEditRelationCtxComponent` subclass to our views, as below:
-
-.. sourcecode:: python
-
- from logilab.common.decorators import monkeypatch
- from cubicweb import ValidationError
- from cubicweb.web.views import uicfg, component
- from cubicweb.web.views import basecontrollers
-
- # hide displayed_on relation using uicfg since it will be displayed by the box below
- uicfg.primaryview_section.tag_object_of(('*', 'displayed_on', '*'), 'hidden')
-
- class PersonBox(component.AjaxEditRelationCtxComponent):
- __regid__ = 'sytweb.displayed-on-box'
- # box position
- order = 101
- context = 'left'
- # define relation to be handled
- rtype = 'displayed_on'
- role = 'object'
- target_etype = 'Person'
- # messages
- added_msg = _('person has been added')
- removed_msg = _('person has been removed')
- # bind to js_* methods of the json controller
- fname_vocabulary = 'unrelated_persons'
- fname_validate = 'link_to_person'
- fname_remove = 'unlink_person'
-
-
- @monkeypatch(basecontrollers.JSonController)
- @basecontrollers.jsonize
- def js_unrelated_persons(self, eid):
- """return tag unrelated to an entity"""
- rql = "Any F + ' ' + S WHERE P surname S, P firstname F, X eid %(x)s, NOT P displayed_on X"
- return [name for (name,) in self._cw.execute(rql, {'x' : eid})]
-
-
- @monkeypatch(basecontrollers.JSonController)
- def js_link_to_person(self, eid, people):
- req = self._cw
- for name in people:
- name = name.strip().title()
- if not name:
- continue
- try:
- firstname, surname = name.split(None, 1)
- except:
- raise ValidationError(eid, {('displayed_on', 'object'): 'provide <first name> <surname>'})
- rset = req.execute('Person P WHERE '
- 'P firstname %(firstname)s, P surname %(surname)s',
- locals())
- if rset:
- person = rset.get_entity(0, 0)
- else:
- person = req.create_entity('Person', firstname=firstname,
- surname=surname)
- req.execute('SET P displayed_on X WHERE '
- 'P eid %(p)s, X eid %(x)s, NOT P displayed_on X',
- {'p': person.eid, 'x' : eid})
-
- @monkeypatch(basecontrollers.JSonController)
- def js_unlink_person(self, eid, personeid):
- self._cw.execute('DELETE P displayed_on X WHERE P eid %(p)s, X eid %(x)s',
- {'p': personeid, 'x': eid})
-
-
-You basically subclass to configure with some class attributes. The `fname_*`
-attributes give the name of methods that should be defined on the json control to
-make the AJAX part of the widget work: one to get the vocabulary, one to add a
-relation and another to delete a relation. These methods must start by a `js_`
-prefix and are added to the controller using the `@monkeypatch` decorator. In my
-case, the most complicated method is the one which adds a relation, since it
-tries to see if the person already exists, and else automatically create it,
-assuming the user entered "firstname surname".
-
-Let's see how it looks like on a file primary view:
-
-.. image:: ../../images/tutos-photowebsite_boxes.png
-
-Great, it's now as easy for me to link my pictures to people than to tag them.
-Also, visitors get a consistent display of these two pieces of information.
-
-.. Note::
- The ui component system has been refactored in `CubicWeb 3.10`_, which also
- introduced the :class:`AjaxEditRelationCtxComponent` class.
-
-
-Step 3: configuring facets
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The last feature we'll add today is facet configuration. If you access to the
-'/file' url, you'll see a set of 'facets' appearing in the left column. Facets
-provide an intuitive way to build a query incrementally, by proposing to the user
-various way to restrict the result set. For instance CubicWeb proposes a facet to
-restrict based on who created an entity; the tag cube proposes a facet to
-restrict based on tags; the zoe cube a facet to restrict based on geographical
-location, and so on. In that gist, I want to propose a facet to restrict based on
-the people displayed on the picture. To do so, there are various classes in the
-:mod:`cubicweb.web.facet` module which simply have to be configured using class
-attributes as we've done for the box. In our case, we'll define a subclass of
-:class:`RelationFacet`.
-
-.. Note::
-
- Since that's ui stuff, we'll continue to add code below to our
- :file:`views.py` file. Though we begin to have a lot of various code their, so
- it's may be a good time to split our views module into submodules of a `view`
- package. In our case of a simple application (glue) cube, we could start using
- for instance the layout below: ::
-
- views/__init__.py # uicfg configuration, facets
- views/layout.py # header/footer/background stuff
- views/components.py # boxes, adapters
- views/pages.py # index view, 404 view
-
-.. sourcecode:: python
-
- from cubicweb.web import facet
-
- class DisplayedOnFacet(facet.RelationFacet):
- __regid__ = 'displayed_on-facet'
- # relation to be displayed
- rtype = 'displayed_on'
- role = 'object'
- # view to use to display persons
- label_vid = 'combobox'
-
-Let's say we also want to filter according to the `visibility` attribute. This is
-even simpler as we just have to derive from the :class:`AttributeFacet` class:
-
-.. sourcecode:: python
-
- class VisibilityFacet(facet.AttributeFacet):
- __regid__ = 'visibility-facet'
- rtype = 'visibility'
-
-Now if I search for some pictures on my site, I get the following facets available:
-
-.. image:: ../../images/tutos-photowebsite_facets.png
-
-.. Note::
-
- By default a facet must be applyable to every entity in the result set and
- provide at leat two elements of vocabulary to be displayed (for instance you
- won't see the `created_by` facet if the same user has created all
- entities). This may explain why you don't see yours...
-
-
-Conclusion
-~~~~~~~~~~
-
-We started to see the power behind the infrastructure provided by the
-framework, both on the pure ui (CSS, Javascript) side and on the Python side
-(high level generic classes for components, including boxes and facets). We now
-have, with a few lines of code, a full-featured web site with a personalized look.
-
-Of course we'll probably want more as time goes, but we can now
-concentrate on making good pictures, publishing albums and sharing them with
-friends...
-
-
-
-.. _`CubicWeb 3.10`: http://www.cubicweb.org/blogentry/1330518
-.. _`here`: http://webdesign.about.com/od/css3/f/blfaqbgsize.htm
--- a/doc/book/en/tutorials/base/blog-in-five-minutes.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _TutosBaseBlogFiveMinutes:
-
-Get a blog running in five minutes!
------------------------------------
-
-For Debian or Ubuntu users, first install the following packages
-(:ref:`DebianInstallation`)::
-
- cubicweb, cubicweb-dev, cubicweb-blog
-
-Windows or Mac OS X users must install |cubicweb| from source (see
-:ref:`SourceInstallation` and :ref:`WindowsInstallation`).
-
-Then create and initialize your instance::
-
- cubicweb-ctl create blog myblog
-
-You'll be asked a few questions, and you can keep the default answer for most of
-them. The one question you'll have to think about is the database you'll want to
-use for that instance. For a quick test, if you don't have `postgresql` installed
-and configured (see :ref:`PostgresqlConfiguration`), it's highly recommended to
-choose `sqlite` when asked for which database driver to use, since it has a much
-simple setup (no database server needed).
-
-One the process is completed (including database initialisation), you can start
-your instance by using: ::
-
- cubicweb-ctl start -D myblog
-
-The `-D` option activates the debugging mode. Removing it will launch the instance
-as a daemon in the background, and ``cubicweb-ctl stop myblog`` will stop
-it in that case.
-
-
-About file system permissions
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Unless you installed from sources, the above commands assume that you have root
-access to the :file:`/etc/` directory. In order to initialize your instance as a
-regular user, within your home directory, you can use the :envvar:`CW_MODE`
-environment variable: ::
-
- export CW_MODE=user
-
-then create a :file:`~/etc/cubicweb.d` directory that will hold your instances.
-
-More information about how to configure your own environment is
-available in :ref:`ResourceMode`.
-
-
-Instance parameters
-~~~~~~~~~~~~~~~~~~~
-
-If you would like to change database parameters such as the database host or the
-user name used to connect to the database, edit the `sources` file located in the
-:file:`/etc/cubicweb.d/myblog` directory.
-
-Then relaunch the database creation::
-
- cubicweb-ctl db-create myblog
-
-Other parameters, like web server or emails parameters, can be modified in the
-:file:`/etc/cubicweb.d/myblog/all-in-one.conf` file.
-
-You'll have to restart the instance after modification in one of those files.
-
-This is it. Your blog is functional and running. Visit http://localhost:8080 and enjoy it!
-
--- a/doc/book/en/tutorials/base/conclusion.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-What's next?
-------------
-
-In this tutorial, we have seen that you can, right after the installation of
-|cubicweb|, build a web application in a few minutes by defining a data model as
-assembling cubes. You get a working application that you can then customize there
-and there while keeping something that works. This is important in agile
-development practices, you can right from the start of the project show things
-to customer and so take the right decision early in the process.
-
-The next steps will be to discover hooks, security, data sources, digging deeper
-into view writing and interface customisation... Yet a lot of fun stuff to
-discover! You will find more `tutorials and howtos`_ in the blog published on the
-CubicWeb.org website.
-
-.. _`tutorials and howtos`: http://www.cubicweb.org/view?rql=Any+X+ORDERBY+D+DESC+WHERE+X+is+BlogEntry%2C+T+tags+X%2C+T+name+IN+%28%22tutorial%22%2C+%22howto%22%29%2C+X+creation_date+D
--- a/doc/book/en/tutorials/base/customizing-the-application.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,539 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _TutosBaseCustomizingTheApplication:
-
-Customizing your application
-----------------------------
-
-So far so good. The point is that usually, you won't get enough by assembling
-cubes out-of-the-box. You will want to customize them, have a personal look and
-feel, add your own data model and so on. Or maybe start from scratch?
-
-So let's get a bit deeper and start coding our own cube. In our case, we want
-to customize the blog we created to add more features to it.
-
-
-Create your own cube
-~~~~~~~~~~~~~~~~~~~~
-
-First, notice that if you've installed |cubicweb| using Debian packages, you will
-need the additional ``cubicweb-dev`` package to get the commands necessary to
-|cubicweb| development. All `cubicweb-ctl` commands are described in details in
-:ref:`cubicweb-ctl`.
-
-Once your |cubicweb| development environment is set up, you can create a new
-cube::
-
- cubicweb-ctl newcube myblog
-
-This will create in the cubes directory (:file:`/path/to/grshell/cubes` for source
-installation, :file:`/usr/share/cubicweb/cubes` for Debian packages installation)
-a directory named :file:`blog` reflecting the structure described in
-:ref:`cubelayout`.
-
-For packages installation, you can still create new cubes in your home directory
-using the following configuration. Let's say you want to develop your new cubes
-in `~src/cubes`, then set the following environment variables: ::
-
- CW_CUBES_PATH=~/src/cubes
-
-and then create your new cube using: ::
-
- cubicweb-ctl newcube --directory=~/src/cubes myblog
-
-.. Note::
-
- We previously used `myblog` as the name of our *instance*. We're now creating
- a *cube* with the same name. Both are different things. We'll now try to
- specify when we talk about one or another, but keep in mind this difference.
-
-
-Cube metadata
-~~~~~~~~~~~~~
-
-A simple set of metadata about your cube are stored in the :file:`__pkginfo__.py`
-file. In our case, we want to extend the blog cube, so we have to tell that our
-cube depends on this cube, by modifying the ``__depends__`` dictionary in that
-file:
-
-.. sourcecode:: python
-
- __depends__ = {'cubicweb': '>= 3.10.7',
- 'cubicweb-blog': None}
-
-where the ``None`` means we do not depends on a particular version of the cube.
-
-.. _TutosBaseCustomizingTheApplicationDataModel:
-
-Extending the data model
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-The data model or schema is the core of your |cubicweb| application. It defines
-the type of content your application will handle. It is defined in the file
-:file:`schema.py` of the cube.
-
-
-Defining our model
-******************
-
-For the sake of example, let's say we want a new entity type named `Community`
-with a name, a description. A `Community` will hold several blogs.
-
-.. sourcecode:: python
-
- from yams.buildobjs import EntityType, RelationDefinition, String, RichString
-
- class Community(EntityType):
- name = String(maxsize=50, required=True)
- description = RichString()
-
- class community_blog(RelationDefinition):
- subject = 'Community'
- object = 'Blog'
- cardinality = '*?'
- composite = 'subject'
-
-The first step is the import from the :mod:`yams` package necessary classes to build
-the schema.
-
-This file defines the following:
-
-* a `Community` has a title and a description as attributes
-
- - the name is a string that is required and can't be longer than 50 characters
-
- - the description is a string that is not constrained and may contains rich
- content such as HTML or Restructured text.
-
-* a `Community` may be linked to a `Blog` using the `community_blog` relation
-
- - ``*`` means a community may be linked to 0 to N blog, ``?`` means a blog may
- be linked to 0 to 1 community. For completeness, remember that you can also
- use ``+`` for 1 to N, and ``1`` for single, mandatory relation (e.g. one to one);
-
- - this is a composite relation where `Community` (e.g. the subject of the
- relation) is the composite. That means that if you delete a community, its
- blog will be deleted as well.
-
-Of course, there are a lot of other data types and things such as constraints,
-permissions, etc, that may be defined in the schema, but those won't be covered
-in this tutorial.
-
-Notice that our schema refers to the `Blog` entity type which is not defined
-here. But we know this type is available since we depend on the `blog` cube
-which is defining it.
-
-
-Applying changes to the model into our instance
-***********************************************
-
-Now the problem is that we created an instance using the `blog` cube, not our
-`myblog` cube, so if we don't do anything there is no way that we'll see anything
-changing in the instance.
-
-One easy way, as we've no really valuable data in the instance would be to trash and recreated it::
-
- cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
- cubicweb-ctl delete myblog
- cubicweb-ctl create myblog
- cubicweb-ctl start -D myblog
-
-Another way is to add our cube to the instance using the cubicweb-ctl shell
-facility. It's a python shell connected to the instance with some special
-commands available to manipulate it (the same as you'll have in migration
-scripts, which are not covered in this tutorial). In that case, we're interested
-in the `add_cube` command: ::
-
- $ cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
- $ cubicweb-ctl shell myblog
- entering the migration python shell
- just type migration commands or arbitrary python code and type ENTER to execute it
- type "exit" or Ctrl-D to quit the shell and resume operation
- >>> add_cube('myblog')
- >>>
- $ cubicweb-ctl start -D myblog
-
-The `add_cube` command is enough since it automatically updates our
-application to the cube's schema. There are plenty of other migration
-commands of a more finer grain. They are described in :ref:`migration`
-
-As explained, leave the shell by typing Ctrl-D. If you restart the instance and
-take another look at the schema, you'll see that changes to the data model have
-actually been applied (meaning database schema updates and all necessary stuff
-has been done).
-
-.. image:: ../../images/tutos-base_myblog-schema_en.png
- :alt: the instance schema after adding our cube
-
-If you follow the 'info' link in the user pop-up menu, you'll also see that the
-instance is using blog and myblog cubes.
-
-.. image:: ../../images/tutos-base_myblog-siteinfo_en.png
- :alt: the instance schema after adding our cube
-
-You can now add some communities, link them to blog, etc... You'll see that the
-framework provides default views for this entity type (we have not yet defined any
-view for it!), and also that the blog primary view will show the community it's
-linked to if any. All this thanks to the model driven interface provided by the
-framework.
-
-You'll then be able to redefine each of them according to your needs
-and preferences. We'll now see how to do such thing.
-
-.. _TutosBaseCustomizingTheApplicationCustomViews:
-
-Defining your views
-~~~~~~~~~~~~~~~~~~~
-
-|cubicweb| provides a lot of standard views in directory
-:file:`cubicweb/web/views/`. We already talked about 'primary' and 'list' views,
-which are views which apply to one ore more entities.
-
-A view is defined by a python class which includes:
-
- - an identifier: all objects used to build the user interface in |cubicweb| are
- recorded in a registry and this identifier will be used as a key in that
- registry. There may be multiple views for the same identifier.
-
- - a *selector*, which is a kind of filter telling how well a view suit to a
- particular context. When looking for a particular view (e.g. given an
- identifier), |cubicweb| computes for each available view with that identifier
- a score which is returned by the selector. Then the view with the highest
- score is used. The standard library of predicates is in
- :mod:`cubicweb.predicates`.
-
-A view has a set of methods inherited from the :class:`cubicweb.view.View` class,
-though you usually don't derive directly from this class but from one of its more
-specific child class.
-
-Last but not least, |cubicweb| provides a set of default views accepting any kind
-of entities.
-
-Want a proof? Create a community as you've already done for other entity types
-through the index page, you'll then see something like that:
-
-.. image:: ../../images/tutos-base_myblog-community-default-primary_en.png
- :alt: the default primary view for our community entity type
-
-
-If you notice the weird messages that appear in the page: those are messages
-generated for the new data model, which have no translation yet. To fix that,
-we'll have to use dedicated `cubicweb-ctl` commands:
-
-.. sourcecode: bash
-
- cubicweb-ctl i18ncube myblog # build/update cube's message catalogs
- # then add translation into .po file into the cube's i18n directory
- cubicweb-ctl i18ninstance myblog # recompile instance's message catalogs
- cubicweb-ctl restart -D myblog # instance has to be restarted to consider new catalogs
-
-You'll then be able to redefine each of them according to your needs and
-preferences. So let's see how to do such thing.
-
-Changing the layout of the application
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The layout is the general organization of the pages in the site. Views that generate
-the layout are sometimes referred to as 'templates'. They are implemented in the
-framework in the module :mod:`cubicweb.web.views.basetemplates`. By overriding
-classes in this module, you can customize whatever part you wish of the default
-layout.
-
-But notice that |cubicweb| provides many other ways to customize the
-interface, thanks to actions and components (which you can individually
-(de)activate, control their location, customize their look...) as well as
-"simple" CSS customization. You should first try to achieve your goal using such
-fine grained parametrization rather then overriding a whole template, which usually
-embeds customisation access points that you may loose in the process.
-
-But for the sake of example, let's say we want to change the generic page
-footer... We can simply add to the module ``views`` of our cube,
-e.g. :file:`cubes/myblog/views.py`, the code below:
-
-.. sourcecode:: python
-
- from cubicweb.web.views import basetemplates
-
- class MyHTMLPageFooter(basetemplates.HTMLPageFooter):
-
- def footer_content(self):
- self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
-
- def registration_callback(vreg):
- vreg.register_all(globals().values(), __name__, (MyHTMLPageFooter,))
- vreg.register_and_replace(MyHTMLPageFooter, basetemplates.HTMLPageFooter)
-
-
-* Our class inherits from the default page footer to ease getting things right,
- but this is not mandatory.
-
-* When we want to write something to the output stream, we simply call `self.w`,
- which *must be passed a unicode string*.
-
-* The latest function is the most exotic stuff. The point is that without it, you
- would get an error at display time because the framework wouldn't be able to
- choose which footer to use between :class:`HTMLPageFooter` and
- :class:`MyHTMLPageFooter`, since both have the same selector, hence the same
- score... In this case, we want our footer to replace the default one, so we have
- to define a :func:`registration_callback` function to control object
- registration: the first instruction tells to register everything in the module
- but the :class:`MyHTMLPageFooter` class, then the second to register it instead
- of :class:`HTMLPageFooter`. Without this function, everything in the module is
- registered blindly.
-
-.. Note::
-
- When a view is modified while running in debug mode, it is not required to
- restart the instance server. Save the Python file and reload the page in your
- web browser to view the changes.
-
-We will now have this simple footer on every page of the site.
-
-
-Primary view customization
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The 'primary' view (i.e. any view with the identifier set to 'primary') is the one used to
-display all the information about a single entity. The standard primary view is one
-of the most sophisticated views of all. It has several customisation points, but
-its power comes with `uicfg`, allowing you to control it without having to
-subclass it.
-
-However this is a bit off-topic for this first tutorial. Let's say we simply want a
-custom primary view for my `Community` entity type, using directly the view
-interface without trying to benefit from the default implementation (you should
-do that though if you're rewriting reusable cubes; everything is described in more
-details in :ref:`primary_view`).
-
-
-So... Some code! That we'll put again in the module ``views`` of our cube.
-
-.. sourcecode:: python
-
- from cubicweb.predicates import is_instance
- from cubicweb.web.views import primary
-
- class CommunityPrimaryView(primary.PrimaryView):
- __select__ = is_instance('Community')
-
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
- if entity.description:
- self.w(u'<p>%s</p>' % entity.printable_value('description'))
-
-What's going on here?
-
-* Our class inherits from the default primary view, here mainly to get the correct
- view identifier, since we don't use any of its features.
-
-* We set on it a selector telling that it only applies when trying to display
- some entity of the `Community` type. This is enough to get an higher score than
- the default view for entities of this type.
-
-* View applying to entities usually have to define `cell_call` as entry point,
- and are given `row` and `col` arguments tell to which entity in the result set
- the view is applied. We can then get this entity from the result set
- (`self.cw_rset`) by using the `get_entity` method.
-
-* To ease thing, we access our entity's attribute for display using its
- printable_value method, which will handle formatting and escaping when
- necessary. As you can see, you can also access attributes by their name on the
- entity to get the raw value.
-
-
-You can now reload the page of the community we just created and see the changes.
-
-.. image:: ../../images/tutos-base_myblog-community-custom-primary_en.png
- :alt: the custom primary view for our community entity type
-
-We've seen here a lot of thing you'll have to deal with to write views in
-|cubicweb|. The good news is that this is almost everything that is used to
-build higher level layers.
-
-.. Note::
-
- As things get complicated and the volume of code in your cube increases, you can
- of course still split your views module into a python package with subpackages.
-
-You can find more details about views and selectors in :ref:`Views`.
-
-
-Write entities to add logic in your data
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-|cubicweb| provides an ORM to easily programmaticaly manipulate
-entities (just like the one we have fetched earlier by calling
-`get_entity` on a result set). By default, entity
-types are instances of the :class:`AnyEntity` class, which holds a set of
-predefined methods as well as property automatically generated for
-attributes/relations of the type it represents.
-
-You can redefine each entity to provide additional methods or whatever you want
-to help you write your application. Customizing an entity requires that your
-entity:
-
-- inherits from :class:`cubicweb.entities.AnyEntity` or any subclass
-
-- defines a :attr:`__regid__` linked to the corresponding data type of your schema
-
-You may then want to add your own methods, override default implementation of some
-method, etc...
-
-.. sourcecode:: python
-
- from cubicweb.entities import AnyEntity, fetch_config
-
-
- class Community(AnyEntity):
- """customized class for Community entities"""
- __regid__ = 'Community'
-
- fetch_attrs, cw_fetch_order = fetch_config(['name'])
-
- def dc_title(self):
- return self.name
-
- def display_cw_logo(self):
- return 'CubicWeb' in self.description
-
-In this example:
-
-* we used convenience :func:`fetch_config` function to tell which attributes
- should be prefetched by the ORM when looking for some related entities of this
- type, and how they should be ordered
-
-* we overrode the standard `dc_title` method, used in various place in the interface
- to display the entity (though in this case the default implementation would
- have had the same result)
-
-* we implemented here a method :meth:`display_cw_logo` which tests if the blog
- entry title contains 'CW'. It can then be used when you're writing code
- involving 'Community' entities in your views, hooks, etc. For instance, you can
- modify your previous views as follows:
-
-.. sourcecode:: python
-
-
- class CommunityPrimaryView(primary.PrimaryView):
- __select__ = is_instance('Community')
-
- def cell_call(self, row, col):
- entity = self.cw_rset.get_entity(row, col)
- self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
- if entity.display_cw_logo():
- self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
- if entity.description:
- self.w(u'<p>%s</p>' % entity.printable_value('description'))
-
-Then each community whose description contains 'CW' is shown with the |cubicweb|
-logo in front of it.
-
-.. Note::
-
- As for view, you don't have to restart your instance when modifying some entity
- classes while your server is running in debug mode, the code will be
- automatically reloaded.
-
-
-Extending the application by using more cubes!
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-One of the goal of the |cubicweb| framework was to have truly reusable
-components. To do so, they must both behave nicely when plugged into the
-application and be easily customisable, from the data model to the user
-interface. And I think the result is pretty successful, thanks to system such as
-the selection mechanism and the choice to write views as python code which allows
-to build our page using true object oriented programming techniques, that no
-template language provides.
-
-
-A library of standard cubes is available from `CubicWeb Forge`_, to address a
-lot of common concerns such has manipulating people, files, things to do, etc. In
-our community blog case, we could be interested for instance in functionalities
-provided by the `comment` and `tag` cubes. The former provides threaded
-discussion functionalities, the latter a simple tag mechanism to classify content.
-Let's say we want to try those. We will first modify our cube's :file:`__pkginfo__.py`
-file:
-
-.. sourcecode:: python
-
- __depends__ = {'cubicweb': '>= 3.10.7',
- 'cubicweb-blog': None,
- 'cubicweb-comment': None,
- 'cubicweb-tag': None}
-
-Now, we'll simply tell on which entity types we want to activate the 'comment'
-and 'tag' facilities by adding respectively the 'comments' and 'tags' relations on
-them in our schema (:file:`schema.py`).
-
-.. sourcecode:: python
-
- class comments(RelationDefinition):
- subject = 'Comment'
- object = 'BlogEntry'
- cardinality = '1*'
- composite = 'object'
-
- class tags(RelationDefinition):
- subject = 'Tag'
- object = ('Community', 'BlogEntry')
-
-
-So in the case above we activated comments on `BlogEntry` entities and tags on
-both `Community` and `BlogEntry`. Various views from both `comment` and `tag`
-cubes will then be automatically displayed when one of those relations is
-supported.
-
-Let's synchronize the data model as we've done earlier: ::
-
-
- $ cubicweb-ctl stop myblog
- $ cubicweb-ctl shell myblog
- entering the migration python shell
- just type migration commands or arbitrary python code and type ENTER to execute it
- type "exit" or Ctrl-D to quit the shell and resume operation
- >>> add_cubes(('comment', 'tag'))
- >>>
-
-Then restart the instance. Let's look at a blog entry:
-
-.. image:: ../../images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png
- :alt: the primary view for a blog entry with comments and tags activated
-
-As you can see, we now have a box displaying tags and a section proposing to add
-a comment and displaying existing one below the post. All this without changing
-anything in our views, thanks to the design of generic views provided by the
-framework. Though if we take a look at a community, we won't see the tags box!
-That's because by default this box try to locate itself in the left column within
-the white frame, and this column is handled by the primary view we
-hijacked. Let's change our view to make it more extensible, by keeping both our
-custom rendering but also extension points provided by the default
-implementation.
-
-
-.. sourcecode:: python
-
- class CommunityPrimaryView(primary.PrimaryView):
- __select__ = is_instance('Community')
-
- def render_entity_title(self, entity):
- self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
-
- def render_entity_attributes(self, entity):
- if entity.display_cw_logo():
- self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
- if entity.description:
- self.w(u'<p>%s</p>' % entity.printable_value('description'))
-
-It appears now properly:
-
-.. image:: ../../images/tutos-base_myblog-community-taggable-primary_en.png
- :alt: the custom primary view for a community entry with tags activated
-
-You can control part of the interface independently from each others, piece by
-piece. Really.
-
-
-
-.. _`CubicWeb Forge`: http://www.cubicweb.org/project
--- a/doc/book/en/tutorials/base/discovering-the-ui.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,161 +0,0 @@
-
-.. _TutosBaseDiscoveringTheUI:
-
-Discovering the web interface
------------------------------
-
-You can now access your web instance to create blogs and post messages
-by visiting the URL http://localhost:8080/.
-
-By default, anonymous access is disabled, so a login form will appear. If you
-asked to allow anonymous access when initializing the instance, click on the
-'login' link in the top right hand corner. To login, you need then use the admin
-account you specified at the time you initialized the database with
-``cubicweb-ctl create``.
-
-.. image:: ../../images/tutos-base_login-form_en.png
- :alt: the login form
-
-
-Once authenticated, you can start playing with your instance. The default index
-page looks like the following:
-
-.. image:: ../../images/tutos-base_index_en.png
- :alt: the index page
-
-
-Minimal configuration
-~~~~~~~~~~~~~~~~~~~~~
-
-Before creating entities, let's change that 'unset title' thing that appears
-here and there. This comes from a |cubicweb| system properties. To set it,
-click on the 'site configuration link' in the pop-up menu behind your login name
-in the upper left-hand corner
-
-.. image:: ../../images/tutos-base_user-menu_en.png
- :alt: the user pop-up menu
-
-The site title is in the 'Ui' section. Simply set it to the desired value and
-click the 'validate' button.
-
-.. image:: ../../images/tutos-base_siteconfig_en.png
- :alt: the site configuration form
-
-You should see a 'changes applied' message. You can now go back to the
-index page by clicking on the |cubicweb| logo in the upper left-hand corner.
-
-You will much likely still see 'unset title' at this point. This is because by
-default the index page is cached. Force a refresh of the page (by typing Ctrl-R
-in Firefox for instance) and you should now see the title you entered.
-
-
-Adding entities
-~~~~~~~~~~~~~~~
-
-The ``blog`` cube defines several entity types, among them ``Blog`` which is a
-container for ``BlogEntry`` (i.e. posts) on a particular topic. We can get a
-graphical view of the schema by clicking on the 'site schema' link in the user
-pop-up menu we've already seen:
-
-.. image:: ../../images/tutos-base_schema_en.png
- :alt: graphical view of the schema (aka data-model)
-
-Nice isn't it? Notice that this, as most other stuff we'll see in this tutorial,
-is generated by the framework according to the model of the application. In our
-case, the model defined by the ``blog`` cube.
-
-Now let us create a few of these entities.
-
-
-Add a blog
-**********
-
-Clicking on the `[+]` at the left of the 'Blog' link on the index page will lead
-you to an HTML form to create a blog.
-
-.. image:: ../../images/tutos-base_blog-form_en.png
- :alt: the blog creation form
-
-For instance, call this new blog 'Tech-blog' and type in 'everything about
-technology' as the description , then validate the form by clicking on
-'Validate'. You will be redirected to the `primary` view of the newly created blog.
-
-.. image:: ../../images/tutos-base_blog-primary_en.png
- :alt: the blog primary view
-
-
-Add a blog post
-***************
-
-There are several ways to add a blog entry. The simplest is to click on the 'add
-blog entry' link in the actions box on viewing the blog you have just created.
-You will then see a form to create a post, with a 'blog entry of' field preset
-to the blog we're coming from. Enter a title, some content, click the 'validate'
-button and you're done. You will be redirected to the blog primary view, though you
-now see that it contains the blog post you've just created.
-
-.. image:: ../../images/tutos-base_blog-primary-after-post-creation_en.png
- :alt: the blog primary view after creation of a post
-
-Notice there are some new boxes that appears in the left column.
-
-You can achieve the same thing by following the same path as we did for the blog
-creation, e.g. by clicking on the `[+]` at the left of the 'Blog entry' link on
-the index page. The diffidence being that since there is no context information,
-the 'blog entry of' selector won't be preset to the blog.
-
-
-If you click on the 'modify' link of the action box, you are back to
-the form to edit the entity you just created, except that the form now
-has another section with a combo-box entitled 'add relation'. It
-provisos a generic way to edit relations which don't appears in the
-above form. Choose the relation you want to add and a second combo box
-appears where you can pick existing entities. If there are too many
-of them, you will be offered to navigate to the target entity, that is
-go away from the form and go back to it later, once you've selected
-the entity you want to link with.
-
-.. image:: ../../images/tutos-base_form-generic-relations_en.png
- :alt: the generic relations combo box
-
-This combo box can't appear until the entity is actually created. That's why you
-haven't seen it at creation time. You could also have hit 'Apply' instead of
-'validate' and it would have showed up.
-
-
-About ui auto-adaptation
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-One of the things that make |cubicweb| different of other frameworks is
-its automatic user interface that adapts itself according to the data being
-displayed. Let's see an example.
-
-If you go back to the home page an click on the 'Blog' link, you will be redirected
-to the primary view of the blog, the same we've seen earlier. Now, add another
-blog, go back to the index page, and click again on this link. You will see
-a very different view (namely the 'list' view).
-
-.. image:: ../../images/tutos-base_blogs-list_en.png
- :alt: the list view when there are more than one blog to display
-
-This is because in the first case, the framework chose to use the 'primary'
-view since there was only one entity in the data to be displayed. Now that there
-are two entities, the 'list' view is more appropriate and hence is being used.
-
-There are various other places where |cubicweb| adapts to display data in the best
-way, the main being provided by the view *selection* mechanism that will be detailed
-later.
-
-
-Digging deeper
-~~~~~~~~~~~~~~
-
-By following principles explained below, you should now be able to
-create new users for your application, to configure with a finer
-grain, etc... You will notice that the index page lists a lot of types
-you don't know about. Most are built-in types provided by the framework
-to make the whole system work. You may ignore them in a first time and
-discover them as time goes.
-
-One thing that is worth playing with is the search box. It may be used in various
-way, from simple full text search to advanced queries using the :ref:`RQL` .
--- a/doc/book/en/tutorials/base/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-.. _TutosBase:
-
-Building a simple blog with |cubicweb|
-======================================
-
-|cubicweb| is a semantic web application framework that favors reuse and
-object-oriented design.
-
-
-This tutorial is designed to help in your very first steps to start with
-|cubicweb|. We will tour through basic concepts such as:
-
-* getting an application running by using existing components
-* discovering the default user interface
-* basic extending and customizing the look and feel of that application
-
-More advanced concepts are covered in :ref:`TutosPhotoWebSite`.
-
-
-.. _TutosBaseVocab:
-
-Some vocabulary
----------------
-
-|cubicweb| comes with a few words of vocabulary that you should know to
-understand what we're talking about. To follow this tutorial, you should at least
-know that:
-
-* a `cube` is a component that usually includes a model defining some data types
- and a set of views to display them. A cube can be built by assembling other
- cubes;
-
-* an `instance` is a specific installation of one or more cubes and includes
- configuration files, a web server and a database.
-
-Reading :ref:`Concepts` for more vocabulary will be required at some point.
-
-Now, let's start the hot stuff!
-
-.. toctree::
- :maxdepth: 2
-
- blog-in-five-minutes
- discovering-the-ui
- customizing-the-application
- conclusion
--- a/doc/book/en/tutorials/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-.. _Tutorials:
-
----------
-Tutorials
----------
-
-We present two tutorials of different levels. The blog building
-tutorial introduces one smoothly to the basic concepts.
-
-Then there is a photo gallery construction tutorial which highlights
-more advanced concepts such as unit tests, security settings,
-migration scripts.
-
-.. toctree::
- :maxdepth: 1
- :numbered:
-
- base/index
- advanced/index
- tools/windmill.rst
- textreports/index
--- a/doc/book/en/tutorials/textreports/index.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-.. -*- coding: utf-8 -*-
-
-Writing text reports with RestructuredText
-==========================================
-
-|cubicweb| offers several text formats for the RichString type used in schemas,
-including restructuredtext.
-
-Three additional restructuredtext roles are defined by |cubicweb|:
-
-.. autofunction:: cubicweb.ext.rest.eid_reference_role
-.. autofunction:: cubicweb.ext.rest.rql_role
-.. autofunction:: cubicweb.ext.rest.bookmark_role
--- a/doc/book/en/tutorials/tools/windmill.rst Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,229 +0,0 @@
-==========================
-Use Windmill with CubicWeb
-==========================
-
-Windmill_ implements cross browser testing, in-browser recording and playback,
-and functionality for fast accurate debugging and test environment integration.
-
-.. _Windmill: http://www.getwindmill.com/
-
-`Online features list <http://www.getwindmill.com/features>`_ is available.
-
-
-Installation
-============
-
-Windmill
---------
-
-You have to install Windmill manually for now. If you're using Debian, there is
-no binary package (`yet <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=579109>`_).
-
-The simplest solution is to use a *setuptools/pip* command (for a clean
-environment, take a look to the `virtualenv
-<http://pypi.python.org/pypi/virtualenv>`_ project as well)::
-
- $ pip install windmill
- $ curl -O http://github.com/windmill/windmill/tarball/master
-
-However, the Windmill project doesn't release frequently. Our recommandation is
-to used the last snapshot of the Git repository::
-
- $ git clone git://github.com/windmill/windmill.git HEAD
- $ cd windmill
- $ python setup.py develop
-
-Install instructions are `available <http://wiki.github.com/windmill/windmill/installing>`_.
-
-Be sure to have the windmill module in your PYTHONPATH afterwards::
-
- $ python -c "import windmill"
-
-X dummy
--------
-
-In order to reduce unecessary system load from your test machines, It's
-recommended to use X dummy server for testing the Unix web clients, you need a
-dummy video X driver (as xserver-xorg-video-dummy package in Debian) coupled
-with a light X server as `Xvfb <http://en.wikipedia.org/wiki/Xvfb>`_.
-
- The dummy driver is a special driver available with the XFree86 DDX. To use
- the dummy driver, simply substitue it for your normal card driver in the
- Device section of your xorg.conf configuration file. For example, if you
- normally uses an ati driver, then you will have a Device section with
- Driver "ati" to let the X server know that you want it to load and use the
- ati driver; however, for these conformance tests, you would change that
- line to Driver "dummy" and remove any other ati specific options from the
- Device section.
-
- *From: http://www.x.org/wiki/XorgTesting*
-
-Then, you can run the X server with the following command ::
-
- $ /usr/bin/X11/Xvfb :1 -ac -screen 0 1280x1024x8 -fbdir /tmp
-
-
-Windmill usage
-==============
-
-Record your use case
---------------------
-
-- start your instance manually
-- start Windmill_ with url site as last argument (read Usage_ or use *'-h'*
- option to find required command line arguments)
-- use the record button
-- click on save to obtain python code of your use case
-- copy the content to a new file in a *windmill* directory
-
-.. _Usage: http://wiki.github.com/windmill/windmill/running-tests
-
-If you are using firefox as client, consider the "firebug" option.
-
-If you have a running instance, you can refine the test by the *loadtest* windmill option::
-
- $ windmill -m firebug loadtest=<test_file.py> <instance url>
-
-Or use the internal windmill shell to explore available commands::
-
- $ windmill -m firebug shell <instance url>
-
-And enter python commands:
-
-.. sourcecode:: python
-
- >>> load_test(<your test file>)
- >>> run_test(<your test file>)
-
-
-
-Integrate Windmill tests into CubicWeb
-======================================
-
-Set environment
----------------
-
-You have to create a new unit test file and a `windmill` directory and copy all
-your windmill use case into it.
-
-.. sourcecode:: python
-
- # test_windmill.py
-
- # Run all scenarii found in windmill directory
- from cubicweb.devtools.cwwindmill import (CubicWebWindmillUseCase,
- unittest_main)
-
- if __name__ == '__main__':
- unittest_main()
-
-Run your tests
---------------
-
-You can easily run your windmill test suite through `pytest` or :mod:`unittest`.
-You have to copy a *test_windmill.py* file from :mod:`web.test`.
-
-To run your test series::
-
- $ pytest test/test_windmill.py
-
-By default, CubicWeb will use **firefox** as the default browser and will try
-to run test instance server on localhost. In the general case, You've no need
-to change anything.
-
-Check :class:`cubicweb.devtools.cwwindmill.CubicWebWindmillUseCase` for
-Windmill configuration. You can edit windmill settings with following class attributes:
-
-* browser
- identification string (firefox|ie|safari|chrome) (firefox by default)
-* test_dir
- testing file path or directory (windmill directory under your unit case
- file by default)
-* edit_test
- load and edit test for debugging (False by default)
-
-Examples:
-
-.. sourcecode:: python
-
- browser = 'firefox'
- test_dir = osp.join(__file__, 'windmill')
- edit_test = False
-
-If you want to change cubicweb test server parameters, you can check class
-variables from :class:`CubicWebServerConfig` or inherit it with overriding the
-:attr:`configcls` attribute in :class:`CubicWebServerTC` ::
-
-.. sourcecode:: python
-
- class OtherCubicWebServerConfig(CubicWebServerConfig):
- port = 9999
-
- class NewCubicWebServerTC(CubicWebServerTC):
- configcls = OtherCubicWebServerConfig
-
-For instance, CubicWeb framework windmill tests can be manually run by::
-
- $ pytest web/test/test_windmill.py
-
-Edit your tests
----------------
-
-You can toggle the `edit_test` variable to enable test edition.
-
-But if you are using `pytest` as test runner, use the `-i` option directly.
-The test series will be loaded and you can run assertions step-by-step::
-
- $ pytest -i test/test_windmill.py
-
-In this case, the `firebug` extension will be loaded automatically for you.
-
-Afterwards, don't forget to save your edited test into the right file (no autosave feature).
-
-Best practises
---------------
-
-Don't run another instance on the same port. You risk to silence some
-regressions (test runner will automatically fail in further versions).
-
-Start your use case by using an assert on the expected primary url page.
-Otherwise all your tests could fail without clear explanation of the used
-navigation.
-
-In the same location of the *test_windmill.py*, create a *windmill/* with your
-windmill recorded use cases.
-
-
-Caveats
-=======
-
-File Upload
------------
-
-Windmill can't do file uploads. This is a limitation of browser Javascript
-support / sandboxing, not of Windmill per se. It would be nice if there were
-some command that would prime the Windmill HTTP proxy to add a particular file
-to the next HTTP request that comes through, so that uploads could at least be
-faked.
-
-.. http://groups.google.com/group/windmill-dev/browse_thread/thread/cf9dc969722bd6bb/01aa18fdd652f7ff?lnk=gst&q=input+type+file#01aa18fdd652f7ff
-
-.. http://davisagli.com/blog/in-browser-integration-testing-with-windmill
-
-.. http://groups.google.com/group/windmill-dev/browse_thread/thread/b7bebcc38ed30dc7
-
-
-Preferences
-===========
-
-A *.windmill/prefs.py* could be used to redefine default configuration values.
-
-.. define CubicWeb preferences in the parent test case instead with a dedicated firefox profile
-
-For managing browser extensions, read `advanced topic chapter
-<http://wiki.github.com/windmill/windmill/advanced-topics>`_.
-
-More configuration examples could be seen in *windmill/conf/global_settings.py*
-as template.
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,2 @@
+.. -*- coding: utf-8 -*-
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/intro/concepts.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,306 @@
+.. -*- coding: utf-8 -*-
+
+.. _Concepts:
+
+The Core Concepts of |cubicweb|
+===============================
+
+This section defines some terms and core concepts of the |cubicweb| framework. To
+avoid confusion while reading this book, take time to go through the following
+definitions and use this section as a reference during your reading.
+
+
+.. _Cube:
+
+Cubes
+-----
+
+A cube is a software component made of three parts: its data model
+(:mod:`schema`), its logic (:mod:`entities`) and its user interface
+(:mod:`views`).
+
+A cube can use other cubes as building blocks and assemble them to provide a
+whole with richer functionnalities than its parts. The cubes `cubicweb-blog`_ and
+`cubicweb-comment`_ could be used to make a cube named *myblog* with commentable
+blog entries.
+
+The `CubicWeb.org Forge`_ offers a large number of cubes developed by the community
+and available under a free software license.
+
+.. note::
+
+ The command :command:`cubicweb-ctl list` displays the list of available cubes.
+
+.. _`CubicWeb.org Forge`: http://www.cubicweb.org/project/
+.. _`cubicweb-blog`: http://www.cubicweb.org/project/cubicweb-blog
+.. _`cubicweb-comment`: http://www.cubicweb.org/project/cubicweb-comment
+
+
+.. _Instance:
+
+Instances
+---------
+
+An instance is a runnable application installed on a computer and based on a
+cube.
+
+The instance directory contains the configuration files. Several instances can be
+created and based on the same cube. For exemple, several software forges can be
+set up on one computer system based on the `cubicweb-forge`_ cube.
+
+.. _`cubicweb-forge`: http://www.cubicweb.org/project/cubicweb-forge
+
+Instances can be of three different types: all-in-one, web engine or data
+repository. For applications that support high traffic, several web (front-end)
+and data (back-end) instances can be set-up to share the load.
+
+.. image:: ../images/archi_globale_en.png
+
+The command :command:`cubicweb-ctl list` also displays the list of instances
+installed on your system.
+
+.. note::
+
+ The term application is used to refer to "something that should do something as
+ a whole", eg more like a project and so can refer to an instance or to a cube,
+ depending on the context. This book will try to use *application*, *cube* and
+ *instance* as appropriate.
+
+
+.. _RepositoryIntro:
+
+Data Repository
+---------------
+
+The data repository [1]_ encapsulates and groups an access to one or
+more data sources (including SQL databases, LDAP repositories, other
+|cubicweb| instance repositories, filesystems, Google AppEngine's
+DataStore, etc).
+
+All interactions with the repository are done using the `Relation Query Language`
+(:ref:`RQL`). The repository federates the data sources and hides them from the
+querier, which does not realize when a query spans several data sources
+and requires running sub-queries and merges to complete.
+
+Application logic can be mapped to data events happenning within the
+repository, like creation of entities, deletion of relations,
+etc. This is used for example to send email notifications when the
+state of an object changes. See :ref:`HookIntro` below.
+
+.. [1] not to be confused with a Mercurial repository or a Debian repository.
+.. _`Python Remote Objects`: http://pythonhosted.org/Pyro4/
+
+.. _WebEngineIntro:
+
+Web Engine
+----------
+
+The web engine replies to http requests and runs the user interface.
+
+By default the web engine provides a `CRUD`_ user interface based on
+the data model of the instance. Entities can be created, displayed,
+updated and deleted. As the default user interface is not very fancy,
+it is usually necessary to develop your own.
+
+It is common to run the web engine and the repository in the same
+process (see instances of type all-in-one above), but this is not a
+requirement. A repository can be set up to be accessed remotely using
+Pyro (`Python Remote Objects`_) and act as a standalone server, which
+can be directly accessed or also through a standalone web engine.
+
+.. _`CRUD`: http://en.wikipedia.org/wiki/Create,_read,_update_and_delete
+
+.. _SchemaIntro:
+
+Schema (Data Model)
+-------------------
+
+The data model of a cube is described as an entity-relationship schema using a
+comprehensive language made of Python classes imported from the yams_ library.
+
+.. _yams: http://www.logilab.org/project/yams/
+
+An `entity type` defines a sequence of attributes. Attributes may be
+of the following types: `String`, `Int`, `Float`, `Boolean`, `Date`,
+`Time`, `Datetime`, `Interval`, `Password`, `Bytes`, `RichString`.
+
+A `relation type` is used to define an oriented binary relation
+between entity types. The left-hand part of a relation is named the
+`subject` and the right-hand part is named the `object`.
+
+A `relation definition` is a triple (*subject entity type*, *relation type*, *object
+entity type*) associated with a set of properties such as cardinality,
+constraints, etc.
+
+Permissions can be set on entity types or relation definition to control who
+will be able to create, read, update or delete entities and relations. Permissions
+are granted to groups (to which users may belong) or using rql expressions (if the
+rql expression returns some results, the permission is granted).
+
+Some meta-data necessary to the system are added to the data model. That includes
+entities like users and groups, the entities used to store the data model
+itself and attributes like unique identifier, creation date, creator, etc.
+
+When you create a new |cubicweb| instance, the schema is stored in the database.
+When the cubes the instance is based on evolve, they may change their data model
+and provide migration scripts that will be executed when the administrator will
+run the upgrade process for the instance.
+
+
+.. _VRegistryIntro:
+
+Registries and application objects
+----------------------------------
+
+Application objects
+~~~~~~~~~~~~~~~~~~~
+
+Besides a few core functionalities, almost every feature of the framework is
+achieved by dynamic objects (`application objects` or `appobjects`) stored in a
+two-levels registry. Each object is affected to a registry with
+an identifier in this registry. You may have more than one object sharing an
+identifier in the same registry:
+
+ object's `__registry__` : object's `__regid__` : [list of app objects]
+
+In other words, the `registry` contains several (sub-)registries which hold a
+list of appobjects associated to an identifier.
+
+The base class of appobjects is :class:`cubicweb.appobject.AppObject`.
+
+Selectors
+~~~~~~~~~
+
+At runtime, appobjects can be selected in a registry according to some
+contextual information. Selection is done by comparing the *score*
+returned by each appobject's *selector*.
+
+The better the object fits the context, the higher the score. Scores
+are the glue that ties appobjects to the data model. Using them
+appropriately is an essential part of the construction of well behaved
+cubes.
+
+|cubicweb| provides a set of basic selectors that may be parametrized. Also,
+selectors can be combined with the `~` unary operator (negation) and the binary
+operators `&` and `|` (respectivly 'and' and 'or') to build more complex
+selectors. Of course complex selectors may be combined too. Last but not least, you
+can write your own selectors.
+
+The `registry`
+~~~~~~~~~~~~~~~
+
+At startup, the `registry` inspects a number of directories looking
+for compatible class definitions. After a recording process, the
+objects are assigned to registries and become available through the
+selection process.
+
+In a cube, application object classes are looked in the following modules or
+packages:
+
+- `entities`
+- `views`
+- `hooks`
+- `sobjects`
+
+There are three common ways to look up some application object from a
+registry:
+
+* get the most appropriate object by specifying an identifier and
+ context objects. The object with the greatest score is
+ selected. There should always be a single appobject with a greater
+ score than others for a particular context.
+
+* get all objects applying to a context by specifying a registry. A
+ list of objects will be returned containing the object with the
+ highest score (> 0) for each identifier in that registry.
+
+* get the object within a particular registry/identifier. No selection
+ process is involved: the registry will expect to find a single
+ object in that cell.
+
+
+.. _RQLIntro:
+
+The RQL query language
+----------------------
+
+No need for a complicated ORM when you have a powerful data
+manipulation language.
+
+All the persistent data in a |cubicweb| instance is retrieved and
+modified using RQL (see :ref:`rql_intro`).
+
+This query language is inspired by SQL but is on a higher level in order to
+emphasize browsing relations.
+
+
+Result set
+~~~~~~~~~~
+
+Every request made (using RQL) to the data repository returns an object we call a
+Result Set. It enables easy use of the retrieved data, providing a translation
+layer between the backend's native datatypes and |cubicweb| schema's EntityTypes.
+
+Result sets provide access to the raw data, yielding either basic Python data
+types, or schema-defined high-level entities, in a straightforward way.
+
+
+.. _ViewIntro:
+
+Views
+-----
+
+**CubicWeb is data driven**
+
+The view system is loosely coupled to data through the selection system explained
+above. Views are application objects with a dedicated interface to 'render'
+something, eg producing some html, text, xml, pdf, or whatsover that can be
+displayed to a user.
+
+Views actually are partitioned into different kind of objects such as
+`templates`, `boxes`, `components` and proper `views`, which are more
+high-level abstraction useful to build the user interface in an object
+oriented way.
+
+
+.. _HookIntro:
+
+Hooks and operations
+--------------------
+
+**CubicWeb provides an extensible data repository**
+
+The data model defined using Yams types allows to express the data
+model in a comfortable way. However several aspects of the data model
+can not be expressed there. For instance:
+
+* managing computed attributes
+
+* enforcing complicated business rules
+
+* real-world side-effects linked to data events (email notification
+ being a prime example)
+
+The hook system is much like the triggers of an SQL database engine,
+except that:
+
+* it is not limited to one specific SQL backend (every one of them
+ having an idiomatic way to encode triggers), nor to SQL backends at
+ all (think about LDAP or a Subversion repository)
+
+* it is well-coupled to the rest of the framework
+
+Hooks are also application objects (in the `hooks` registry) and
+selected on events such as after/before add/update/delete on
+entities/relations, server startup or shutdown, etc.
+
+`Operations` may be instantiated by hooks to do further processing at different
+steps of the transaction's commit / rollback, which usually can not be done
+safely at the hook execution time.
+
+Hooks and operation are an essential building block of any moderately complicated
+cubicweb application.
+
+.. note::
+ RQL queries executed in hooks and operations are *unsafe* by default, i.e. the
+ read and write security is deactivated unless explicitly asked.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/intro/history.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,32 @@
+.. -*- coding: utf-8 -*-
+
+A little history...
+===================
+
+*CubicWeb* is a semantic web application framework that Logilab_ started
+developing in 2001 as an offspring of its Narval_ research project. *CubicWeb*
+is written in Python and includes a data server and a web engine.
+
+Its data server publishes data federated from different sources like
+SQL databases, LDAP directories, `VCS`_ repositories or even from other
+CubicWeb data servers.
+
+.. _`VCS`: http://en.wikipedia.org/wiki/Revision_control
+
+Its web engine was designed to let the final user control what content to select
+and how to display it. It allows one to browse the federated data sources and
+display the results with the rendering that best fits the context. This
+flexibility of the user interface gives back to the user some capabilities
+usually only accessible to application developers.
+
+*CubicWeb* has been developed by Logilab_ and used in-house for many years
+before it was first installed for its clients in 2006 as version 2.
+
+In 2008, *CubicWeb* version 3 became downloadable for free under the
+terms of the LGPL license. Its community is now steadily growing
+without hampering the fast-paced stream of changes thanks to the time
+and energy originally put in the design of the framework.
+
+
+.. _Narval: http://www.logilab.org/project/narval-moved
+.. _Logilab: http://www.logilab.fr/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/intro/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,19 @@
+.. -*- coding: utf-8 -*-
+
+.. _Part1:
+
+--------------------------
+Introduction to *CubicWeb*
+--------------------------
+
+This first part of the book offers different reading path to
+discover the *CubicWeb* framework, provides a tutorial to get a quick
+overview of its features and lists its key concepts.
+
+
+.. toctree::
+ :maxdepth: 2
+ :numbered:
+
+ history
+ concepts.rst
--- a/doc/book/mode_plan.py Mon Jul 06 17:39:35 2015 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""
->>> from mode_plan import *
->>> ls()
-<list of directory content>
->>> ren('A01','A03')
-rename A010-joe.en.txt to A030-joe.en.txt
-accept [y/N]?
-"""
-
-def ren(a,b):
- names = glob.glob('%s*'%a)
- for name in names :
- print 'rename %s to %s' % (name, name.replace(a,b))
- if raw_input('accept [y/N]?').lower() =='y':
- for name in names:
- os.system('hg mv %s %s' % (name, name.replace(a,b)))
-
-
-def ls(): print '\n'.join(sorted(os.listdir('.')))
-
-def move():
- filenames = []
- for name in sorted(os.listdir('.')):
- num = name[:2]
- if num.isdigit():
- filenames.append( (int(num), name) )
-
-
- #print filenames
-
- for num, name in filenames:
- if num >= start:
- print 'hg mv %s %2i%s' %(name,num+1,name[2:])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.14.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,164 @@
+Whats new in CubicWeb 3.14
+==========================
+
+First notice CW 3.14 depends on yams 0.34 (which is incompatible with prior
+cubicweb releases regarding instance re-creation).
+
+API changes
+-----------
+
+* `Entity.fetch_rql` `restriction` argument has been deprecated and should be
+ replaced with a call to the new `Entity.fetch_rqlst` method, get the returned
+ value (a rql `Select` node) and use the RQL syntax tree API to include the
+ above-mentionned restrictions.
+
+ Backward compat is kept with proper warning.
+
+* `Entity.fetch_order` and `Entity.fetch_unrelated_order` class methods have been
+ replaced by `Entity.cw_fetch_order` and `Entity.cw_fetch_unrelated_order` with
+ a different prototype:
+
+ - instead of taking (attr, var) as two string argument, they now take (select,
+ attr, var) where select is the rql syntax tree beinx constructed and var the
+ variable *node*.
+
+ - instead of returning some string to be inserted in the ORDERBY clause, it has
+ to modify the syntax tree
+
+ Backward compat is kept with proper warning, BESIDE cases below:
+
+ - custom order method return **something else the a variable name with or
+ without the sorting order** (e.g. cases where you sort on the value of a
+ registered procedure as it was done in the tracker for instance). In such
+ case, an error is logged telling that this sorting is ignored until API
+ upgrade.
+
+ - client code use direct access to one of those methods on an entity (no code
+ known to do that).
+
+* `Entity._rest_attr_info` class method has been renamed to
+ `Entity.cw_rest_attr_info`
+
+ No backward compat yet since this is a protected method an no code is known to
+ use it outside cubicweb itself.
+
+* `AnyEntity.linked_to` has been removed as part of a refactoring of this
+ functionality (link a entity to another one at creation step). It was replaced
+ by a `EntityFieldsForm.linked_to` property.
+
+ In the same refactoring, `cubicweb.web.formfield.relvoc_linkedto`,
+ `cubicweb.web.formfield.relvoc_init` and
+ `cubicweb.web.formfield.relvoc_unrelated` were removed and replaced by
+ RelationField methods with the same names, that take a form as a parameter.
+
+ **No backward compatibility yet**. It's still time to cry for it.
+ Cubes known to be affected: tracker, vcsfile, vcreview.
+
+* `CWPermission` entity type and its associated require_permission relation type
+ (abstract) and require_group relation definitions have been moved to a new
+ `localperms` cube. With this have gone some functions from the
+ `cubicweb.schemas` package as well as some views. This makes cubicweb itself
+ smaller while you get all the local permissions stuff into a single,
+ documented, place.
+
+ Backward compat is kept for existing instances, **though you should have
+ installed the localperms cubes**. A proper error should be displayed when
+ trying to migrate to 3.14 an instance the use `CWPermission` without the new
+ cube installed. For new instances / test, you should add a dependancy on the
+ new cube in cubes using this feature, along with a dependancy on cubicweb >=
+ 3.14.
+
+* jQuery has been updated to 1.6.4 and jquery-tablesorter to 2.0.5. No backward
+ compat issue known.
+
+* Table views refactoring : new `RsetTableView` and `EntityTableView`, as well as
+ rewritten an enhanced version of `PyValTableView` on the same bases, with logic
+ moved to some column renderers and a layout. Those should be well documented
+ and deprecates former `TableView`, `EntityAttributesTableView` and `CellView`,
+ which are however kept for backward compat, with some warnings that may not be
+ very clear unfortunatly (you may see your own table view subclass name here,
+ which doesn't make the problem that clear). Notice that `_cw.view('table',
+ rset, *kwargs)` will be routed to the new `RsetTableView` or to the old
+ `TableView` depending on given extra arguments. See #1986413.
+
+* `display_name` don't call .lower() anymore. This may leads to changes in your
+ user interface. Different msgid for upper/lower cases version of entity type
+ names, as this is the only proper way to handle this with some languages.
+
+* `IEditControlAdapter` has been deprecated in favor of `EditController`
+ overloading, which was made easier by adding dedicated selectors called
+ `match_edited_type` and `match_form_id`.
+
+* Pre 3.6 API backward compat has been dropped, though *data* migration
+ compatibility has been kept. You may have to fix errors due to old API usage
+ for your instance before to be able to run migration, but then you should be
+ able to upgrade even a pre 3.6 database.
+
+* Deprecated `cubicweb.web.views.iprogress` in favor of new `iprogress` cube.
+
+* Deprecated `cubicweb.web.views.flot` in favor of new `jqplot` cube.
+
+
+Unintrusive API changes
+-----------------------
+
+* Refactored properties forms (eg user preferences and site wide properties) as
+ well as pagination components to ease overridding.
+
+* New `cubicweb.web.uihelper` module with high-level helpers for uicfg.
+
+* New `anonymized_request` decorator to temporary run stuff as an anonymous
+ user, whatever the currently logged in user.
+
+* New 'verbatimattr' attribute view.
+
+* New facet and form widget for Integer used to store binary mask.
+
+* New `js_href` function to generated proper javascript href.
+
+* `match_kwargs` and `match_form_params` selectors both accept a new
+ `once_is_enough` argument.
+
+* `printable_value` is now a method of request, and may be given dict of
+ formatters to use.
+
+* `[Rset]TableView` allows to set None in 'headers', meaning the label should be
+ fetched from the result set as done by default.
+
+* Field vocabulary computation on entity creation now takes `__linkto`
+ information into accounet.
+
+* Started a `cubicweb.pylintext` pylint plugin to help pylint analyzing cubes.
+
+
+RQL
+---
+
+* Support for HAVING in 'SET' and 'DELETE' queries.
+
+* new `AT_TZ` function to get back a timestamp at a given time-zone.
+
+* new `WEEKDAY` date extraction function
+
+
+User interface changes
+----------------------
+
+* Datafeed source now present an history of the latest import's log, including
+ global status and debug/info/warning/error messages issued during
+ imports. Import logs older than a configurable amount of time are automatically
+ deleted.
+
+* Breadcrumbs component is properly kept when creating an entity with '__linkto'.
+
+* users and groups management now really lead to that (i.e. includes *groups*
+ management).
+
+* New 'jsonp' controller with 'jsonexport' and 'ejsonexport' views.
+
+
+Configuration
+------------
+
+* Added option 'resources-concat' to make javascript/css files concatenation
+ optional.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.15.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,96 @@
+What's new in CubicWeb 3.15?
+============================
+
+New functionnalities
+--------------------
+
+* Add Zmq server, based on the cutting edge ZMQ (http://www.zeromq.org/) socket
+ library. This allows to access distant instance, in a similar way as Pyro.
+
+* Publish/subscribe mechanism using ZMQ for communication among cubicweb
+ instances. The new zmq-address-sub and zmq-address-pub configuration variables
+ define where this communication occurs. As of this release this mechanism is
+ used for entity cache invalidation.
+
+* Improved WSGI support. While there is still some caveats, most of the code
+ which was twisted only is now generic and allows related functionalities to work
+ with a WSGI front-end.
+
+* Full undo/transaction support : undo of modification has eventually been
+ implemented, and the configuration simplified (basically you activate it or not
+ on an instance basis).
+
+* Controlling HTTP status code used is not much more easier :
+
+ - `WebRequest` now has a `status_out` attribut to control the response status ;
+
+ - most web-side exceptions take an optional ``status`` argument.
+
+API changes
+-----------
+
+* The base registry implementation has been moved to a new
+ `logilab.common.registry` module (see #1916014). This includes code from :
+
+ * `cubicweb.vreg` (the whole things that was in there)
+ * `cw.appobject` (base selectors and all).
+
+ In the process, some renaming was done:
+
+ * the top level registry is now `RegistryStore` (was `VRegistry`), but that
+ should not impact cubicweb client code ;
+
+ * former selectors functions are now known as "predicate", though you still use
+ predicates to build an object'selector ;
+
+ * for consistency, the `objectify_selector` decoraror has hence be renamed to
+ `objectify_predicate` ;
+
+ * on the CubicWeb side, the `selectors` module has been renamed to
+ `predicates`.
+
+ Debugging refactoring dropped the more need for the `lltrace` decorator. There
+ should be full backward compat with proper deprecation warnings. Notice the
+ `yes` predicate and `objectify_predicate` decorator, as well as the
+ `traced_selection` function should now be imported from the
+ `logilab.common.registry` module.
+
+* All login forms are now submitted to <app_root>/login. Redirection to requested
+ page is now handled by the login controller (it was previously handle by the
+ session manager).
+
+* `Publisher.publish` has been renamed to `Publisher.handle_request`. This
+ method now contains generic version of logic previously handled by
+ Twisted. `Controller.publish` is **not** affected.
+
+Unintrusive API changes
+-----------------------
+
+* New 'ldapfeed' source type, designed to replace 'ldapuser' source with
+ data-feed (i.e. copy based) source ideas.
+
+* New 'zmqrql' source type, similar to 'pyrorql' but using ømq instead of Pyro.
+
+* A new registry called `services` has appeared, where you can register
+ server-side `cubicweb.server.Service` child classes. Their `call` method can be
+ invoked from a web-side AppObject instance using new `self._cw.call_service`
+ method or a server-side one using `self.session.call_service`. This is a new
+ way to call server-side methods, much cleaner than monkey patching the
+ Repository class, which becomes a deprecated way to perform similar tasks.
+
+* a new `ajax-func` registry now hosts all remote functions (i.e. functions
+ callable through the `asyncRemoteExec` JS api). A convenience `ajaxfunc`
+ decorator will let you expose your python function easily without all the
+ appobject standard boilerplate. Backward compatibility is preserved.
+
+* the 'json' controller is now deprecated in favor of the 'ajax' one.
+
+* `WebRequest.build_url` can now take a __secure__ argument. When True cubicweb
+ try to generate an https url.
+
+
+User interface changes
+----------------------
+
+A new 'undohistory' view expose the undoable transactions and give access to undo
+some of them.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.16.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,97 @@
+What's new in CubicWeb 3.16?
+============================
+
+New functionalities
+--------------------
+
+* Add a new dataimport store (`SQLGenObjectStore`). This store enables a fast
+ import of data (entity creation, link creation) in CubicWeb, by directly
+ flushing information in SQL. This may only be used with PostgreSQL, as it
+ requires the 'COPY FROM' command.
+
+
+API changes
+-----------
+
+* Orm: `set_attributes` and `set_relations` are unified (and
+ deprecated) in favor of `cw_set` that works in all cases.
+
+* db-api/configuration: all the external repository connection information is
+ now in an URL (see `#2521848 <http://www.cubicweb.org/2521848>`_),
+ allowing to drop specific options of pyro nameserver host, group, etc and fix
+ broken `ZMQ <http://www.zeromq.org/>`_ source. Configuration related changes:
+
+ * Dropped 'pyro-ns-host', 'pyro-instance-id', 'pyro-ns-group' from the client side
+ configuration, in favor of 'repository-uri'. **NO MIGRATION IS DONE**,
+ supposing there is no web-only configuration in the wild.
+
+ * Stop discovering the connection method through `repo_method` class attribute
+ of the configuration, varying according to the configuration class. This is
+ a first step on the way to a simpler configuration handling.
+
+ DB-API related changes:
+
+ * Stop indicating the connection method using `ConnectionProperties`.
+
+ * Drop `_cnxtype` attribute from `Connection` and `cnxtype` from
+ `Session`. The former is replaced by a `is_repo_in_memory` property
+ and the later is totaly useless.
+
+ * Turn `repo_connect` into `_repo_connect` to mark it as a private function.
+
+ * Deprecate `in_memory_cnx` which becomes useless, use `_repo_connect` instead
+ if necessary.
+
+* the "tcp://" uri scheme used for `ZMQ <http://www.zeromq.org/>`_
+ communications (in a way reminiscent of Pyro) is now named
+ "zmqpickle-tcp://", so as to make room for future zmq-based lightweight
+ communications (without python objects pickling).
+
+* Request.base_url gets a `secure=True` optional parameter that yields
+ an https url if possible, allowing hook-generated content to send
+ secure urls (e.g. when sending mail notifications)
+
+* Dataimport ucsvreader gets a new boolean `ignore_errors`
+ parameter.
+
+
+Unintrusive API changes
+-----------------------
+
+* Drop of `cubicweb.web.uicfg.AutoformSectionRelationTags.bw_tag_map`,
+ deprecated since 3.6.
+
+
+User interface changes
+----------------------
+
+* The RQL search bar has now some auto-completion support. It means
+ relation types or entity types can be suggested while typing. It is
+ an awesome improvement over the current behaviour !
+
+* The `action box` associated with `table` views (from `tableview.py`)
+ has been transformed into a nice-looking series of small tabs; it
+ means that the possible actions are immediately visible and need not
+ be discovered by clicking on an almost invisible icon on the upper
+ right.
+
+* The `uicfg` module has moved to web/views/ and ui configuration
+ objects are now selectable. This will reduce the amount of
+ subclassing and whole methods replacement usually needed to
+ customize the ui behaviour in many cases.
+
+* Remove changelog view, as neither cubicweb nor known
+ cubes/applications were properly feeding related files.
+
+
+Other changes
+-------------
+
+* 'pyrorql' sources will be automatically updated to use an URL to locate the source
+ rather than configuration option. 'zmqrql' sources were broken before this change,
+ so no upgrade is needed...
+
+* Debugging filters for Hooks and Operations have been added.
+
+* Some cubicweb-ctl commands used to show the output of `msgcat` and
+ `msgfmt`; they don't anymore.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.17.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,60 @@
+What's new in CubicWeb 3.17?
+============================
+
+New functionalities
+--------------------
+
+* add a command to compare db schema and file system schema
+ (see `#464991 <http://www.cubicweb.org/464991>`_)
+
+* Add CubicWebRequestBase.content with the content of the HTTP request (see #2742453)
+ (see `#2742453 <http://www.cubicweb.org/2742453>`_)
+
+* Add directive bookmark to ReST rendering
+ (see `#2545595 <http://www.cubicweb.org/ticket/2545595>`_)
+
+* Allow user defined final type
+ (see `#124342 <https://www.logilab.org/ticket/124342>`_)
+
+
+API changes
+-----------
+
+* drop typed_eid() in favour of int() (see `#2742462 <http://www.cubicweb.org/2742462>`_)
+
+* The SIOC views and adapters have been removed from CubicWeb and moved to the
+ `sioc` cube.
+
+* The web page embedding views and adapters have been removed from CubicWeb and
+ moved to the `embed` cube.
+
+* The email sending views and controllers have been removed from CubicWeb and
+ moved to the `massmailing` cube.
+
+* ``RenderAndSendNotificationView`` is deprecated in favor of
+ ``ActualNotificationOp`` the new operation use the more efficient *data*
+ idiom.
+
+* Looping task can now have a interval <= ``0``. Negative interval disable the
+ looping task entirely.
+
+* We now serve html instead of xhtml.
+ (see `#2065651 <http://www.cubicweb.org/ticket/2065651>`_)
+
+
+Deprecation
+---------------------
+
+* ``ldapuser`` have been deprecated. It'll be fully dropped in the next
+ version. If you are still using ldapuser switch to ``ldapfeed`` **NOW**!
+
+* ``hijack_user`` have been deprecated. It will be dropped soon.
+
+Deprecated Code Drops
+----------------------
+
+* The progress views and adapters have been removed from CubicWeb. These
+ classes were deprecated since 3.14.0. They are still available in the
+ `iprogress` cube.
+
+* API deprecated since 3.7 have been dropped.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.18.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,101 @@
+What's new in CubicWeb 3.18?
+============================
+
+The migration script does not handle sqlite nor mysql instances.
+
+
+New functionalities
+--------------------
+
+* add a security debugging tool
+ (see `#2920304 <http://www.cubicweb.org/2920304>`_)
+
+* introduce an `add` permission on attributes, to be interpreted at
+ entity creation time only and allow the implementation of complex
+ `update` rules that don't block entity creation (before that the
+ `update` attribute permission was interpreted at entity creation and
+ update time)
+
+* the primary view display controller (uicfg) now has a
+ `set_fields_order` method similar to the one available for forms
+
+* new method `ResultSet.one(col=0)` to retrive a single entity and enforce the
+ result has only one row (see `#3352314 https://www.cubicweb.org/ticket/3352314`_)
+
+* new method `RequestSessionBase.find` to look for entities
+ (see `#3361290 https://www.cubicweb.org/ticket/3361290`_)
+
+* the embedded jQuery copy has been updated to version 1.10.2, and jQuery UI to
+ version 1.10.3.
+
+* initial support for wsgi for the debug mode, available through the new
+ ``wsgi`` cubicweb-ctl command, which can use either python's builtin
+ wsgi server or the werkzeug module if present.
+
+* a ``rql-table`` directive is now available in ReST fields
+
+* cubicweb-ctl upgrade can now generate the static data resource directory
+ directly, without a manual call to gen-static-datadir.
+
+API changes
+-----------
+
+* not really an API change, but the entity permission checks are now
+ systematically deferred to an operation, instead of a) trying in a
+ hook and b) if it failed, retrying later in an operation
+
+* The default value storage for attributes is no longer String, but
+ Bytes. This opens the road to storing arbitrary python objects, e.g.
+ numpy arrays, and fixes a bug where default values whose truth value
+ was False were not properly migrated.
+
+* `symmetric` relations are no more handled by an rql rewrite but are
+ now handled with hooks (from the `activeintegrity` category); this
+ may have some consequences for applications that do low-level database
+ manipulations or at times disable (some) hooks.
+
+* `unique together` constraints (multi-columns unicity constraints)
+ get a `name` attribute that maps the CubicWeb contraint entities to
+ corresponding backend index.
+
+* BreadCrumbEntityVComponent's open_breadcrumbs method now includes
+ the first breadcrumbs separator
+
+* entities can be compared for equality and hashed
+
+* the ``on_fire_transition`` predicate accepts a sequence of possible
+ transition names
+
+* the GROUP_CONCAT rql aggregate function no longer repeats duplicate
+ values, on the sqlite and postgresql backends
+
+Deprecation
+---------------------
+
+* ``pyrorql`` sources have been deprecated. Multisource will be fully dropped
+ in the next version. If you are still using pyrorql, switch to ``datafeed``
+ **NOW**!
+
+* the old multi-source system
+
+* `find_one_entity` and `find_entities` in favor of `find`
+ (see `#3361290 https://www.cubicweb.org/ticket/3361290`_)
+
+* the `TmpFileViewMixin` and `TmpPngView` classes (see `#3400448
+ https://www.cubicweb.org/ticket/3400448`_)
+
+Deprecated Code Drops
+----------------------
+
+* ``ldapuser`` have been dropped; use ``ldapfeed`` now
+ (see `#2936496 <http://www.cubicweb.org/2936496>`_)
+
+* action ``GotRhythm`` was removed, make sure you do not
+ import it in your cubes (even to unregister it)
+ (see `#3093362 <http://www.cubicweb.org/3093362>`_)
+
+* all 3.8 backward compat is gone
+
+* all 3.9 backward compat (including the javascript side) is gone
+
+* the ``twisted`` (web-only) instance type has been removed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.19.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,180 @@
+What's new in CubicWeb 3.19?
+============================
+
+New functionalities
+--------------------
+
+* implement Cross Origin Resource Sharing (CORS)
+ (see `#2491768 <http://www.cubicweb.org/2491768>`_)
+
+* system_source.create_eid can get a range of IDs, to reduce overhead of batch
+ entity creation
+
+Behaviour Changes
+-----------------
+
+* The anonymous property of Session and Connection are now computed from the
+ related user login. If it matches the ``anonymous-user`` in the config the
+ connection is anonymous. Beware that the ``anonymous-user`` config is web
+ specific. Therefore, no session may be anonymous in a repository only setup.
+
+
+New Repository Access API
+-------------------------
+
+Connection replaces Session
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A new explicit Connection object replaces Session as the main repository entry
+point. Connection holds all the necessary methods to be used server-side
+(``execute``, ``commit``, ``rollback``, ``call_service``, ``entity_from_eid``,
+etc...). One obtains a new Connection object using ``session.new_cnx()``.
+Connection objects need to have an explicit begin and end. Use them as a context
+manager to never miss an end::
+
+ with session.new_cnx() as cnx:
+ cnx.execute('INSERT Elephant E, E name "Babar"')
+ cnx.commit()
+ cnx.execute('INSERT Elephant E, E name "Celeste"')
+ cnx.commit()
+ # Once you get out of the "with" clause, the connection is closed.
+
+Using the same Connection object in multiple threads will give you access to the
+same Transaction. However, Connection objects are not thread safe (hence at your
+own risks).
+
+``repository.internal_session`` is deprecated in favor of
+``repository.internal_cnx``. Note that internal connections are now `safe` by default,
+i.e. the integrity hooks are enabled.
+
+Backward compatibility is preserved on Session.
+
+
+dbapi vs repoapi
+~~~~~~~~~~~~~~~~
+
+A new API has been introduced to replace the dbapi. It is called `repoapi`.
+
+There are three relevant functions for now:
+
+* ``repoapi.get_repository`` returns a Repository object either from an
+ URI when used as ``repoapi.get_repository(uri)`` or from a config
+ when used as ``repoapi.get_repository(config=config)``.
+
+* ``repoapi.connect(repo, login, **credentials)`` returns a ClientConnection
+ associated with the user identified by the credentials. The
+ ClientConnection is associated with its own Session that is closed
+ when the ClientConnection is closed. A ClientConnection is a
+ Connection-like object to be used client side.
+
+* ``repoapi.anonymous_cnx(repo)`` returns a ClientConnection associated
+ with the anonymous user if described in the config.
+
+
+repoapi.ClientConnection replace dbapi.Connection and company
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+On the client/web side, the Request is now using a ``repoapi.ClientConnection``
+instead of a ``dbapi.connection``. The ``ClientConnection`` has multiple backward
+compatible methods to make it look like a ``dbapi.Cursor`` and ``dbapi.Connection``.
+
+Session used on the Web side are now the same than the one used Server side.
+Some backward compatibility methods have been installed on the server side Session
+to ease the transition.
+
+The authentication stack has been altered to use the ``repoapi`` instead of
+the ``dbapi``. Cubes adding new element to this stack are likely to break.
+
+Session data can be accessed using the cnx.data dictionary, while
+transaction data is available through cnx.transaction_data. These
+replace the [gs]et_shared_data methods with optional txid kwarg.
+
+New API in tests
+~~~~~~~~~~~~~~~~
+
+All current methods and attributes used to access the repo on ``CubicWebTC`` are
+deprecated. You may now use a ``RepoAccess`` object. A ``RepoAccess`` object is
+linked to a new ``Session`` for a specified user. It is able to create
+``Connection``, ``ClientConnection`` and web side requests linked to this
+session::
+
+ access = self.new_access('babar') # create a new RepoAccess for user babar
+ with access.repo_cnx() as cnx:
+ # some work with server side cnx
+ cnx.execute(...)
+ cnx.commit()
+ cnx.execute(...)
+ cnx.commit()
+
+ with access.client_cnx() as cnx:
+ # some work with client side cnx
+ cnx.execute(...)
+ cnx.commit()
+
+ with access.web_request(elephant='babar') as req:
+ # some work with client side cnx
+ elephant_name = req.form['elephant']
+ req.execute(...)
+ req.cnx.commit()
+
+By default ``testcase.admin_access`` contains a ``RepoAccess`` object for the
+default admin session.
+
+
+API changes
+-----------
+
+* ``RepositorySessionManager.postlogin`` is now called with two arguments,
+ request and session. And this now happens before the session is linked to the
+ request.
+
+* ``SessionManager`` and ``AuthenticationManager`` now take a repo object at
+ initialization time instead of a vreg.
+
+* The ``async`` argument of ``_cw.call_service`` has been dropped. All calls are
+ now synchronous. The zmq notification bus looks like a good replacement for
+ most async use cases.
+
+* ``repo.stats()`` is now deprecated. The same information is available through
+ a service (``_cw.call_service('repo_stats')``).
+
+* ``repo.gc_stats()`` is now deprecated. The same information is available through
+ a service (``_cw.call_service('repo_gc_stats')``).
+
+* ``repo.register_user()`` is now deprecated. The functionality is now
+ available through a service (``_cw.call_service('register_user')``).
+
+* ``request.set_session`` no longer takes an optional ``user`` argument.
+
+* CubicwebTC does not have repo and cnx as class attributes anymore. They are
+ standard instance attributes. ``set_cnx`` and ``_init_repo`` class methods
+ become instance methods.
+
+* ``set_cnxset`` and ``free_cnxset`` are deprecated. cnxset are now
+ automatically managed.
+
+* The implementation of cascading deletion when deleting `composite`
+ entities has changed. There comes a semantic change: merely deleting
+ a composite relation does not entail any more the deletion of the
+ component side of the relation.
+
+* ``_cw.user_callback`` and ``_cw.user_rql_callback`` are deprecated. Users
+ are encouraged to write an actual controller (e.g. using ``ajaxfunc``)
+ instead of storing a closure in the session data.
+
+* A new ``entity.cw_linkable_rql`` method provides the rql to fetch all entities
+ that are already or may be related to the current entity using the given
+ relation.
+
+
+Deprecated Code Drops
+----------------------
+
+* session.hijack_user mechanism has been dropped.
+
+* EtypeRestrictionComponent has been removed, its functionality has been
+ replaced by facets a while ago.
+
+* the old multi-source support has been removed. Only copy-based sources
+ remain, such as datafeed or ldapfeed.
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.20.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,78 @@
+What's new in CubicWeb 3.20
+===========================
+
+New features
+------------
+
+* virtual relations: a new ComputedRelation class can be used in
+ schema.py; its `rule` attribute is an RQL snippet that defines the new
+ relation.
+
+* computed attributes: an attribute can now be defined with a `formula`
+ argument (also an RQL snippet); it will be read-only, and updated
+ automatically.
+
+ Both of these features are described in `CWEP-002`_, and the updated
+ "Data model" chapter of the CubicWeb book.
+
+* cubicweb-ctl plugins can use the ``cubicweb.utils.admincnx`` function
+ to get a Connection object from an instance name.
+
+* new 'tornado' wsgi backend
+
+* session cookies have the HttpOnly flag, so they're no longer exposed to
+ javascript
+
+* rich text fields can be formatted as markdown
+
+* the edit controller detects concurrent editions, and raises a ValidationError
+ if an entity was modified between form generation and submission
+
+* cubicweb can use a postgresql "schema" (namespace) for its tables
+
+* "cubicweb-ctl configure" can be used to set values of the admin user
+ credentials in the sources configuration file
+
+* in debug mode, setting the _cwtracehtml parameter on a request allows tracing
+ where each bit of output is produced
+
+.. _CWEP-002: http://hg.logilab.org/review/cwep/file/tip/CWEP-002.rst
+
+
+API Changes
+-----------
+
+* ``ucsvreader()`` and ``ucsvreader_pb()`` from the ``dataimport`` module have
+ 2 new keyword arguments ``delimiter`` and ``quotechar`` to replace the
+ ``separator`` and ``quote`` arguments respectively. This makes the API match
+ that of Python's ``csv.reader()``. The old arguments are still supported
+ though deprecated.
+
+* the migration environment's ``remove_cube`` function is now called ``drop_cube``.
+
+* cubicweb.old.css is now cubicweb.css. The previous "new"
+ cubicweb.css, along with its cubicweb.reset.css companion, have been
+ removed.
+
+* the jquery-treeview plugin was updated to its latest version
+
+
+Deprecated Code Drops
+----------------------
+
+* most of 3.10 and 3.11 backward compat is gone; this includes:
+ - CtxComponent.box_action() and CtxComponent.build_link()
+ - cubicweb.devtools.htmlparser.XMLDemotingValidator
+ - various methods and properties on Entities, replaced by cw_edited and cw_attr_cache
+ - 'commit_event' method on hooks, replaced by 'postcommit_event'
+ - server.hook.set_operation(), replaced by Operation.get_instance(...).add_data()
+ - View.div_id(), View.div_class() and View.create_url()
+ - `*VComponent` classes
+ - in forms, Field.value() and Field.help() must take the form and the field itself as arguments
+ - form.render() must get `w` as a named argument, and renderer.render() must take `w` as first argument
+ - in breadcrumbs, the optional `recurs` argument must be a set, not False
+ - cubicweb.web.views.idownloadable.{download_box,IDownloadableLineView}
+ - primary views no longer have `render_entity_summary` and `summary` methods
+ - WFHistoryVComponent's `cell_call` method is replaced by `render_body`
+ - cubicweb.dataimport.ObjectStore.add(), replaced by create_entity
+ - ManageView.{folders,display_folders}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,13 @@
+Changes
+-------
+
+.. toctree::
+ :maxdepth: 1
+
+ 3.14
+ 3.15
+ 3.16
+ 3.17
+ 3.18
+ 3.19
+ 3.20
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/conf.py Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,223 @@
+# -*- coding: utf-8 -*-
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""
+
+"""
+#
+# Cubicweb documentation build configuration file, created by
+# sphinx-quickstart on Fri Oct 31 09:10:36 2008.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+from os import path as osp
+
+path = __file__
+path = osp.dirname(path) # ./doc
+path = osp.dirname(path) # ./
+path = osp.join(path, '__pkginfo__.py') # ./__pkginfo__.py
+cw = {}
+execfile(path, {}, cw)
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+#sys.path.append(os.path.abspath('some/directory'))
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.viewcode',
+ 'logilab.common.sphinx_ext',
+ ]
+
+autoclass_content = 'both'
+
+# Add any paths that contain templates here, relative to this directory.
+#templates_path = []
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = 'CubicWeb'
+copyright = '2001-2014, Logilab'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '.'.join(str(n) for n in cw['numversion'][:2])
+# The full version, including alpha/beta/rc tags.
+release = cw['version']
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+unused_docs = []
+
+# List of directories, relative to source directories, that shouldn't be searched
+# for source files.
+#exclude_dirs = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+#html_style = 'sphinx-default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = '%s %s' % (project, release)
+
+html_theme_path = ['_themes']
+html_theme = 'cubicweb'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (within the static path) to place at the top of
+# the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['.static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+#html_copy_source = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+html_file_suffix = '.html'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Cubicwebdoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'Cubicweb.tex', 'Cubicweb Documentation',
+ 'Logilab', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
+
+#aafig_format = dict(latex='pdf', html='svg', text=None)
+
+rst_epilog = """
+.. |cubicweb| replace:: *CubicWeb*
+.. |yams| replace:: *Yams*
+.. |rql| replace:: *RQL*
+"""
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/dev/documenting.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,85 @@
+====
+Book
+====
+
+----
+Part
+----
+
+Chapter
+=======
+
+.. _Level1AnchorForLaterReference:
+
+Level 1 section
+---------------
+
+Level 2 section
+~~~~~~~~~~~~~~~
+
+Level 3 section
+```````````````
+
+
+
+*CubicWeb*
+
+
+inline directives:
+ :file:`directory/file`
+ :envvar:`AN_ENV_VARIABLE`
+ :command:`command --option arguments`
+
+ :ref:, :mod:
+
+
+.. sourcecode:: python
+
+ class SomePythonCode:
+ ...
+
+.. XXX a comment, wont be rendered
+
+
+a [foot note]_
+
+.. [foot note] the foot note content
+
+
+Boxes
+=====
+
+- warning box:
+ .. warning::
+
+ Warning content
+- note box:
+ .. note::
+
+ Note content
+
+
+
+Cross references
+================
+
+To arbitrary section
+--------------------
+
+:ref:`identifier` ou :ref:`label <identifier>`
+
+Label required of referencing node which as no title, else the node's title will be used.
+
+
+To API objects
+--------------
+See the autodoc sphinx extension documentation. Quick overview:
+
+* ref to a class: :class:`cubicweb.devtools.testlib.AutomaticWebTest`
+
+* if you can to see only the class name in the generated documentation, add a ~:
+ :class:`~cubicweb.devtools.testlib.AutomaticWebTest`
+
+* you can also use :mod: (module), :exc: (exception), :func: (function), :meth: (method)...
+
+* syntax explained above to specify label explicitly may also be used
Binary file doc/images/03-transitions-view_en.png has changed
Binary file doc/images/archi_globale.png has changed
Binary file doc/images/archi_globale_en.png has changed
Binary file doc/images/breadcrumbs_header.png has changed
Binary file doc/images/facet_date_range.png has changed
Binary file doc/images/facet_has_image.png has changed
Binary file doc/images/facet_overview.png has changed
Binary file doc/images/facet_range.png has changed
Binary file doc/images/lax-book_00-login_en.png has changed
Binary file doc/images/lax-book_01-start_en.png has changed
Binary file doc/images/lax-book_02-cookie-values_en.png has changed
Binary file doc/images/lax-book_02-create-blog_en.png has changed
Binary file doc/images/lax-book_03-list-one-blog_en.png has changed
Binary file doc/images/lax-book_03-site-config-panel_en.png has changed
Binary file doc/images/lax-book_03-state-submitted_en.png has changed
Binary file doc/images/lax-book_03-transitions-view_en.png has changed
Binary file doc/images/lax-book_04-detail-one-blog_en.png has changed
Binary file doc/images/lax-book_05-list-two-blog_en.png has changed
Binary file doc/images/lax-book_06-add-relation-entryof_en.png has changed
Binary file doc/images/lax-book_06-main-template-logo_en.png has changed
Binary file doc/images/lax-book_07-detail-one-blogentry_en.png has changed
Binary file doc/images/lax-book_08-schema_en.png has changed
Binary file doc/images/lax-book_09-new-view-blogentry_en.png has changed
Binary file doc/images/lax-book_10-blog-with-two-entries_en.png has changed
Binary file doc/images/main_template.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/images/main_template.svg Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1036.6421"
+ height="845.07812"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="main_template.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0"
+ inkscape:export-filename="/home/auc/cw/doc/book/en/images/main_template.png"
+ inkscape:export-xdpi="60.659016"
+ inkscape:export-ydpi="60.659016">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.80355603"
+ inkscape:cx="510.91495"
+ inkscape:cy="422.53906"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="925"
+ inkscape:window-height="1168"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:snap-bbox="true" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(162.2968,90.697922)">
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2439"
+ width="854.37006"
+ height="698.2019"
+ x="20.307629"
+ y="-20.575344" />
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3301"
+ width="816.3457"
+ height="508.15628"
+ x="31.751091"
+ y="96.33345" />
+ <g
+ id="g3220"
+ transform="matrix(1.0035394,0,0,1,0.5745006,0)">
+ <rect
+ y="-89.447922"
+ x="-161.0468"
+ height="55.714287"
+ width="1031.1713"
+ id="rect3240"
+ style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.50000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ id="text3264"
+ y="-51.771908"
+ x="757.85767"
+ style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3266"
+ y="-51.771908"
+ x="757.85767"
+ sodipodi:role="line">header</tspan></text>
+ </g>
+ <rect
+ style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.775;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3270"
+ width="167.87744"
+ height="707.71222"
+ x="-160.02441"
+ y="-24.671618" />
+ <g
+ id="g2434"
+ transform="matrix(0.975467,0,0,1,0.6942419,-3.6587365)">
+ <rect
+ y="35.365849"
+ x="29.548275"
+ height="55.714287"
+ width="842.59979"
+ id="rect3279"
+ style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ id="text3281"
+ y="72.885193"
+ x="681.65283"
+ style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3283"
+ y="72.885193"
+ x="681.65283"
+ sodipodi:role="line">contentheader</tspan></text>
+ </g>
+ <g
+ id="g3170"
+ transform="matrix(1.0023324,0,0,1,-2.0421673,-10.976211)">
+ <rect
+ y="698.6355"
+ x="-158.28485"
+ height="55.714287"
+ width="1032.5997"
+ id="rect3285"
+ style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ id="text3287"
+ y="736.52045"
+ x="770.28204"
+ style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3289"
+ y="736.52045"
+ x="770.28204"
+ sodipodi:role="line">footer</tspan></text>
+ </g>
+ <g
+ id="g3211" />
+ <g
+ id="g3215"
+ transform="matrix(0.9712065,0,0,1,0.7659296,-17.074106)">
+ <rect
+ style="fill:#dfdfdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3291"
+ width="844.62012"
+ height="55.714287"
+ x="27.850754"
+ y="629.88562" />
+ <text
+ id="text3293"
+ y="666.60339"
+ x="692.85773"
+ style="font-size:23.38711166px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3295"
+ y="666.60339"
+ x="692.85773"
+ sodipodi:role="line">contentfooter</tspan></text>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:23.38711166px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="-143.67273"
+ y="20.58094"
+ id="text3297"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2432"
+ x="-143.67273"
+ y="20.58094">left column</tspan></text>
+ <text
+ transform="scale(0.9876573,1.0124969)"
+ id="text3175"
+ y="12.071429"
+ x="721.0575"
+ style="font-size:23.09845161px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3177"
+ y="12.071429"
+ x="721.0575"
+ sodipodi:role="line">contentcol</tspan></text>
+ <text
+ transform="scale(0.9876573,1.0124969)"
+ id="text3179"
+ y="126.27104"
+ x="701.45959"
+ style="font-size:23.09845161px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3181"
+ y="126.27104"
+ x="701.45959"
+ sodipodi:role="line">contentmain</tspan></text>
+ </g>
+</svg>
Binary file doc/images/main_template_layout.png has changed
Binary file doc/images/primaryview_template.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/images/primaryview_template.svg Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,285 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1036.6421"
+ height="845.07812"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="primaryview_template.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0"
+ inkscape:export-filename="/home/steph/local/fcubicweb/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="43.451603"
+ inkscape:export-ydpi="43.451603">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.9357135"
+ inkscape:cx="518.32104"
+ inkscape:cy="337.0428"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1307"
+ inkscape:window-height="1168"
+ inkscape:window-x="0"
+ inkscape:window-y="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Calque 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(162.2968,90.697922)">
+ <g
+ id="g3869"
+ transform="matrix(1,0,0,1.0373644,0,-72.039777)"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449">
+ <rect
+ y="-15.840891"
+ x="-159.08963"
+ height="770.11017"
+ width="1033.0049"
+ id="rect3301"
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.90144825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <text
+ id="text3865"
+ y="19.784882"
+ x="-150.07172"
+ style="font-size:28.67479324px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ xml:space="preserve"><tspan
+ id="tspan3867"
+ y="19.784882"
+ x="-150.07172"
+ sodipodi:role="line">contentmain</tspan></text>
+ </g>
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.45654476;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2383"
+ width="772.32111"
+ height="43.888428"
+ x="-131.1837"
+ y="86.559296"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%"
+ x="-122.69418"
+ y="115.50363"
+ id="text2385"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ x="-122.69418"
+ y="115.50363"
+ id="tspan3163">navcontenttop</tspan></text>
+ <rect
+ style="fill:#ffd5d5;fill-rule:evenodd;stroke:#000000;stroke-width:3.06523442;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3167"
+ width="770.26868"
+ height="203.16078"
+ x="-125.88269"
+ y="172.90417"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="348.26724"
+ y="205.34305"
+ id="text3169"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ x="348.26724"
+ y="205.34305"
+ id="tspan3171">render_entity_attributes()</tspan></text>
+ <rect
+ style="fill:#ffd5d5;fill-rule:evenodd;stroke:#000000;stroke-width:3.06523442;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3173"
+ width="769.93549"
+ height="237.84663"
+ x="-125.03326"
+ y="391.32156"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="360.99954"
+ y="428.38055"
+ id="text3175"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ x="360.99954"
+ y="428.38055"
+ id="tspan3177">render_entity_relations()</tspan></text>
+ <rect
+ style="fill:#ffd5d5;fill-rule:evenodd;stroke:#000000;stroke-width:2.15903592;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3185"
+ width="178.93939"
+ height="612.36584"
+ x="667.10443"
+ y="84.64225"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans;font-stretch:normal;font-variant:normal;text-anchor:start;text-align:start;writing-mode:lr;line-height:125%"
+ x="105.32364"
+ y="-810.65997"
+ id="text3187"
+ transform="matrix(0,1,-1,0,0,0)"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ id="tspan2408">render_side_boxes()</tspan></text>
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:3.0652349;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3191"
+ width="771.97766"
+ height="55.647793"
+ x="-127.80586"
+ y="642.0293"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="-121.22153"
+ y="674.1748"
+ id="text3181"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ x="-121.22153"
+ y="674.1748"
+ id="tspan3183">navcontentbottom</tspan></text>
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.68198514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3881"
+ width="986.90503"
+ height="45.800392"
+ x="-128.34428"
+ y="-31.574066"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="355.60541"
+ y="-2.7424495"
+ id="text3883"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ x="355.60541"
+ y="-2.7424495"
+ id="tspan3885">render_entity_toolbox(), render_entity_title()</tspan></text>
+ <rect
+ style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1.68198514;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3890"
+ width="986.90503"
+ height="45.800392"
+ x="-128.87863"
+ y="19.723684"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449" />
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="565.71027"
+ y="50.135612"
+ id="text3892"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ x="565.71027"
+ y="50.135612"
+ id="tspan3894">render_entity_summary()</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="87.154541"
+ y="114.2578"
+ id="text3899"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ id="tspan3903"
+ x="87.154541"
+ y="114.2578">content_navigation_components('navcontenttop')</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans"
+ x="88.46772"
+ y="675.71582"
+ id="text2410"
+ sodipodi:linespacing="125%"
+ inkscape:export-filename="/home/auc/src/fcw/cubicweb/doc/book/en/images/primaryview_template.png"
+ inkscape:export-xdpi="60.912449"
+ inkscape:export-ydpi="60.912449"><tspan
+ sodipodi:role="line"
+ id="tspan2412"
+ x="88.46772"
+ y="675.71582">content_navigation_components('navcontenttop')</tspan></text>
+ </g>
+</svg>
Binary file doc/images/request_session.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/images/request_session.svg Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="85.960938"
+ height="12.382812"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="request_session.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Arrow1Lend"
+ style="overflow:visible;">
+ <path
+ id="path3822"
+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
+ transform="scale(0.8) rotate(180) translate(12.5,0)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="25.928992"
+ inkscape:cy="-185.87004"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="958"
+ inkscape:window-height="1160"
+ inkscape:window-x="0"
+ inkscape:window-y="38"
+ inkscape:window-maximized="0"
+ inkscape:snap-global="true" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-263.52249,-495.73373)">
+ <rect
+ style="fill:#ffffff;stroke:#000000;stroke-width:0.92460138;stroke-opacity:1"
+ id="rect3773"
+ width="214.15233"
+ height="184.80336"
+ x="57.578697"
+ y="366.01306" />
+ <rect
+ id="rect2985"
+ width="216.86372"
+ height="183.54575"
+ x="348.50262"
+ y="367.78079"
+ style="fill:#ffffff;stroke:#000000;stroke-width:0.55298227;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="376.7869"
+ y="399.80365"
+ id="text3755"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3757"
+ x="376.7869"
+ y="399.80365">Repository</tspan></text>
+ <rect
+ style="fill:#ffffff;stroke:#000000;stroke-opacity:1"
+ id="rect3759"
+ width="144.45181"
+ height="104.04572"
+ x="237.38585"
+ y="423.03714" />
+ <text
+ xml:space="preserve"
+ style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="262.63968"
+ y="470.51431"
+ id="text3761"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3763"
+ x="262.63968"
+ y="470.51431">REPOAPI</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="262.63968"
+ y="507.88998"
+ id="text3765"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3767"
+ x="262.63968"
+ y="507.88998">connection</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="419.21332"
+ y="509.91025"
+ id="text3769"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3771"
+ x="419.21332"
+ y="509.91025">session</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:32px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="102.02541"
+ y="397.78333"
+ id="text3775"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3777"
+ x="102.02541"
+ y="397.78333">Client</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="116.16754"
+ y="507.88995"
+ id="text3779"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3781"
+ x="116.16754"
+ y="507.88995">request</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:16px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="361.50729"
+ y="585.89832"
+ id="text3802"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3804"
+ x="361.50729"
+ y="585.89832">database </tspan><tspan
+ sodipodi:role="line"
+ x="361.50729"
+ y="605.89832"
+ id="tspan3806">connection</tspan></text>
+ <rect
+ style="fill:#ffffff;stroke:#000000;stroke-width:1.48014534;stroke-opacity:1"
+ id="rect3808"
+ width="192.09367"
+ height="58.095726"
+ x="365.79443"
+ y="621.50018" />
+ <text
+ xml:space="preserve"
+ style="font-size:36px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="369.5885"
+ y="662.66992"
+ id="text3810"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3812"
+ x="369.5885"
+ y="662.66992">Database</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:none"
+ d="M 197.57252,125.76645 195.76971,55.592808"
+ id="path4260"
+ inkscape:connector-type="polyline"
+ inkscape:connector-curvature="3"
+ inkscape:connection-start="#rect3808"
+ inkscape:connection-start-point="d4"
+ inkscape:connection-end="#rect2985"
+ inkscape:connection-end-point="d4"
+ transform="translate(263.52249,495.73373)" />
+ </g>
+</svg>
Binary file doc/images/server-class-diagram.png has changed
Binary file doc/images/tutos-base_blog-form_en.png has changed
Binary file doc/images/tutos-base_blog-primary-after-post-creation_en.png has changed
Binary file doc/images/tutos-base_blog-primary_en.png has changed
Binary file doc/images/tutos-base_blogs-list_en.png has changed
Binary file doc/images/tutos-base_form-generic-relations_en.png has changed
Binary file doc/images/tutos-base_index_en.png has changed
Binary file doc/images/tutos-base_login-form_en.png has changed
Binary file doc/images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png has changed
Binary file doc/images/tutos-base_myblog-community-custom-primary_en.png has changed
Binary file doc/images/tutos-base_myblog-community-default-primary_en.png has changed
Binary file doc/images/tutos-base_myblog-community-taggable-primary_en.png has changed
Binary file doc/images/tutos-base_myblog-custom-footer_en.png has changed
Binary file doc/images/tutos-base_myblog-schema_en.png has changed
Binary file doc/images/tutos-base_myblog-siteinfo_en.png has changed
Binary file doc/images/tutos-base_schema_en.png has changed
Binary file doc/images/tutos-base_siteconfig_en.png has changed
Binary file doc/images/tutos-base_user-menu_en.png has changed
Binary file doc/images/tutos-photowebsite_background-image.png has changed
Binary file doc/images/tutos-photowebsite_boxes.png has changed
Binary file doc/images/tutos-photowebsite_breadcrumbs.png has changed
Binary file doc/images/tutos-photowebsite_facets.png has changed
Binary file doc/images/tutos-photowebsite_grey-box.png has changed
Binary file doc/images/tutos-photowebsite_index-after.png has changed
Binary file doc/images/tutos-photowebsite_index-before.png has changed
Binary file doc/images/tutos-photowebsite_login-box.png has changed
Binary file doc/images/tutos-photowebsite_prevnext.png has changed
Binary file doc/images/tutos-photowebsite_ui1.png has changed
Binary file doc/images/tutos-photowebsite_ui2.png has changed
Binary file doc/images/tutos-photowebsite_ui3.png has changed
Binary file doc/images/undo_history-view_w600.png has changed
Binary file doc/images/undo_mesage_w600.png has changed
Binary file doc/images/undo_startup-link_w600.png has changed
Binary file doc/images/views-table-filter-shadow.png has changed
Binary file doc/images/views-table-filter.png has changed
Binary file doc/images/views-table-shadow.png has changed
Binary file doc/images/views-table.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,111 @@
+=====================================================
+|cubicweb| - The Semantic Web is a construction game!
+=====================================================
+
+|cubicweb| is a semantic web application framework, licensed under the LGPL,
+that empowers developers to efficiently build web applications by reusing
+components (called `cubes`) and following the well known object-oriented design
+principles.
+
+Main Features
+~~~~~~~~~~~~~
+
+* an engine driven by the explicit :ref:`data model
+ <TutosBaseCustomizingTheApplicationDataModel>` of the application,
+
+* a query language named :ref:`RQL <RQL>` similar to W3C's SPARQL,
+
+* a :ref:`selection+view <TutosBaseCustomizingTheApplicationCustomViews>`
+ mechanism for semi-automatic XHTML/XML/JSON/text generation,
+
+* a library of reusable :ref:`components <Cube>` (data model and views) that
+ fulfill common needs,
+
+* the power and flexibility of the Python_ programming language,
+
+* the reliability of SQL databases, LDAP directories, Subversion and Mercurial
+ for storage backends.
+
+Built since 2000 from an R&D effort still continued, supporting 100,000s of
+daily visits at some production sites, |cubicweb| is a proven end to end solution
+for semantic web application development that promotes quality, reusability and
+efficiency.
+
+QuickStart
+~~~~~~~~~~
+
+The impatient developer will move right away to :ref:`SetUpEnv` then to :ref:`ConfigEnv`.
+
+Social
+~~~~~~
+
+* Chat on the `jabber forum`_
+* Discuss on the `mailing-list`_
+* Discover on the `blog`_
+* Contribute on the forge_
+
+
+.. _Logilab: http://www.logilab.fr/
+.. _forge: http://www.cubicweb.org/project/
+.. _Python: http://www.python.org/
+.. _`jabber forum`: http://www.logilab.org/blogentry/6718
+.. _`mailing-list`: http://lists.cubicweb.org/mailman/listinfo/cubicweb
+.. _blog: http://www.cubicweb.org/blog/1238
+
+
+Narrative Documentation
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A.k.a. "The Book"
+
+.. toctree::
+ :maxdepth: 2
+
+ book/intro/index
+
+.. toctree::
+ :maxdepth: 3
+
+ book/devrepo/index
+ book/devweb/index
+
+.. toctree::
+ :maxdepth: 2
+
+ book/admin/index
+ book/additionnal_services/index
+ book/annexes/index
+
+Tutorial
+~~~~~~~~
+
+We present two tutorials of different levels. The blog building
+tutorial introduces one smoothly to the basic concepts.
+
+Then there is a photo gallery construction tutorial which highlights
+more advanced concepts such as unit tests, security settings,
+migration scripts.
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ tutorials/base/index
+ tutorials/advanced/index
+ tutorials/tools/windmill.rst
+ tutorials/textreports/index
+
+
+Reference documentation
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. toctree::
+ :maxdepth: 1
+
+ js_api/index
+
+Indexes
+~~~~~~~
+
+* the :ref:`genindex`,
+* the :ref:`modindex`,
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tools/mode_plan.py Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,50 @@
+# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+"""
+>>> from mode_plan import *
+>>> ls()
+<list of directory content>
+>>> ren('A01','A03')
+rename A010-joe.en.txt to A030-joe.en.txt
+accept [y/N]?
+"""
+
+def ren(a,b):
+ names = glob.glob('%s*'%a)
+ for name in names :
+ print 'rename %s to %s' % (name, name.replace(a,b))
+ if raw_input('accept [y/N]?').lower() =='y':
+ for name in names:
+ os.system('hg mv %s %s' % (name, name.replace(a,b)))
+
+
+def ls(): print '\n'.join(sorted(os.listdir('.')))
+
+def move():
+ filenames = []
+ for name in sorted(os.listdir('.')):
+ num = name[:2]
+ if num.isdigit():
+ filenames.append( (int(num), name) )
+
+
+ #print filenames
+
+ for num, name in filenames:
+ if num >= start:
+ print 'hg mv %s %2i%s' %(name,num+1,name[2:])
--- a/doc/tools/pyjsrest.py Mon Jul 06 17:39:35 2015 +0200
+++ b/doc/tools/pyjsrest.py Thu Jan 08 22:11:06 2015 +0100
@@ -92,6 +92,9 @@
f_rst.write(rst_content)
stream = open(osp.join(rst_dir, 'index.rst'), 'w')
stream.write('''
+Javascript API
+==============
+
.. toctree::
:maxdepth: 1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,29 @@
+
+.. _TutosPhotoWebSite:
+
+Building a photo gallery with |cubicweb|
+========================================
+
+Desired features
+----------------
+
+* basically a photo gallery
+
+* photo stored on the file system and displayed dynamically through a web interface
+
+* navigation through folder (album), tags, geographical zone, people on the
+ picture... using facets
+
+* advanced security (not everyone can see everything). More on this later.
+
+
+.. toctree::
+ :maxdepth: 2
+
+ part01_create-cube
+ part02_security
+ part03_bfss
+ part04_ui-base
+ part05_ui-advanced
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/part01_create-cube.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,155 @@
+.. _TutosPhotoWebSiteCubeCreation:
+
+Cube creation and schema definition
+-----------------------------------
+
+.. _adv_tuto_create_new_cube:
+
+Step 1: creating a new cube for my web site
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One note about my development environment: I wanted to use the packaged
+version of CubicWeb and cubes while keeping my cube in my user
+directory, let's say `~src/cubes`. I achieve this by setting the
+following environment variables::
+
+ CW_CUBES_PATH=~/src/cubes
+ CW_MODE=user
+
+I can now create the cube which will hold custom code for this web
+site using::
+
+ cubicweb-ctl newcube --directory=~/src/cubes sytweb
+
+
+.. _adv_tuto_assemble_cubes:
+
+Step 2: pick building blocks into existing cubes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Almost everything I want to handle in my web-site is somehow already modelized in
+existing cubes that I'll extend for my need. So I'll pick the following cubes:
+
+* `folder`, containing the `Folder` entity type, which will be used as
+ both 'album' and a way to map file system folders. Entities are
+ added to a given folder using the `filed_under` relation.
+
+* `file`, containing `File` entity type, gallery view, and a file system import
+ utility.
+
+* `zone`, containing the `Zone` entity type for hierarchical geographical
+ zones. Entities (including sub-zones) are added to a given zone using the
+ `situated_in` relation.
+
+* `person`, containing the `Person` entity type plus some basic views.
+
+* `comment`, providing a full commenting system allowing one to comment entity types
+ supporting the `comments` relation by adding a `Comment` entity.
+
+* `tag`, providing a full tagging system as an easy and powerful way to classify
+ entities supporting the `tags` relation by linking the to `Tag` entities. This
+ will allows navigation into a large number of picture.
+
+Ok, now I'll tell my cube requires all this by editing :file:`cubes/sytweb/__pkginfo__.py`:
+
+ .. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.10.0',
+ 'cubicweb-file': '>= 1.9.0',
+ 'cubicweb-folder': '>= 1.1.0',
+ 'cubicweb-person': '>= 1.2.0',
+ 'cubicweb-comment': '>= 1.2.0',
+ 'cubicweb-tag': '>= 1.2.0',
+ 'cubicweb-zone': None}
+
+Notice that you can express minimal version of the cube that should be used,
+`None` meaning whatever version available. All packages starting with 'cubicweb-'
+will be recognized as being cube, not bare python packages. You can still specify
+this explicitly using instead the `__depends_cubes__` dictionary which should
+contains cube's name without the prefix. So the example below would be written
+as:
+
+ .. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.10.0'}
+ __depends_cubes__ = {'file': '>= 1.9.0',
+ 'folder': '>= 1.1.0',
+ 'person': '>= 1.2.0',
+ 'comment': '>= 1.2.0',
+ 'tag': '>= 1.2.0',
+ 'zone': None}
+
+If your cube is packaged for debian, it's a good idea to update the
+`debian/control` file at the same time, so you won't forget it.
+
+
+Step 3: glue everything together in my cube's schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. sourcecode:: python
+
+ from yams.buildobjs import RelationDefinition
+
+ class comments(RelationDefinition):
+ subject = 'Comment'
+ object = 'File'
+ cardinality = '1*'
+ composite = 'object'
+
+ class tags(RelationDefinition):
+ subject = 'Tag'
+ object = 'File'
+
+ class filed_under(RelationDefinition):
+ subject = 'File'
+ object = 'Folder'
+
+ class situated_in(RelationDefinition):
+ subject = 'File'
+ object = 'Zone'
+
+ class displayed_on(RelationDefinition):
+ subject = 'Person'
+ object = 'File'
+
+
+This schema:
+
+* allows to comment and tag on `File` entity type by adding the `comments` and
+ `tags` relations. This should be all we've to do for this feature since the
+ related cubes provide 'pluggable section' which are automatically displayed on
+ the primary view of entity types supporting the relation.
+
+* adds a `situated_in` relation definition so that image entities can be
+ geolocalized.
+
+* add a new relation `displayed_on` relation telling who can be seen on a
+ picture.
+
+This schema will probably have to evolve as time goes (for security handling at
+least), but since the possibility to let a schema evolve is one of CubicWeb's
+features (and goals), we won't worry about it for now and see that later when needed.
+
+
+Step 4: creating the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now that I have a schema, I want to create an instance. To
+do so using this new 'sytweb' cube, I run::
+
+ cubicweb-ctl create sytweb sytweb_instance
+
+Hint: if you get an error while the database is initialized, you can
+avoid having to answer the questions again by running::
+
+ cubicweb-ctl db-create sytweb_instance
+
+This will use your already configured instance and start directly from the create
+database step, thus skipping questions asked by the 'create' command.
+
+Once the instance and database are fully initialized, run ::
+
+ cubicweb-ctl start sytweb_instance
+
+to start the instance, check you can connect on it, etc...
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/part02_security.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,440 @@
+.. _TutosPhotoWebSiteSecurity:
+
+Security, testing and migration
+-------------------------------
+
+This part will cover various topics:
+
+* configuring security
+* migrating existing instance
+* writing some unit tests
+
+Here is the ``read`` security model I want:
+
+* folders, files, images and comments should have one of the following visibility:
+
+ - ``public``, everyone can see it
+ - ``authenticated``, only authenticated users can see it
+ - ``restricted``, only a subset of authenticated users can see it
+
+* managers (e.g. me) can see everything
+* only authenticated users can see people
+* everyone can see classifier entities, such as tag and zone
+
+Also, unless explicitly specified, the visibility of an image should be the same as
+its parent folder, as well as visibility of a comment should be the same as the
+commented entity. If there is no parent entity, the default visibility is
+``authenticated``.
+
+Regarding write security, that's much easier:
+* anonymous can't write anything
+* authenticated users can only add comment
+* managers will add the remaining stuff
+
+Now, let's implement that!
+
+Proper security in CubicWeb is done at the schema level, so you don't have to
+bother with it in views: users will only see what they can see automatically.
+
+.. _adv_tuto_security:
+
+Step 1: configuring security into the schema
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In schema, you can grant access according to groups, or to some RQL expressions:
+users get access if the expression returns some results. To implement the read
+security defined earlier, groups are not enough, we'll need some RQL expression. Here
+is the idea:
+
+* add a `visibility` attribute on Folder, File and Comment, which may be one of
+ the value explained above
+
+* add a `may_be_read_by` relation from Folder, File and Comment to users,
+ which will define who can see the entity
+
+* security propagation will be done in hook.
+
+So the first thing to do is to modify my cube's schema.py to define those
+relations:
+
+.. sourcecode:: python
+
+ from yams.constraints import StaticVocabularyConstraint
+
+ class visibility(RelationDefinition):
+ subject = ('Folder', 'File', 'Comment')
+ object = 'String'
+ constraints = [StaticVocabularyConstraint(('public', 'authenticated',
+ 'restricted', 'parent'))]
+ default = 'parent'
+ cardinality = '11' # required
+
+ class may_be_read_by(RelationDefinition):
+ __permissions__ = {
+ 'read': ('managers', 'users'),
+ 'add': ('managers',),
+ 'delete': ('managers',),
+ }
+
+ subject = ('Folder', 'File', 'Comment',)
+ object = 'CWUser'
+
+We can note the following points:
+
+* we've added a new `visibility` attribute to folder, file, image and comment
+ using a `RelationDefinition`
+
+* `cardinality = '11'` means this attribute is required. This is usually hidden
+ under the `required` argument given to the `String` constructor, but we can
+ rely on this here (same thing for StaticVocabularyConstraint, which is usually
+ hidden by the `vocabulary` argument)
+
+* the `parent` possible value will be used for visibility propagation
+
+* think to secure the `may_be_read_by` permissions, else any user can add/delete it
+ by default, which somewhat breaks our security model...
+
+Now, we should be able to define security rules in the schema, based on these new
+attribute and relation. Here is the code to add to *schema.py*:
+
+.. sourcecode:: python
+
+ from cubicweb.schema import ERQLExpression
+
+ VISIBILITY_PERMISSIONS = {
+ 'read': ('managers',
+ ERQLExpression('X visibility "public"'),
+ ERQLExpression('X may_be_read_by U')),
+ 'add': ('managers',),
+ 'update': ('managers', 'owners',),
+ 'delete': ('managers', 'owners'),
+ }
+ AUTH_ONLY_PERMISSIONS = {
+ 'read': ('managers', 'users'),
+ 'add': ('managers',),
+ 'update': ('managers', 'owners',),
+ 'delete': ('managers', 'owners'),
+ }
+ CLASSIFIERS_PERMISSIONS = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers',),
+ 'update': ('managers', 'owners',),
+ 'delete': ('managers', 'owners'),
+ }
+
+ from cubes.folder.schema import Folder
+ from cubes.file.schema import File
+ from cubes.comment.schema import Comment
+ from cubes.person.schema import Person
+ from cubes.zone.schema import Zone
+ from cubes.tag.schema import Tag
+
+ Folder.__permissions__ = VISIBILITY_PERMISSIONS
+ File.__permissions__ = VISIBILITY_PERMISSIONS
+ Comment.__permissions__ = VISIBILITY_PERMISSIONS.copy()
+ Comment.__permissions__['add'] = ('managers', 'users',)
+ Person.__permissions__ = AUTH_ONLY_PERMISSIONS
+ Zone.__permissions__ = CLASSIFIERS_PERMISSIONS
+ Tag.__permissions__ = CLASSIFIERS_PERMISSIONS
+
+What's important in there:
+
+* `VISIBILITY_PERMISSIONS` provides read access to managers group, if
+ `visibility` attribute's value is 'public', or if user (designed by the 'U'
+ variable in the expression) is linked to the entity (the 'X' variable) through
+ the `may_be_read_by` permission
+
+* we modify permissions of the entity types we use by importing them and
+ modifying their `__permissions__` attribute
+
+* notice the `.copy()`: we only want to modify 'add' permission for `Comment`,
+ not for all entity types using `VISIBILITY_PERMISSIONS`!
+
+* the remaining part of the security model is done using regular groups:
+
+ - `users` is the group to which all authenticated users will belong
+ - `guests` is the group of anonymous users
+
+
+.. _adv_tuto_security_propagation:
+
+Step 2: security propagation in hooks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To fullfill the requirements, we have to implement::
+
+ Also, unless explicity specified, visibility of an image should be the same as
+ its parent folder, as well as visibility of a comment should be the same as the
+ commented entity.
+
+This kind of `active` rule will be done using CubicWeb's hook
+system. Hooks are triggered on database events such as addition of a new
+entity or relation.
+
+The tricky part of the requirement is in *unless explicitly specified*, notably
+because when the entity is added, we don't know yet its 'parent'
+entity (e.g. Folder of an File, File commented by a Comment). To handle such things,
+CubicWeb provides `Operation`, which allow to schedule things to do at commit time.
+
+In our case we will:
+
+* on entity creation, schedule an operation that will set default visibility
+
+* when a "parent" relation is added, propagate parent's visibility unless the
+ child already has a visibility set
+
+Here is the code in cube's *hooks.py*:
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import is_instance
+ from cubicweb.server import hook
+
+ class SetVisibilityOp(hook.DataOperationMixIn, hook.Operation):
+
+ def precommit_event(self):
+ for eid in self.get_data():
+ entity = self.session.entity_from_eid(eid)
+ if entity.visibility == 'parent':
+ entity.cw_set(visibility=u'authenticated')
+
+ class SetVisibilityHook(hook.Hook):
+ __regid__ = 'sytweb.setvisibility'
+ __select__ = hook.Hook.__select__ & is_instance('Folder', 'File', 'Comment')
+ events = ('after_add_entity',)
+
+ def __call__(self):
+ SetVisibilityOp.get_instance(self._cw).add_data(self.entity.eid)
+
+ class SetParentVisibilityHook(hook.Hook):
+ __regid__ = 'sytweb.setparentvisibility'
+ __select__ = hook.Hook.__select__ & hook.match_rtype('filed_under', 'comments')
+ events = ('after_add_relation',)
+
+ def __call__(self):
+ parent = self._cw.entity_from_eid(self.eidto)
+ child = self._cw.entity_from_eid(self.eidfrom)
+ if child.visibility == 'parent':
+ child.cw_set(visibility=parent.visibility)
+
+Notice:
+
+* hooks are application objects, hence have selectors that should match entity or
+ relation types to which the hook applies. To match a relation type, we use the
+ hook specific `match_rtype` selector.
+
+* usage of `DataOperationMixIn`: instead of adding an operation for each added entity,
+ DataOperationMixIn allows to create a single one and to store entity's eids to be
+ processed in the transaction data. This is a good pratice to avoid heavy
+ operations manipulation cost when creating a lot of entities in the same
+ transaction.
+
+* the `precommit_event` method of the operation will be called at transaction's
+ commit time.
+
+* in a hook, `self._cw` is the repository session, not a web request as usually
+ in views
+
+* according to hook's event, you have access to different attributes on the hook
+ instance. Here:
+
+ - `self.entity` is the newly added entity on 'after_add_entity' events
+
+ - `self.eidfrom` / `self.eidto` are the eid of the subject / object entity on
+ 'after_add_relation' events (you may also get the relation type using
+ `self.rtype`)
+
+The `parent` visibility value is used to tell "propagate using parent security"
+because we want that attribute to be required, so we can't use None value else
+we'll get an error before we get any chance to propagate...
+
+Now, we also want to propagate the `may_be_read_by` relation. Fortunately,
+CubicWeb provides some base hook classes for such things, so we only have to add
+the following code to *hooks.py*:
+
+.. sourcecode:: python
+
+ # relations where the "parent" entity is the subject
+ S_RELS = set()
+ # relations where the "parent" entity is the object
+ O_RELS = set(('filed_under', 'comments',))
+
+ class AddEntitySecurityPropagationHook(hook.PropagateRelationHook):
+ """propagate permissions when new entity are added"""
+ __regid__ = 'sytweb.addentity_security_propagation'
+ __select__ = (hook.PropagateRelationHook.__select__
+ & hook.match_rtype_sets(S_RELS, O_RELS))
+ main_rtype = 'may_be_read_by'
+ subject_relations = S_RELS
+ object_relations = O_RELS
+
+ class AddPermissionSecurityPropagationHook(hook.PropagateRelationAddHook):
+ """propagate permissions when new entity are added"""
+ __regid__ = 'sytweb.addperm_security_propagation'
+ __select__ = (hook.PropagateRelationAddHook.__select__
+ & hook.match_rtype('may_be_read_by',))
+ subject_relations = S_RELS
+ object_relations = O_RELS
+
+ class DelPermissionSecurityPropagationHook(hook.PropagateRelationDelHook):
+ __regid__ = 'sytweb.delperm_security_propagation'
+ __select__ = (hook.PropagateRelationDelHook.__select__
+ & hook.match_rtype('may_be_read_by',))
+ subject_relations = S_RELS
+ object_relations = O_RELS
+
+* the `AddEntitySecurityPropagationHook` will propagate the relation
+ when `filed_under` or `comments` relations are added
+
+ - the `S_RELS` and `O_RELS` set as well as the `match_rtype_sets` selector are
+ used here so that if my cube is used by another one, it'll be able to
+ configure security propagation by simply adding relation to one of the two
+ sets.
+
+* the two others will propagate permissions changes on parent entities to
+ children entities
+
+
+.. _adv_tuto_tesing_security:
+
+Step 3: testing our security
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Security is tricky. Writing some tests for it is a very good idea. You should
+even write them first, as Test Driven Development recommends!
+
+Here is a small test case that will check the basis of our security
+model, in *test/unittest_sytweb.py*:
+
+.. sourcecode:: python
+
+ from cubicweb.devtools.testlib import CubicWebTC
+ from cubicweb import Binary
+
+ class SecurityTC(CubicWebTC):
+
+ def test_visibility_propagation(self):
+ with self.admin_access.repo_cnx() as cnx:
+ # create a user for later security checks
+ toto = self.create_user(cnx, 'toto')
+ cnx.commit()
+ # init some data using the default manager connection
+ folder = cnx.create_entity('Folder',
+ name=u'restricted',
+ visibility=u'restricted')
+ photo1 = cnx.create_entity('File',
+ data_name=u'photo1.jpg',
+ data=Binary('xxx'),
+ filed_under=folder)
+ cnx.commit()
+ # visibility propagation
+ self.assertEquals(photo1.visibility, 'restricted')
+ # unless explicitly specified
+ photo2 = cnx.create_entity('File',
+ data_name=u'photo2.jpg',
+ data=Binary('xxx'),
+ visibility=u'public',
+ filed_under=folder)
+ cnx.commit()
+ self.assertEquals(photo2.visibility, 'public')
+ with self.new_access('toto').repo_cnx() as cnx:
+ # test security
+ self.assertEqual(1, len(cnx.execute('File X'))) # only the public one
+ self.assertEqual(0, len(cnx.execute('Folder X'))) # restricted...
+ with self.admin_access.repo_cnx() as cnx:
+ # may_be_read_by propagation
+ folder = cnx.entity_from_eid(folder.eid)
+ folder.cw_set(may_be_read_by=toto)
+ cnx.commit()
+ with self.new_access('toto').repo_cnx() as cnx:
+ photo1 = cnx.entity_from_eid(photo1.eid)
+ self.failUnless(photo1.may_be_read_by)
+ # test security with permissions
+ self.assertEquals(2, len(cnx.execute('File X'))) # now toto has access to photo2
+ self.assertEquals(1, len(cnx.execute('Folder X'))) # and to restricted folder
+
+ if __name__ == '__main__':
+ from logilab.common.testlib import unittest_main
+ unittest_main()
+
+It's not complete, but shows most things you'll want to do in tests: adding some
+content, creating users and connecting as them in the test, etc...
+
+To run it type:
+
+.. sourcecode:: bash
+
+ $ pytest unittest_sytweb.py
+ ======================== unittest_sytweb.py ========================
+ -> creating tables [....................]
+ -> inserting default user and default groups.
+ -> storing the schema in the database [....................]
+ -> database for instance data initialized.
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 22.547s
+
+ OK
+
+
+The first execution is taking time, since it creates a sqlite database for the
+test instance. The second one will be much quicker:
+
+.. sourcecode:: bash
+
+ $ pytest unittest_sytweb.py
+ ======================== unittest_sytweb.py ========================
+ .
+ ----------------------------------------------------------------------
+ Ran 1 test in 2.662s
+
+ OK
+
+If you do some changes in your schema, you'll have to force regeneration of that
+database. You do that by removing the tmpdb files before running the test: ::
+
+ $ rm data/database/tmpdb*
+
+
+.. Note::
+ pytest is a very convenient utility used to control test execution. It is available from the `logilab-common`_ package.
+
+.. _`logilab-common`: http://www.logilab.org/project/logilab-common
+
+.. _adv_tuto_migration_script:
+
+Step 4: writing the migration script and migrating the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Prior to those changes, I created an instance, fed it with some data, so I
+don't want to create a new one, but to migrate the existing one. Let's see how to
+do that.
+
+Migration commands should be put in the cube's *migration* directory, in a
+file named file:`<X.Y.Z>_Any.py` ('Any' being there mostly for historical reasons).
+
+Here I'll create a *migration/0.2.0_Any.py* file containing the following
+instructions:
+
+.. sourcecode:: python
+
+ add_relation_type('may_be_read_by')
+ add_relation_type('visibility')
+ sync_schema_props_perms()
+
+Then I update the version number in the cube's *__pkginfo__.py* to 0.2.0. And
+that's it! Those instructions will:
+
+* update the instance's schema by adding our two new relations and update the
+ underlying database tables accordingly (the first two instructions)
+
+* update schema's permissions definition (the last instruction)
+
+
+To migrate my instance I simply type::
+
+ cubicweb-ctl upgrade sytweb_instance
+
+You'll then be asked some questions to do the migration step by step. You should say
+YES when it asks if a backup of your database should be done, so you can get back
+to initial state if anything goes wrong...
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/part03_bfss.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,131 @@
+Storing images on the file-system
+---------------------------------
+
+Step 1: configuring the BytesFileSystem storage
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To avoid cluttering my database, and to ease file manipulation, I don't want them
+to be stored in the database. I want to be able create File entities for some
+files on the server file system, where those file will be accessed to get
+entities data. To do so I've to set a custom :class:`BytesFileSystemStorage`
+storage for the File 'data' attribute, which hold the actual file's content.
+
+Since the function to register a custom storage needs to have a repository
+instance as first argument, we've to call it in a server startup hook. So I added
+in `cubes/sytweb/hooks.py` :
+
+.. sourcecode:: python
+
+ from os import makedirs
+ from os.path import join, exists
+
+ from cubicweb.server import hook
+ from cubicweb.server.sources import storages
+
+ class ServerStartupHook(hook.Hook):
+ __regid__ = 'sytweb.serverstartup'
+ events = ('server_startup', 'server_maintenance')
+
+ def __call__(self):
+ bfssdir = join(self.repo.config.appdatahome, 'bfss')
+ if not exists(bfssdir):
+ makedirs(bfssdir)
+ print 'created', bfssdir
+ storage = storages.BytesFileSystemStorage(bfssdir)
+ storages.set_attribute_storage(self.repo, 'File', 'data', storage)
+
+.. Note::
+
+ * how we built the hook's registry identifier (`__regid__`): you can introduce
+ 'namespaces' by using there python module like naming identifiers. This is
+ especially important for hooks where you usually want a new custom hook, not
+ overriding / specializing an existant one, but the concept may be applied to
+ any application objects
+
+ * we catch two events here: "server_startup" and "server_maintenance". The first
+ is called on regular repository startup (eg, as a server), the other for
+ maintenance task such as shell or upgrade. In both cases, we need to have
+ the storage set, else we'll be in trouble...
+
+ * the path given to the storage is the place where file added through the ui
+ (or in the database before migration) will be located
+
+ * beware that by doing this, you can't anymore write queries that will try to
+ restrict on File `data` attribute. Hopefuly we don't do that usually
+ on file's content or more generally on attributes for the Bytes type
+
+Now, if you've already added some photos through the web ui, you'll have to
+migrate existing data so file's content will be stored on the file-system instead
+of the database. There is a migration command to do so, let's run it in the
+cubicweb shell (in real life, you would have to put it in a migration script as we
+have seen last time):
+
+::
+
+ $ cubicweb-ctl shell sytweb_instance
+ entering the migration python shell
+ just type migration commands or arbitrary python code and type ENTER to execute it
+ type "exit" or Ctrl-D to quit the shell and resume operation
+ >>> storage_changed('File', 'data')
+ [........................]
+
+
+That's it. Now, files added through the web ui will have their content stored on
+the file-system, and you'll also be able to import files from the file-system as
+explained in the next part.
+
+Step 2: importing some data into the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Hey, we start to have some nice features, let us give a try to this new web
+site. For instance if I have a 'photos/201005WePyrenees' containing pictures for
+a particular event, I can import it to my web site by typing ::
+
+ $ cubicweb-ctl fsimport -F sytweb_instance photos/201005WePyrenees/
+ ** importing directory /home/syt/photos/201005WePyrenees
+ importing IMG_8314.JPG
+ importing IMG_8274.JPG
+ importing IMG_8286.JPG
+ importing IMG_8308.JPG
+ importing IMG_8304.JPG
+
+.. Note::
+ The -F option means that folders should be mapped, hence my photos will be
+ linked to a Folder entity corresponding to the file-system folder.
+
+Let's take a look at the web ui:
+
+.. image:: ../../images/tutos-photowebsite_ui1.png
+
+Nothing different, I can't see the new folder... But remember our security model!
+By default, files are only accessible to authenticated users, and I'm looking at
+the site as anonymous, e.g. not authenticated. If I login, I can now see:
+
+.. image:: ../../images/tutos-photowebsite_ui2.png
+
+Yeah, it's there! You will notice that I can see some entities as well as
+folders and images the anonymous user can't. It just works **everywhere in the
+ui** since it's handled at the repository level, thanks to our security model.
+
+Now if I click on the recently inserted folder, I can see
+
+.. image:: ../../images/tutos-photowebsite_ui3.png
+
+Great! There is even my pictures in the folder. I can know give to this folder a
+nicer name (provided I don't intend to import from it anymore, else already
+imported photos will be reimported), change permissions, title for some pictures,
+etc... Having a good content is much more difficult than having a good web site
+;)
+
+
+Conclusion
+~~~~~~~~~~
+
+We started to see here an advanced feature of our repository: the ability
+to store some parts of our data-model into a custom storage, outside the
+database. There is currently only the :class:`BytesFileSystemStorage` available,
+but you can expect to see more coming in a near future (or write your own!).
+
+Also, we can know start to feed our web-site with some nice pictures!
+The site isn't perfect (far from it actually) but it's usable, and we can
+now start using it and improve it on the way. The Incremental Cubic Way :)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/part04_ui-base.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,361 @@
+Let's make it more user friendly
+================================
+
+
+Step 1: let's improve site's usability for our visitors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first thing I've noticed is that people to whom I send links to photos with
+some login/password authentication get lost, because they don't grasp they have
+to login by clicking on the 'authenticate' link. That's much probably because
+they only get a 404 when trying to access an unauthorized folder, and the site
+doesn't make clear that 1. you're not authenticated, 2. you could get more
+content by authenticating yourself.
+
+So, to improve this situation, I decided that I should:
+
+* make a login box appears for anonymous, so they see at a first glance a place
+ to put the login / password information I provided
+
+* customize the 404 page, proposing to login to anonymous.
+
+Here is the code, samples from my cube's `views.py` file:
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import is_instance
+ from cubicweb.web import component
+ from cubicweb.web.views import error
+ from cubicweb.predicates import anonymous_user
+
+ class FourOhFour(error.FourOhFour):
+ __select__ = error.FourOhFour.__select__ & anonymous_user()
+
+ def call(self):
+ self.w(u"<h1>%s</h1>" % self._cw._('this resource does not exist'))
+ self.w(u"<p>%s</p>" % self._cw._('have you tried to login?'))
+
+
+ class LoginBox(component.CtxComponent):
+ """display a box containing links to all startup views"""
+ __regid__ = 'sytweb.loginbox'
+ __select__ = component.CtxComponent.__select__ & anonymous_user()
+
+ title = _('Authenticate yourself')
+ order = 70
+
+ def render_body(self, w):
+ cw = self._cw
+ form = cw.vreg['forms'].select('logform', cw)
+ form.render(w=w, table_class='', display_progress_div=False)
+
+The first class provides a new specific implementation of the default page you
+get on 404 error, to display an adapted message to anonymous user.
+
+.. Note::
+
+ Thanks to the selection mecanism, it will be selected for anoymous user,
+ since the additional `anonymous_user()` selector gives it a higher score than
+ the default, and not for authenticated since this selector will return 0 in
+ such case (hence the object won't be selectable)
+
+The second class defines a simple box, that will be displayed by default with
+boxes in the left column, thanks to default :class:`component.CtxComponent`
+selector. The HTML is written to match default CubicWeb boxes style. The code
+fetch the actual login form and render it.
+
+
+.. figure:: ../../images/tutos-photowebsite_login-box.png
+ :alt: login box / 404 screenshot
+
+ The login box and the custom 404 page for an anonymous visitor (translated in french)
+
+
+Step 2: providing a custom index page
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Another thing we can easily do to improve the site is... A nicer index page
+(e.g. the first page you get when accessing the web site)! The default one is
+quite intimidating (that should change in a near future). I will provide a much
+simpler index page that simply list available folders (e.g. photo albums in that
+site).
+
+.. sourcecode:: python
+
+ from cubicweb.web.views import startup
+
+ class IndexView(startup.IndexView):
+ def call(self, **kwargs):
+ self.w(u'<div>\n')
+ if self._cw.cnx.anonymous_connection:
+ self.w(u'<h4>%s</h4>\n' % self._cw._('Public Albums'))
+ else:
+ self.w(u'<h4>%s</h4>\n' % self._cw._('Albums for %s') % self._cw.user.login)
+ self._cw.vreg['views'].select('tree', self._cw).render(w=self.w)
+ self.w(u'</div>\n')
+
+ def registration_callback(vreg):
+ vreg.register_all(globals().values(), __name__, (IndexView,))
+ vreg.register_and_replace(IndexView, startup.IndexView)
+
+As you can see, we override the default index view found in
+`cubicweb.web.views.startup`, geting back nothing but its identifier and selector
+since we override the top level view's `call` method.
+
+.. Note::
+
+ in that case, we want our index view to **replace** the existing one. To do so
+ we've to implements the `registration_callback` function, in which we tell to
+ register everything in the module *but* our IndexView, then we register it
+ instead of the former index view.
+
+Also, we added a title that tries to make it more evident that the visitor is
+authenticated, or not. Hopefuly people will get it now!
+
+
+.. figure:: ../../images/tutos-photowebsite_index-before.png
+ :alt: default index page screenshot
+
+ The default index page
+
+.. figure:: ../../images/tutos-photowebsite_index-after.png
+ :alt: new index page screenshot
+
+ Our simpler, less intimidating, index page (still translated in french)
+
+
+Step 3: more navigation improvments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are still a few problems I want to solve...
+
+* Images in a folder are displayed in a somewhat random order. I would like to
+ have them ordered by file's name (which will usually, inside a given folder,
+ also result ordering photo by their date and time)
+
+* When clicking a photo from an album view, you've to get back to the gallery
+ view to go to the next photo. This is pretty annoying...
+
+* Also, when viewing an image, there is no clue about the folder to which this
+ image belongs to.
+
+I will first try to explain the ordering problem. By default, when accessing
+related entities by using the ORM's API, you should get them ordered according to
+the target's class `cw_fetch_order`. If we take a look at the file cube'schema,
+we can see:
+
+.. sourcecode:: python
+
+ class File(AnyEntity):
+ """customized class for File entities"""
+ __regid__ = 'File'
+ fetch_attrs, cw_fetch_order = fetch_config(['data_name', 'title'])
+
+
+By default, `fetch_config` will return a `cw_fetch_order` method that will order
+on the first attribute in the list. So, we could expect to get files ordered by
+their name. But we don't. What's up doc ?
+
+The problem is that files are related to folder using the `filed_under` relation.
+And that relation is ambiguous, eg it can lead to `File` entities, but also to
+`Folder` entities. In such case, since both entity types doesn't share the
+attribute on which we want to sort, we'll get linked entities sorted on a common
+attribute (usually `modification_date`).
+
+To fix this, we've to help the ORM. We'll do this in the method from the `ITree`
+folder's adapter, used in the folder's primary view to display the folder's
+content. Here's the code, that I've put in our cube's `entities.py` file, since
+it's more logical stuff than view stuff:
+
+.. sourcecode:: python
+
+ from cubes.folder import entities as folder
+
+ class FolderITreeAdapter(folder.FolderITreeAdapter):
+
+ def different_type_children(self, entities=True):
+ rql = self.entity.cw_related_rql(self.tree_relation,
+ self.parent_role, ('File',))
+ rset = self._cw.execute(rql, {'x': self.entity.eid})
+ if entities:
+ return list(rset.entities())
+ return rset
+
+ def registration_callback(vreg):
+ vreg.register_and_replace(FolderITreeAdapter, folder.FolderITreeAdapter)
+
+As you can see, we simple inherit from the adapter defined in the `folder` cube,
+then we override the `different_type_children` method to give a clue to the ORM's
+`cw_related_rql` method, that is responsible to generate the rql to get entities
+related to the folder by the `filed_under` relation (the value of the
+`tree_relation` attribute). The clue is that we only want to consider the `File`
+target entity type. By doing this, we remove the ambiguity and get back a RQL
+query that correctly order files by their `data_name` attribute.
+
+
+.. Note::
+
+ * As seen earlier, we want to **replace** the folder's `ITree` adapter by our
+ implementation, hence the custom `registration_callback` method.
+
+
+Ouf. That one was tricky...
+
+Now the easier parts. Let's start by adding some links on the file's primary view
+to see the previous / next image in the same folder. CubicWeb's provide a
+component that do exactly that. To make it appears, one have to be adaptable to
+the `IPrevNext` interface. Here is the related code sample, extracted from our
+cube's `views.py` file:
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import is_instance
+ from cubicweb.web.views import navigation
+
+
+ class FileIPrevNextAdapter(navigation.IPrevNextAdapter):
+ __select__ = is_instance('File')
+
+ def previous_entity(self):
+ rset = self._cw.execute('File F ORDERBY FDN DESC LIMIT 1 WHERE '
+ 'X filed_under FOLDER, F filed_under FOLDER, '
+ 'F data_name FDN, X data_name > FDN, X eid %(x)s',
+ {'x': self.entity.eid})
+ if rset:
+ return rset.get_entity(0, 0)
+
+ def next_entity(self):
+ rset = self._cw.execute('File F ORDERBY FDN ASC LIMIT 1 WHERE '
+ 'X filed_under FOLDER, F filed_under FOLDER, '
+ 'F data_name FDN, X data_name < FDN, X eid %(x)s',
+ {'x': self.entity.eid})
+ if rset:
+ return rset.get_entity(0, 0)
+
+
+The `IPrevNext` interface implemented by the adapter simply consist in the
+`previous_entity` / `next_entity` methods, that should respectivly return the
+previous / next entity or `None`. We make an RQL query to get files in the same
+folder, ordered similarly (eg by their `data_name` attribute). We set
+ascendant/descendant ordering and a strict comparison with current file's name
+(the "X" variable representing the current file).
+
+Notice that this query supposes we wont have two files of the same name in the
+same folder, else things may go wrong. Fixing this is out of the scope of this
+blog. And as I would like to have at some point a smarter, context sensitive
+previous/next entity, I'll probably never fix this query (though if I had to, I
+would probably choosing to add a constraint in the schema so that we can't add
+two files of the same name in a folder).
+
+One more thing: by default, the component will be displayed below the content
+zone (the one with the white background). You can change this in the site's
+properties through the ui, but you can also change the default value in the code
+by modifying the `context` attribute of the component:
+
+.. sourcecode:: python
+
+ navigation.NextPrevNavigationComponent.context = 'navcontentbottom'
+
+.. Note::
+
+ `context` may be one of 'navtop', 'navbottom', 'navcontenttop' or
+ 'navcontentbottom'; the first two being outside the main content zone, the two
+ others inside it.
+
+.. figure:: ../../images/tutos-photowebsite_prevnext.png
+ :alt: screenshot of the previous/next entity component
+
+ The previous/next entity component, at the bottom of the main content zone.
+
+Now, the only remaining stuff in my todo list is to see the file's folder. I'll use
+the standard breadcrumb component to do so. Similarly as what we've seen before, this
+component is controled by the :class:`IBreadCrumbs` interface, so we'll have to provide a custom
+adapter for `File` entity, telling the a file's parent entity is its folder:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views import ibreadcrumbs
+
+ class FileIBreadCrumbsAdapter(ibreadcrumbs.IBreadCrumbsAdapter):
+ __select__ = is_instance('File')
+
+ def parent_entity(self):
+ if self.entity.filed_under:
+ return self.entity.filed_under[0]
+
+In that case, we simply use attribute notation provided by the ORM to get the
+folder in which the current file (e.g. `self.entity`) is located.
+
+.. Note::
+
+ The :class:`IBreadCrumbs` interface is a `breadcrumbs` method, but the default
+ :class:`IBreadCrumbsAdapter` provides a default implementation for it that will look
+ at the value returned by its `parent_entity` method. It also provides a
+ default implementation for this method for entities adapting to the `ITree`
+ interface, but as our `File` doesn't, we've to provide a custom adapter.
+
+.. figure:: ../../images/tutos-photowebsite_breadcrumbs.png
+ :alt: screenshot of the breadcrumb component
+
+ The breadcrumb component when on a file entity, now displaying parent folder.
+
+
+Step 4: preparing the release and migrating the instance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Now that greatly enhanced our cube, it's time to release it to upgrade production site.
+I'll probably detail that process later, but I currently simply transfer the new code
+to the server running the web site.
+
+However, I've still today some step to respect to get things done properly...
+
+First, as I've added some translatable string, I've to run: ::
+
+ $ cubicweb-ctl i18ncube sytweb
+
+To update the cube's gettext catalogs (the '.po' files under the cube's `i18n`
+directory). Once the above command is executed, I'll then update translations.
+
+To see if everything is ok on my test instance, I do: ::
+
+ $ cubicweb-ctl i18ninstance sytweb
+ $ cubicweb-ctl start -D sytweb
+
+The first command compile i18n catalogs (e.g. generates '.mo' files) for my test
+instance. The second command start it in debug mode, so I can open my browser and
+navigate through the web site to see if everything is ok...
+
+.. Note::
+
+ In the 'cubicweb-ctl i18ncube' command, `sytweb` refers to the **cube**, while
+ in the two other, it refers to the **instance** (if you can't see the
+ difference, reread CubicWeb's concept chapter !).
+
+
+Once I've checked it's ok, I simply have to bump the version number in the
+`__pkginfo__` module to trigger a migration once I'll have updated the code on
+the production site. I can check then check the migration is also going fine, by
+first restoring a dump from the production site, then upgrading my test instance.
+
+To generate a dump from the production site: ::
+
+ $ cubicweb-ctl db-dump sytweb
+ pg_dump -Fc --username=syt --no-owner --file /home/syt/etc/cubicweb.d/sytweb/backup/tmpYIN0YI/system sytweb
+ -> backup file /home/syt/etc/cubicweb.d/sytweb/backup/sytweb-2010-07-13_10-22-40.tar.gz
+
+I can now get back the dump file ('sytweb-2010-07-13_10-22-40.tar.gz') to my test
+machine (using `scp` for instance) to restore it and start migration: ::
+
+ $ cubicweb-ctl db-restore sytweb sytweb-2010-07-13_10-22-40.tar.gz
+ $ cubicweb-ctl upgrade sytweb
+
+You'll have to answer some questions, as we've seen in `an earlier post`_.
+
+Now that everything is tested, I can transfer the new code to the production
+server, `apt-get upgrade` cubicweb and its dependencies, and eventually
+upgrade the production instance.
+
+
+.. _`several improvments`: http://www.cubicweb.org/blogentry/1179899
+.. _`3.8`: http://www.cubicweb.org/blogentry/917107
+.. _`first blog of this series`: http://www.cubicweb.org/blogentry/824642
+.. _`an earlier post`: http://www.cubicweb.org/867464
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/advanced/part05_ui-advanced.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,374 @@
+Building my photos web site with |cubicweb| part V: let's make it even more user friendly
+=========================================================================================
+
+.. _uiprops:
+
+Step 1: tired of the default look?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+OK... Now our site has its most desired features. But... I would like to make it look
+somewhat like *my* website. It is not www.cubicweb.org after all. Let's tackle this
+first!
+
+The first thing we can to is to change the logo. There are various way to achieve
+this. The easiest way is to put a :file:`logo.png` file into the cube's :file:`data`
+directory. As data files are looked at according to cubes order (CubicWeb
+resources coming last), that file will be selected instead of CubicWeb's one.
+
+.. Note::
+ As the location for static resources are cached, you'll have to restart
+ your instance for this to be taken into account.
+
+Though there are some cases where you don't want to use a :file:`logo.png` file.
+For instance if it's a JPEG file. You can still change the logo by defining in
+the cube's :file:`uiprops.py` file:
+
+.. sourcecode:: python
+
+ LOGO = data('logo.jpg')
+
+The uiprops machinery is used to define some static file resources,
+such as the logo, default Javascript / CSS files, as well as CSS
+properties (we'll see that later).
+
+.. Note::
+ This file is imported specifically by |cubicweb|, with a predefined name space,
+ containing for instance the `data` function, telling the file is somewhere
+ in a cube or CubicWeb's data directory.
+
+ One side effect of this is that it can't be imported as a regular python
+ module.
+
+The nice thing is that in debug mode, change to a :file:`uiprops.py` file are detected
+and then automatically reloaded.
+
+Now, as it's a photos web-site, I would like to have a photo of mine as background...
+After some trials I won't detail here, I've found a working recipe explained `here`_.
+All I've to do is to override some stuff of the default CubicWeb user interface to
+apply it as explained.
+
+The first thing to to get the ``<img/>`` tag as first element after the
+``<body>`` tag. If you know a way to avoid this by simply specifying the image
+in the CSS, tell me! The easiest way to do so is to override the
+:class:`HTMLPageHeader` view, since that's the one that is directly called once
+the ``<body>`` has been written. How did I find this? By looking in the
+:mod:`cubiweb.web.views.basetemplates` module, since I know that global page
+layouts sits there. I could also have grep the "body" tag in
+:mod:`cubicweb.web.views`... Finding this was the hardest part. Now all I need is
+to customize it to write that ``img`` tag, as below:
+
+.. sourcecode:: python
+
+ class HTMLPageHeader(basetemplates.HTMLPageHeader):
+ # override this since it's the easier way to have our bg image
+ # as the first element following <body>
+ def call(self, **kwargs):
+ self.w(u'<img id="bg-image" src="%sbackground.jpg" alt="background image"/>'
+ % self._cw.datadir_url)
+ super(HTMLPageHeader, self).call(**kwargs)
+
+
+ def registration_callback(vreg):
+ vreg.register_all(globals().values(), __name__, (HTMLPageHeader))
+ vreg.register_and_replace(HTMLPageHeader, basetemplates.HTMLPageHeader)
+
+
+As you may have guessed, my background image is in a :file:`background.jpg` file
+in the cube's :file:`data` directory, but there are still some things to explain
+to newcomers here:
+
+* The :meth:`call` method is there the main access point of the view. It's called by
+ the view's :meth:`render` method. It is not the only access point for a view, but
+ this will be detailed later.
+
+* Calling `self.w` writes something to the output stream. Except for binary views
+ (which do not generate text), it *must* be passed an Unicode string.
+
+* The proper way to get a file in :file:`data` directory is to use the `datadir_url`
+ attribute of the incoming request (e.g. `self._cw`).
+
+I won't explain again the :func:`registration_callback` stuff, you should understand it
+now! If not, go back to previous posts in the series :)
+
+Fine. Now all I've to do is to add a bit of CSS to get it to behave nicely (which
+is not the case at all for now). I'll put all this in a :file:`cubes.sytweb.css`
+file, stored as usual in our :file:`data` directory:
+
+.. sourcecode:: css
+
+
+ /* fixed full screen background image
+ * as explained on http://webdesign.about.com/od/css3/f/blfaqbgsize.htm
+ *
+ * syt update: set z-index=0 on the img instead of z-index=1 on div#page & co to
+ * avoid pb with the user actions menu
+ */
+ img#bg-image {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 0;
+ }
+
+ div#page, table#header, div#footer {
+ background: transparent;
+ position: relative;
+ }
+
+ /* add some space around the logo
+ */
+ img#logo {
+ padding: 5px 15px 0px 15px;
+ }
+
+ /* more dark font for metadata to have a chance to see them with the background
+ * image
+ */
+ div.metadata {
+ color: black;
+ }
+
+You can see here stuff explained in the cited page, with only a slight modification
+explained in the comments, plus some additional rules to make things somewhat cleaner:
+
+* a bit of padding around the logo
+
+* darker metadata which appears by default below the content (the white frame in the page)
+
+To get this CSS file used everywhere in the site, I have to modify the :file:`uiprops.py` file
+introduced above:
+
+.. sourcecode:: python
+
+ STYLESHEETS = sheet['STYLESHEETS'] + [data('cubes.sytweb.css')]
+
+.. Note::
+ `sheet` is another predefined variable containing values defined by
+ already process `:file:`uiprops.py`` file, notably the CubicWeb's one.
+
+Here we simply want our CSS in addition to CubicWeb's base CSS files, so we
+redefine the `STYLESHEETS` variable to existing CSS (accessed through the `sheet`
+variable) with our one added. I could also have done:
+
+.. sourcecode:: python
+
+ sheet['STYLESHEETS'].append(data('cubes.sytweb.css'))
+
+But this is less interesting since we don't see the overriding mechanism...
+
+At this point, the site should start looking good, the background image being
+resized to fit the screen.
+
+.. image:: ../../images/tutos-photowebsite_background-image.png
+
+The final touch: let's customize CubicWeb's CSS to get less orange... By simply adding
+
+.. sourcecode:: python
+
+ contextualBoxTitleBg = incontextBoxTitleBg = '#AAAAAA'
+
+and reloading the page we've just seen, we know have a nice greyed box instead of
+the orange one:
+
+.. image:: ../../images/tutos-photowebsite_grey-box.png
+
+This is because CubicWeb's CSS include some variables which are
+expanded by values defined in uiprops file. In our case we controlled the
+properties of the CSS `background` property of boxes with CSS class
+`contextualBoxTitleBg` and `incontextBoxTitleBg`.
+
+
+Step 2: configuring boxes
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Boxes present to the user some ways to use the application. Let's first do a few
+user interface tweaks in our :file:`views.py` file:
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import none_rset
+ from cubicweb.web.views import bookmark
+ from cubes.zone import views as zone
+ from cubes.tag import views as tag
+
+ # change bookmarks box selector so it's only displayed on startup views
+ bookmark.BookmarksBox.__select__ = bookmark.BookmarksBox.__select__ & none_rset()
+ # move zone box to the left instead of in the context frame and tweak its order
+ zone.ZoneBox.context = 'left'
+ zone.ZoneBox.order = 100
+ # move tags box to the left instead of in the context frame and tweak its order
+ tag.TagsBox.context = 'left'
+ tag.TagsBox.order = 102
+ # hide similarity box, not interested
+ tag.SimilarityBox.visible = False
+
+The idea is to move all boxes in the left column, so we get more space for the
+photos. Now, serious things: I want a box similar to the tags box but to handle
+the `Person displayed_on File` relation. We can do this simply by adding a
+:class:`AjaxEditRelationCtxComponent` subclass to our views, as below:
+
+.. sourcecode:: python
+
+ from logilab.common.decorators import monkeypatch
+ from cubicweb import ValidationError
+ from cubicweb.web.views import uicfg, component
+ from cubicweb.web.views import basecontrollers
+
+ # hide displayed_on relation using uicfg since it will be displayed by the box below
+ uicfg.primaryview_section.tag_object_of(('*', 'displayed_on', '*'), 'hidden')
+
+ class PersonBox(component.AjaxEditRelationCtxComponent):
+ __regid__ = 'sytweb.displayed-on-box'
+ # box position
+ order = 101
+ context = 'left'
+ # define relation to be handled
+ rtype = 'displayed_on'
+ role = 'object'
+ target_etype = 'Person'
+ # messages
+ added_msg = _('person has been added')
+ removed_msg = _('person has been removed')
+ # bind to js_* methods of the json controller
+ fname_vocabulary = 'unrelated_persons'
+ fname_validate = 'link_to_person'
+ fname_remove = 'unlink_person'
+
+
+ @monkeypatch(basecontrollers.JSonController)
+ @basecontrollers.jsonize
+ def js_unrelated_persons(self, eid):
+ """return tag unrelated to an entity"""
+ rql = "Any F + ' ' + S WHERE P surname S, P firstname F, X eid %(x)s, NOT P displayed_on X"
+ return [name for (name,) in self._cw.execute(rql, {'x' : eid})]
+
+
+ @monkeypatch(basecontrollers.JSonController)
+ def js_link_to_person(self, eid, people):
+ req = self._cw
+ for name in people:
+ name = name.strip().title()
+ if not name:
+ continue
+ try:
+ firstname, surname = name.split(None, 1)
+ except:
+ raise ValidationError(eid, {('displayed_on', 'object'): 'provide <first name> <surname>'})
+ rset = req.execute('Person P WHERE '
+ 'P firstname %(firstname)s, P surname %(surname)s',
+ locals())
+ if rset:
+ person = rset.get_entity(0, 0)
+ else:
+ person = req.create_entity('Person', firstname=firstname,
+ surname=surname)
+ req.execute('SET P displayed_on X WHERE '
+ 'P eid %(p)s, X eid %(x)s, NOT P displayed_on X',
+ {'p': person.eid, 'x' : eid})
+
+ @monkeypatch(basecontrollers.JSonController)
+ def js_unlink_person(self, eid, personeid):
+ self._cw.execute('DELETE P displayed_on X WHERE P eid %(p)s, X eid %(x)s',
+ {'p': personeid, 'x': eid})
+
+
+You basically subclass to configure with some class attributes. The `fname_*`
+attributes give the name of methods that should be defined on the json control to
+make the AJAX part of the widget work: one to get the vocabulary, one to add a
+relation and another to delete a relation. These methods must start by a `js_`
+prefix and are added to the controller using the `@monkeypatch` decorator. In my
+case, the most complicated method is the one which adds a relation, since it
+tries to see if the person already exists, and else automatically create it,
+assuming the user entered "firstname surname".
+
+Let's see how it looks like on a file primary view:
+
+.. image:: ../../images/tutos-photowebsite_boxes.png
+
+Great, it's now as easy for me to link my pictures to people than to tag them.
+Also, visitors get a consistent display of these two pieces of information.
+
+.. Note::
+ The ui component system has been refactored in `CubicWeb 3.10`_, which also
+ introduced the :class:`AjaxEditRelationCtxComponent` class.
+
+
+Step 3: configuring facets
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The last feature we'll add today is facet configuration. If you access to the
+'/file' url, you'll see a set of 'facets' appearing in the left column. Facets
+provide an intuitive way to build a query incrementally, by proposing to the user
+various way to restrict the result set. For instance CubicWeb proposes a facet to
+restrict based on who created an entity; the tag cube proposes a facet to
+restrict based on tags; the zoe cube a facet to restrict based on geographical
+location, and so on. In that gist, I want to propose a facet to restrict based on
+the people displayed on the picture. To do so, there are various classes in the
+:mod:`cubicweb.web.facet` module which simply have to be configured using class
+attributes as we've done for the box. In our case, we'll define a subclass of
+:class:`RelationFacet`.
+
+.. Note::
+
+ Since that's ui stuff, we'll continue to add code below to our
+ :file:`views.py` file. Though we begin to have a lot of various code their, so
+ it's may be a good time to split our views module into submodules of a `view`
+ package. In our case of a simple application (glue) cube, we could start using
+ for instance the layout below: ::
+
+ views/__init__.py # uicfg configuration, facets
+ views/layout.py # header/footer/background stuff
+ views/components.py # boxes, adapters
+ views/pages.py # index view, 404 view
+
+.. sourcecode:: python
+
+ from cubicweb.web import facet
+
+ class DisplayedOnFacet(facet.RelationFacet):
+ __regid__ = 'displayed_on-facet'
+ # relation to be displayed
+ rtype = 'displayed_on'
+ role = 'object'
+ # view to use to display persons
+ label_vid = 'combobox'
+
+Let's say we also want to filter according to the `visibility` attribute. This is
+even simpler as we just have to derive from the :class:`AttributeFacet` class:
+
+.. sourcecode:: python
+
+ class VisibilityFacet(facet.AttributeFacet):
+ __regid__ = 'visibility-facet'
+ rtype = 'visibility'
+
+Now if I search for some pictures on my site, I get the following facets available:
+
+.. image:: ../../images/tutos-photowebsite_facets.png
+
+.. Note::
+
+ By default a facet must be applyable to every entity in the result set and
+ provide at leat two elements of vocabulary to be displayed (for instance you
+ won't see the `created_by` facet if the same user has created all
+ entities). This may explain why you don't see yours...
+
+
+Conclusion
+~~~~~~~~~~
+
+We started to see the power behind the infrastructure provided by the
+framework, both on the pure ui (CSS, Javascript) side and on the Python side
+(high level generic classes for components, including boxes and facets). We now
+have, with a few lines of code, a full-featured web site with a personalized look.
+
+Of course we'll probably want more as time goes, but we can now
+concentrate on making good pictures, publishing albums and sharing them with
+friends...
+
+
+
+.. _`CubicWeb 3.10`: http://www.cubicweb.org/blogentry/1330518
+.. _`here`: http://webdesign.about.com/od/css3/f/blfaqbgsize.htm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/base/blog-in-five-minutes.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,70 @@
+.. -*- coding: utf-8 -*-
+
+.. _TutosBaseBlogFiveMinutes:
+
+Get a blog running in five minutes!
+-----------------------------------
+
+For Debian or Ubuntu users, first install the following packages
+(:ref:`DebianInstallation`)::
+
+ cubicweb, cubicweb-dev, cubicweb-blog
+
+Windows or Mac OS X users must install |cubicweb| from source (see
+:ref:`SourceInstallation` and :ref:`WindowsInstallation`).
+
+Then create and initialize your instance::
+
+ cubicweb-ctl create blog myblog
+
+You'll be asked a few questions, and you can keep the default answer for most of
+them. The one question you'll have to think about is the database you'll want to
+use for that instance. For a quick test, if you don't have `postgresql` installed
+and configured (see :ref:`PostgresqlConfiguration`), it's highly recommended to
+choose `sqlite` when asked for which database driver to use, since it has a much
+simple setup (no database server needed).
+
+One the process is completed (including database initialisation), you can start
+your instance by using: ::
+
+ cubicweb-ctl start -D myblog
+
+The `-D` option activates the debugging mode. Removing it will launch the instance
+as a daemon in the background, and ``cubicweb-ctl stop myblog`` will stop
+it in that case.
+
+
+About file system permissions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Unless you installed from sources, the above commands assume that you have root
+access to the :file:`/etc/` directory. In order to initialize your instance as a
+regular user, within your home directory, you can use the :envvar:`CW_MODE`
+environment variable: ::
+
+ export CW_MODE=user
+
+then create a :file:`~/etc/cubicweb.d` directory that will hold your instances.
+
+More information about how to configure your own environment is
+available in :ref:`ResourceMode`.
+
+
+Instance parameters
+~~~~~~~~~~~~~~~~~~~
+
+If you would like to change database parameters such as the database host or the
+user name used to connect to the database, edit the `sources` file located in the
+:file:`/etc/cubicweb.d/myblog` directory.
+
+Then relaunch the database creation::
+
+ cubicweb-ctl db-create myblog
+
+Other parameters, like web server or emails parameters, can be modified in the
+:file:`/etc/cubicweb.d/myblog/all-in-one.conf` file.
+
+You'll have to restart the instance after modification in one of those files.
+
+This is it. Your blog is functional and running. Visit http://localhost:8080 and enjoy it!
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/base/conclusion.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,18 @@
+.. -*- coding: utf-8 -*-
+
+What's next?
+------------
+
+In this tutorial, we have seen that you can, right after the installation of
+|cubicweb|, build a web application in a few minutes by defining a data model as
+assembling cubes. You get a working application that you can then customize there
+and there while keeping something that works. This is important in agile
+development practices, you can right from the start of the project show things
+to customer and so take the right decision early in the process.
+
+The next steps will be to discover hooks, security, data sources, digging deeper
+into view writing and interface customisation... Yet a lot of fun stuff to
+discover! You will find more `tutorials and howtos`_ in the blog published on the
+CubicWeb.org website.
+
+.. _`tutorials and howtos`: http://www.cubicweb.org/view?rql=Any+X+ORDERBY+D+DESC+WHERE+X+is+BlogEntry%2C+T+tags+X%2C+T+name+IN+%28%22tutorial%22%2C+%22howto%22%29%2C+X+creation_date+D
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/base/customizing-the-application.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,539 @@
+.. -*- coding: utf-8 -*-
+
+.. _TutosBaseCustomizingTheApplication:
+
+Customizing your application
+----------------------------
+
+So far so good. The point is that usually, you won't get enough by assembling
+cubes out-of-the-box. You will want to customize them, have a personal look and
+feel, add your own data model and so on. Or maybe start from scratch?
+
+So let's get a bit deeper and start coding our own cube. In our case, we want
+to customize the blog we created to add more features to it.
+
+
+Create your own cube
+~~~~~~~~~~~~~~~~~~~~
+
+First, notice that if you've installed |cubicweb| using Debian packages, you will
+need the additional ``cubicweb-dev`` package to get the commands necessary to
+|cubicweb| development. All `cubicweb-ctl` commands are described in details in
+:ref:`cubicweb-ctl`.
+
+Once your |cubicweb| development environment is set up, you can create a new
+cube::
+
+ cubicweb-ctl newcube myblog
+
+This will create in the cubes directory (:file:`/path/to/grshell/cubes` for source
+installation, :file:`/usr/share/cubicweb/cubes` for Debian packages installation)
+a directory named :file:`blog` reflecting the structure described in
+:ref:`cubelayout`.
+
+For packages installation, you can still create new cubes in your home directory
+using the following configuration. Let's say you want to develop your new cubes
+in `~src/cubes`, then set the following environment variables: ::
+
+ CW_CUBES_PATH=~/src/cubes
+
+and then create your new cube using: ::
+
+ cubicweb-ctl newcube --directory=~/src/cubes myblog
+
+.. Note::
+
+ We previously used `myblog` as the name of our *instance*. We're now creating
+ a *cube* with the same name. Both are different things. We'll now try to
+ specify when we talk about one or another, but keep in mind this difference.
+
+
+Cube metadata
+~~~~~~~~~~~~~
+
+A simple set of metadata about your cube are stored in the :file:`__pkginfo__.py`
+file. In our case, we want to extend the blog cube, so we have to tell that our
+cube depends on this cube, by modifying the ``__depends__`` dictionary in that
+file:
+
+.. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.10.7',
+ 'cubicweb-blog': None}
+
+where the ``None`` means we do not depends on a particular version of the cube.
+
+.. _TutosBaseCustomizingTheApplicationDataModel:
+
+Extending the data model
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+The data model or schema is the core of your |cubicweb| application. It defines
+the type of content your application will handle. It is defined in the file
+:file:`schema.py` of the cube.
+
+
+Defining our model
+******************
+
+For the sake of example, let's say we want a new entity type named `Community`
+with a name, a description. A `Community` will hold several blogs.
+
+.. sourcecode:: python
+
+ from yams.buildobjs import EntityType, RelationDefinition, String, RichString
+
+ class Community(EntityType):
+ name = String(maxsize=50, required=True)
+ description = RichString()
+
+ class community_blog(RelationDefinition):
+ subject = 'Community'
+ object = 'Blog'
+ cardinality = '*?'
+ composite = 'subject'
+
+The first step is the import from the :mod:`yams` package necessary classes to build
+the schema.
+
+This file defines the following:
+
+* a `Community` has a title and a description as attributes
+
+ - the name is a string that is required and can't be longer than 50 characters
+
+ - the description is a string that is not constrained and may contains rich
+ content such as HTML or Restructured text.
+
+* a `Community` may be linked to a `Blog` using the `community_blog` relation
+
+ - ``*`` means a community may be linked to 0 to N blog, ``?`` means a blog may
+ be linked to 0 to 1 community. For completeness, remember that you can also
+ use ``+`` for 1 to N, and ``1`` for single, mandatory relation (e.g. one to one);
+
+ - this is a composite relation where `Community` (e.g. the subject of the
+ relation) is the composite. That means that if you delete a community, its
+ blog will be deleted as well.
+
+Of course, there are a lot of other data types and things such as constraints,
+permissions, etc, that may be defined in the schema, but those won't be covered
+in this tutorial.
+
+Notice that our schema refers to the `Blog` entity type which is not defined
+here. But we know this type is available since we depend on the `blog` cube
+which is defining it.
+
+
+Applying changes to the model into our instance
+***********************************************
+
+Now the problem is that we created an instance using the `blog` cube, not our
+`myblog` cube, so if we don't do anything there is no way that we'll see anything
+changing in the instance.
+
+One easy way, as we've no really valuable data in the instance would be to trash and recreated it::
+
+ cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
+ cubicweb-ctl delete myblog
+ cubicweb-ctl create myblog
+ cubicweb-ctl start -D myblog
+
+Another way is to add our cube to the instance using the cubicweb-ctl shell
+facility. It's a python shell connected to the instance with some special
+commands available to manipulate it (the same as you'll have in migration
+scripts, which are not covered in this tutorial). In that case, we're interested
+in the `add_cube` command: ::
+
+ $ cubicweb-ctl stop myblog # or Ctrl-C in the terminal running the server in debug mode
+ $ cubicweb-ctl shell myblog
+ entering the migration python shell
+ just type migration commands or arbitrary python code and type ENTER to execute it
+ type "exit" or Ctrl-D to quit the shell and resume operation
+ >>> add_cube('myblog')
+ >>>
+ $ cubicweb-ctl start -D myblog
+
+The `add_cube` command is enough since it automatically updates our
+application to the cube's schema. There are plenty of other migration
+commands of a more finer grain. They are described in :ref:`migration`
+
+As explained, leave the shell by typing Ctrl-D. If you restart the instance and
+take another look at the schema, you'll see that changes to the data model have
+actually been applied (meaning database schema updates and all necessary stuff
+has been done).
+
+.. image:: ../../images/tutos-base_myblog-schema_en.png
+ :alt: the instance schema after adding our cube
+
+If you follow the 'info' link in the user pop-up menu, you'll also see that the
+instance is using blog and myblog cubes.
+
+.. image:: ../../images/tutos-base_myblog-siteinfo_en.png
+ :alt: the instance schema after adding our cube
+
+You can now add some communities, link them to blog, etc... You'll see that the
+framework provides default views for this entity type (we have not yet defined any
+view for it!), and also that the blog primary view will show the community it's
+linked to if any. All this thanks to the model driven interface provided by the
+framework.
+
+You'll then be able to redefine each of them according to your needs
+and preferences. We'll now see how to do such thing.
+
+.. _TutosBaseCustomizingTheApplicationCustomViews:
+
+Defining your views
+~~~~~~~~~~~~~~~~~~~
+
+|cubicweb| provides a lot of standard views in directory
+:file:`cubicweb/web/views/`. We already talked about 'primary' and 'list' views,
+which are views which apply to one ore more entities.
+
+A view is defined by a python class which includes:
+
+ - an identifier: all objects used to build the user interface in |cubicweb| are
+ recorded in a registry and this identifier will be used as a key in that
+ registry. There may be multiple views for the same identifier.
+
+ - a *selector*, which is a kind of filter telling how well a view suit to a
+ particular context. When looking for a particular view (e.g. given an
+ identifier), |cubicweb| computes for each available view with that identifier
+ a score which is returned by the selector. Then the view with the highest
+ score is used. The standard library of predicates is in
+ :mod:`cubicweb.predicates`.
+
+A view has a set of methods inherited from the :class:`cubicweb.view.View` class,
+though you usually don't derive directly from this class but from one of its more
+specific child class.
+
+Last but not least, |cubicweb| provides a set of default views accepting any kind
+of entities.
+
+Want a proof? Create a community as you've already done for other entity types
+through the index page, you'll then see something like that:
+
+.. image:: ../../images/tutos-base_myblog-community-default-primary_en.png
+ :alt: the default primary view for our community entity type
+
+
+If you notice the weird messages that appear in the page: those are messages
+generated for the new data model, which have no translation yet. To fix that,
+we'll have to use dedicated `cubicweb-ctl` commands:
+
+.. sourcecode: bash
+
+ cubicweb-ctl i18ncube myblog # build/update cube's message catalogs
+ # then add translation into .po file into the cube's i18n directory
+ cubicweb-ctl i18ninstance myblog # recompile instance's message catalogs
+ cubicweb-ctl restart -D myblog # instance has to be restarted to consider new catalogs
+
+You'll then be able to redefine each of them according to your needs and
+preferences. So let's see how to do such thing.
+
+Changing the layout of the application
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The layout is the general organization of the pages in the site. Views that generate
+the layout are sometimes referred to as 'templates'. They are implemented in the
+framework in the module :mod:`cubicweb.web.views.basetemplates`. By overriding
+classes in this module, you can customize whatever part you wish of the default
+layout.
+
+But notice that |cubicweb| provides many other ways to customize the
+interface, thanks to actions and components (which you can individually
+(de)activate, control their location, customize their look...) as well as
+"simple" CSS customization. You should first try to achieve your goal using such
+fine grained parametrization rather then overriding a whole template, which usually
+embeds customisation access points that you may loose in the process.
+
+But for the sake of example, let's say we want to change the generic page
+footer... We can simply add to the module ``views`` of our cube,
+e.g. :file:`cubes/myblog/views.py`, the code below:
+
+.. sourcecode:: python
+
+ from cubicweb.web.views import basetemplates
+
+ class MyHTMLPageFooter(basetemplates.HTMLPageFooter):
+
+ def footer_content(self):
+ self.w(u'This website has been created with <a href="http://cubicweb.org">CubicWeb</a>.')
+
+ def registration_callback(vreg):
+ vreg.register_all(globals().values(), __name__, (MyHTMLPageFooter,))
+ vreg.register_and_replace(MyHTMLPageFooter, basetemplates.HTMLPageFooter)
+
+
+* Our class inherits from the default page footer to ease getting things right,
+ but this is not mandatory.
+
+* When we want to write something to the output stream, we simply call `self.w`,
+ which *must be passed a unicode string*.
+
+* The latest function is the most exotic stuff. The point is that without it, you
+ would get an error at display time because the framework wouldn't be able to
+ choose which footer to use between :class:`HTMLPageFooter` and
+ :class:`MyHTMLPageFooter`, since both have the same selector, hence the same
+ score... In this case, we want our footer to replace the default one, so we have
+ to define a :func:`registration_callback` function to control object
+ registration: the first instruction tells to register everything in the module
+ but the :class:`MyHTMLPageFooter` class, then the second to register it instead
+ of :class:`HTMLPageFooter`. Without this function, everything in the module is
+ registered blindly.
+
+.. Note::
+
+ When a view is modified while running in debug mode, it is not required to
+ restart the instance server. Save the Python file and reload the page in your
+ web browser to view the changes.
+
+We will now have this simple footer on every page of the site.
+
+
+Primary view customization
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The 'primary' view (i.e. any view with the identifier set to 'primary') is the one used to
+display all the information about a single entity. The standard primary view is one
+of the most sophisticated views of all. It has several customisation points, but
+its power comes with `uicfg`, allowing you to control it without having to
+subclass it.
+
+However this is a bit off-topic for this first tutorial. Let's say we simply want a
+custom primary view for my `Community` entity type, using directly the view
+interface without trying to benefit from the default implementation (you should
+do that though if you're rewriting reusable cubes; everything is described in more
+details in :ref:`primary_view`).
+
+
+So... Some code! That we'll put again in the module ``views`` of our cube.
+
+.. sourcecode:: python
+
+ from cubicweb.predicates import is_instance
+ from cubicweb.web.views import primary
+
+ class CommunityPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('Community')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+ if entity.description:
+ self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+What's going on here?
+
+* Our class inherits from the default primary view, here mainly to get the correct
+ view identifier, since we don't use any of its features.
+
+* We set on it a selector telling that it only applies when trying to display
+ some entity of the `Community` type. This is enough to get an higher score than
+ the default view for entities of this type.
+
+* View applying to entities usually have to define `cell_call` as entry point,
+ and are given `row` and `col` arguments tell to which entity in the result set
+ the view is applied. We can then get this entity from the result set
+ (`self.cw_rset`) by using the `get_entity` method.
+
+* To ease thing, we access our entity's attribute for display using its
+ printable_value method, which will handle formatting and escaping when
+ necessary. As you can see, you can also access attributes by their name on the
+ entity to get the raw value.
+
+
+You can now reload the page of the community we just created and see the changes.
+
+.. image:: ../../images/tutos-base_myblog-community-custom-primary_en.png
+ :alt: the custom primary view for our community entity type
+
+We've seen here a lot of thing you'll have to deal with to write views in
+|cubicweb|. The good news is that this is almost everything that is used to
+build higher level layers.
+
+.. Note::
+
+ As things get complicated and the volume of code in your cube increases, you can
+ of course still split your views module into a python package with subpackages.
+
+You can find more details about views and selectors in :ref:`Views`.
+
+
+Write entities to add logic in your data
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+|cubicweb| provides an ORM to easily programmaticaly manipulate
+entities (just like the one we have fetched earlier by calling
+`get_entity` on a result set). By default, entity
+types are instances of the :class:`AnyEntity` class, which holds a set of
+predefined methods as well as property automatically generated for
+attributes/relations of the type it represents.
+
+You can redefine each entity to provide additional methods or whatever you want
+to help you write your application. Customizing an entity requires that your
+entity:
+
+- inherits from :class:`cubicweb.entities.AnyEntity` or any subclass
+
+- defines a :attr:`__regid__` linked to the corresponding data type of your schema
+
+You may then want to add your own methods, override default implementation of some
+method, etc...
+
+.. sourcecode:: python
+
+ from cubicweb.entities import AnyEntity, fetch_config
+
+
+ class Community(AnyEntity):
+ """customized class for Community entities"""
+ __regid__ = 'Community'
+
+ fetch_attrs, cw_fetch_order = fetch_config(['name'])
+
+ def dc_title(self):
+ return self.name
+
+ def display_cw_logo(self):
+ return 'CubicWeb' in self.description
+
+In this example:
+
+* we used convenience :func:`fetch_config` function to tell which attributes
+ should be prefetched by the ORM when looking for some related entities of this
+ type, and how they should be ordered
+
+* we overrode the standard `dc_title` method, used in various place in the interface
+ to display the entity (though in this case the default implementation would
+ have had the same result)
+
+* we implemented here a method :meth:`display_cw_logo` which tests if the blog
+ entry title contains 'CW'. It can then be used when you're writing code
+ involving 'Community' entities in your views, hooks, etc. For instance, you can
+ modify your previous views as follows:
+
+.. sourcecode:: python
+
+
+ class CommunityPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('Community')
+
+ def cell_call(self, row, col):
+ entity = self.cw_rset.get_entity(row, col)
+ self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+ if entity.display_cw_logo():
+ self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+ if entity.description:
+ self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+Then each community whose description contains 'CW' is shown with the |cubicweb|
+logo in front of it.
+
+.. Note::
+
+ As for view, you don't have to restart your instance when modifying some entity
+ classes while your server is running in debug mode, the code will be
+ automatically reloaded.
+
+
+Extending the application by using more cubes!
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the goal of the |cubicweb| framework was to have truly reusable
+components. To do so, they must both behave nicely when plugged into the
+application and be easily customisable, from the data model to the user
+interface. And I think the result is pretty successful, thanks to system such as
+the selection mechanism and the choice to write views as python code which allows
+to build our page using true object oriented programming techniques, that no
+template language provides.
+
+
+A library of standard cubes is available from `CubicWeb Forge`_, to address a
+lot of common concerns such has manipulating people, files, things to do, etc. In
+our community blog case, we could be interested for instance in functionalities
+provided by the `comment` and `tag` cubes. The former provides threaded
+discussion functionalities, the latter a simple tag mechanism to classify content.
+Let's say we want to try those. We will first modify our cube's :file:`__pkginfo__.py`
+file:
+
+.. sourcecode:: python
+
+ __depends__ = {'cubicweb': '>= 3.10.7',
+ 'cubicweb-blog': None,
+ 'cubicweb-comment': None,
+ 'cubicweb-tag': None}
+
+Now, we'll simply tell on which entity types we want to activate the 'comment'
+and 'tag' facilities by adding respectively the 'comments' and 'tags' relations on
+them in our schema (:file:`schema.py`).
+
+.. sourcecode:: python
+
+ class comments(RelationDefinition):
+ subject = 'Comment'
+ object = 'BlogEntry'
+ cardinality = '1*'
+ composite = 'object'
+
+ class tags(RelationDefinition):
+ subject = 'Tag'
+ object = ('Community', 'BlogEntry')
+
+
+So in the case above we activated comments on `BlogEntry` entities and tags on
+both `Community` and `BlogEntry`. Various views from both `comment` and `tag`
+cubes will then be automatically displayed when one of those relations is
+supported.
+
+Let's synchronize the data model as we've done earlier: ::
+
+
+ $ cubicweb-ctl stop myblog
+ $ cubicweb-ctl shell myblog
+ entering the migration python shell
+ just type migration commands or arbitrary python code and type ENTER to execute it
+ type "exit" or Ctrl-D to quit the shell and resume operation
+ >>> add_cubes(('comment', 'tag'))
+ >>>
+
+Then restart the instance. Let's look at a blog entry:
+
+.. image:: ../../images/tutos-base_myblog-blogentry-taggable-commentable-primary_en.png
+ :alt: the primary view for a blog entry with comments and tags activated
+
+As you can see, we now have a box displaying tags and a section proposing to add
+a comment and displaying existing one below the post. All this without changing
+anything in our views, thanks to the design of generic views provided by the
+framework. Though if we take a look at a community, we won't see the tags box!
+That's because by default this box try to locate itself in the left column within
+the white frame, and this column is handled by the primary view we
+hijacked. Let's change our view to make it more extensible, by keeping both our
+custom rendering but also extension points provided by the default
+implementation.
+
+
+.. sourcecode:: python
+
+ class CommunityPrimaryView(primary.PrimaryView):
+ __select__ = is_instance('Community')
+
+ def render_entity_title(self, entity):
+ self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
+
+ def render_entity_attributes(self, entity):
+ if entity.display_cw_logo():
+ self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+ if entity.description:
+ self.w(u'<p>%s</p>' % entity.printable_value('description'))
+
+It appears now properly:
+
+.. image:: ../../images/tutos-base_myblog-community-taggable-primary_en.png
+ :alt: the custom primary view for a community entry with tags activated
+
+You can control part of the interface independently from each others, piece by
+piece. Really.
+
+
+
+.. _`CubicWeb Forge`: http://www.cubicweb.org/project
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/base/discovering-the-ui.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,161 @@
+
+.. _TutosBaseDiscoveringTheUI:
+
+Discovering the web interface
+-----------------------------
+
+You can now access your web instance to create blogs and post messages
+by visiting the URL http://localhost:8080/.
+
+By default, anonymous access is disabled, so a login form will appear. If you
+asked to allow anonymous access when initializing the instance, click on the
+'login' link in the top right hand corner. To login, you need then use the admin
+account you specified at the time you initialized the database with
+``cubicweb-ctl create``.
+
+.. image:: ../../images/tutos-base_login-form_en.png
+ :alt: the login form
+
+
+Once authenticated, you can start playing with your instance. The default index
+page looks like the following:
+
+.. image:: ../../images/tutos-base_index_en.png
+ :alt: the index page
+
+
+Minimal configuration
+~~~~~~~~~~~~~~~~~~~~~
+
+Before creating entities, let's change that 'unset title' thing that appears
+here and there. This comes from a |cubicweb| system properties. To set it,
+click on the 'site configuration link' in the pop-up menu behind your login name
+in the upper left-hand corner
+
+.. image:: ../../images/tutos-base_user-menu_en.png
+ :alt: the user pop-up menu
+
+The site title is in the 'Ui' section. Simply set it to the desired value and
+click the 'validate' button.
+
+.. image:: ../../images/tutos-base_siteconfig_en.png
+ :alt: the site configuration form
+
+You should see a 'changes applied' message. You can now go back to the
+index page by clicking on the |cubicweb| logo in the upper left-hand corner.
+
+You will much likely still see 'unset title' at this point. This is because by
+default the index page is cached. Force a refresh of the page (by typing Ctrl-R
+in Firefox for instance) and you should now see the title you entered.
+
+
+Adding entities
+~~~~~~~~~~~~~~~
+
+The ``blog`` cube defines several entity types, among them ``Blog`` which is a
+container for ``BlogEntry`` (i.e. posts) on a particular topic. We can get a
+graphical view of the schema by clicking on the 'site schema' link in the user
+pop-up menu we've already seen:
+
+.. image:: ../../images/tutos-base_schema_en.png
+ :alt: graphical view of the schema (aka data-model)
+
+Nice isn't it? Notice that this, as most other stuff we'll see in this tutorial,
+is generated by the framework according to the model of the application. In our
+case, the model defined by the ``blog`` cube.
+
+Now let us create a few of these entities.
+
+
+Add a blog
+**********
+
+Clicking on the `[+]` at the left of the 'Blog' link on the index page will lead
+you to an HTML form to create a blog.
+
+.. image:: ../../images/tutos-base_blog-form_en.png
+ :alt: the blog creation form
+
+For instance, call this new blog 'Tech-blog' and type in 'everything about
+technology' as the description , then validate the form by clicking on
+'Validate'. You will be redirected to the `primary` view of the newly created blog.
+
+.. image:: ../../images/tutos-base_blog-primary_en.png
+ :alt: the blog primary view
+
+
+Add a blog post
+***************
+
+There are several ways to add a blog entry. The simplest is to click on the 'add
+blog entry' link in the actions box on viewing the blog you have just created.
+You will then see a form to create a post, with a 'blog entry of' field preset
+to the blog we're coming from. Enter a title, some content, click the 'validate'
+button and you're done. You will be redirected to the blog primary view, though you
+now see that it contains the blog post you've just created.
+
+.. image:: ../../images/tutos-base_blog-primary-after-post-creation_en.png
+ :alt: the blog primary view after creation of a post
+
+Notice there are some new boxes that appears in the left column.
+
+You can achieve the same thing by following the same path as we did for the blog
+creation, e.g. by clicking on the `[+]` at the left of the 'Blog entry' link on
+the index page. The diffidence being that since there is no context information,
+the 'blog entry of' selector won't be preset to the blog.
+
+
+If you click on the 'modify' link of the action box, you are back to
+the form to edit the entity you just created, except that the form now
+has another section with a combo-box entitled 'add relation'. It
+provisos a generic way to edit relations which don't appears in the
+above form. Choose the relation you want to add and a second combo box
+appears where you can pick existing entities. If there are too many
+of them, you will be offered to navigate to the target entity, that is
+go away from the form and go back to it later, once you've selected
+the entity you want to link with.
+
+.. image:: ../../images/tutos-base_form-generic-relations_en.png
+ :alt: the generic relations combo box
+
+This combo box can't appear until the entity is actually created. That's why you
+haven't seen it at creation time. You could also have hit 'Apply' instead of
+'validate' and it would have showed up.
+
+
+About ui auto-adaptation
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the things that make |cubicweb| different of other frameworks is
+its automatic user interface that adapts itself according to the data being
+displayed. Let's see an example.
+
+If you go back to the home page an click on the 'Blog' link, you will be redirected
+to the primary view of the blog, the same we've seen earlier. Now, add another
+blog, go back to the index page, and click again on this link. You will see
+a very different view (namely the 'list' view).
+
+.. image:: ../../images/tutos-base_blogs-list_en.png
+ :alt: the list view when there are more than one blog to display
+
+This is because in the first case, the framework chose to use the 'primary'
+view since there was only one entity in the data to be displayed. Now that there
+are two entities, the 'list' view is more appropriate and hence is being used.
+
+There are various other places where |cubicweb| adapts to display data in the best
+way, the main being provided by the view *selection* mechanism that will be detailed
+later.
+
+
+Digging deeper
+~~~~~~~~~~~~~~
+
+By following principles explained below, you should now be able to
+create new users for your application, to configure with a finer
+grain, etc... You will notice that the index page lists a lot of types
+you don't know about. Most are built-in types provided by the framework
+to make the whole system work. You may ignore them in a first time and
+discover them as time goes.
+
+One thing that is worth playing with is the search box. It may be used in various
+way, from simple full text search to advanced queries using the :ref:`RQL` .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/base/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,48 @@
+.. -*- coding: utf-8 -*-
+
+.. _TutosBase:
+
+Building a simple blog with |cubicweb|
+======================================
+
+|cubicweb| is a semantic web application framework that favors reuse and
+object-oriented design.
+
+
+This tutorial is designed to help in your very first steps to start with
+|cubicweb|. We will tour through basic concepts such as:
+
+* getting an application running by using existing components
+* discovering the default user interface
+* basic extending and customizing the look and feel of that application
+
+More advanced concepts are covered in :ref:`TutosPhotoWebSite`.
+
+
+.. _TutosBaseVocab:
+
+Some vocabulary
+---------------
+
+|cubicweb| comes with a few words of vocabulary that you should know to
+understand what we're talking about. To follow this tutorial, you should at least
+know that:
+
+* a `cube` is a component that usually includes a model defining some data types
+ and a set of views to display them. A cube can be built by assembling other
+ cubes;
+
+* an `instance` is a specific installation of one or more cubes and includes
+ configuration files, a web server and a database.
+
+Reading :ref:`Concepts` for more vocabulary will be required at some point.
+
+Now, let's start the hot stuff!
+
+.. toctree::
+ :maxdepth: 2
+
+ blog-in-five-minutes
+ discovering-the-ui
+ customizing-the-application
+ conclusion
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,21 @@
+.. _Tutorials:
+
+---------
+Tutorials
+---------
+
+We present two tutorials of different levels. The blog building
+tutorial introduces one smoothly to the basic concepts.
+
+Then there is a photo gallery construction tutorial which highlights
+more advanced concepts such as unit tests, security settings,
+migration scripts.
+
+.. toctree::
+ :maxdepth: 1
+ :numbered:
+
+ base/index
+ advanced/index
+ tools/windmill.rst
+ textreports/index
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/textreports/index.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,13 @@
+.. -*- coding: utf-8 -*-
+
+Writing text reports with RestructuredText
+==========================================
+
+|cubicweb| offers several text formats for the RichString type used in schemas,
+including restructuredtext.
+
+Three additional restructuredtext roles are defined by |cubicweb|:
+
+.. autofunction:: cubicweb.ext.rest.eid_reference_role
+.. autofunction:: cubicweb.ext.rest.rql_role
+.. autofunction:: cubicweb.ext.rest.bookmark_role
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/tutorials/tools/windmill.rst Thu Jan 08 22:11:06 2015 +0100
@@ -0,0 +1,229 @@
+==========================
+Use Windmill with CubicWeb
+==========================
+
+Windmill_ implements cross browser testing, in-browser recording and playback,
+and functionality for fast accurate debugging and test environment integration.
+
+.. _Windmill: http://www.getwindmill.com/
+
+`Online features list <http://www.getwindmill.com/features>`_ is available.
+
+
+Installation
+============
+
+Windmill
+--------
+
+You have to install Windmill manually for now. If you're using Debian, there is
+no binary package (`yet <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=579109>`_).
+
+The simplest solution is to use a *setuptools/pip* command (for a clean
+environment, take a look to the `virtualenv
+<http://pypi.python.org/pypi/virtualenv>`_ project as well)::
+
+ $ pip install windmill
+ $ curl -O http://github.com/windmill/windmill/tarball/master
+
+However, the Windmill project doesn't release frequently. Our recommandation is
+to used the last snapshot of the Git repository::
+
+ $ git clone git://github.com/windmill/windmill.git HEAD
+ $ cd windmill
+ $ python setup.py develop
+
+Install instructions are `available <http://wiki.github.com/windmill/windmill/installing>`_.
+
+Be sure to have the windmill module in your PYTHONPATH afterwards::
+
+ $ python -c "import windmill"
+
+X dummy
+-------
+
+In order to reduce unecessary system load from your test machines, It's
+recommended to use X dummy server for testing the Unix web clients, you need a
+dummy video X driver (as xserver-xorg-video-dummy package in Debian) coupled
+with a light X server as `Xvfb <http://en.wikipedia.org/wiki/Xvfb>`_.
+
+ The dummy driver is a special driver available with the XFree86 DDX. To use
+ the dummy driver, simply substitue it for your normal card driver in the
+ Device section of your xorg.conf configuration file. For example, if you
+ normally uses an ati driver, then you will have a Device section with
+ Driver "ati" to let the X server know that you want it to load and use the
+ ati driver; however, for these conformance tests, you would change that
+ line to Driver "dummy" and remove any other ati specific options from the
+ Device section.
+
+ *From: http://www.x.org/wiki/XorgTesting*
+
+Then, you can run the X server with the following command ::
+
+ $ /usr/bin/X11/Xvfb :1 -ac -screen 0 1280x1024x8 -fbdir /tmp
+
+
+Windmill usage
+==============
+
+Record your use case
+--------------------
+
+- start your instance manually
+- start Windmill_ with url site as last argument (read Usage_ or use *'-h'*
+ option to find required command line arguments)
+- use the record button
+- click on save to obtain python code of your use case
+- copy the content to a new file in a *windmill* directory
+
+.. _Usage: http://wiki.github.com/windmill/windmill/running-tests
+
+If you are using firefox as client, consider the "firebug" option.
+
+If you have a running instance, you can refine the test by the *loadtest* windmill option::
+
+ $ windmill -m firebug loadtest=<test_file.py> <instance url>
+
+Or use the internal windmill shell to explore available commands::
+
+ $ windmill -m firebug shell <instance url>
+
+And enter python commands:
+
+.. sourcecode:: python
+
+ >>> load_test(<your test file>)
+ >>> run_test(<your test file>)
+
+
+
+Integrate Windmill tests into CubicWeb
+======================================
+
+Set environment
+---------------
+
+You have to create a new unit test file and a `windmill` directory and copy all
+your windmill use case into it.
+
+.. sourcecode:: python
+
+ # test_windmill.py
+
+ # Run all scenarii found in windmill directory
+ from cubicweb.devtools.cwwindmill import (CubicWebWindmillUseCase,
+ unittest_main)
+
+ if __name__ == '__main__':
+ unittest_main()
+
+Run your tests
+--------------
+
+You can easily run your windmill test suite through `pytest` or :mod:`unittest`.
+You have to copy a *test_windmill.py* file from :mod:`web.test`.
+
+To run your test series::
+
+ $ pytest test/test_windmill.py
+
+By default, CubicWeb will use **firefox** as the default browser and will try
+to run test instance server on localhost. In the general case, You've no need
+to change anything.
+
+Check :class:`cubicweb.devtools.cwwindmill.CubicWebWindmillUseCase` for
+Windmill configuration. You can edit windmill settings with following class attributes:
+
+* browser
+ identification string (firefox|ie|safari|chrome) (firefox by default)
+* test_dir
+ testing file path or directory (windmill directory under your unit case
+ file by default)
+* edit_test
+ load and edit test for debugging (False by default)
+
+Examples:
+
+.. sourcecode:: python
+
+ browser = 'firefox'
+ test_dir = osp.join(__file__, 'windmill')
+ edit_test = False
+
+If you want to change cubicweb test server parameters, you can check class
+variables from :class:`CubicWebServerConfig` or inherit it with overriding the
+:attr:`configcls` attribute in :class:`CubicWebServerTC` ::
+
+.. sourcecode:: python
+
+ class OtherCubicWebServerConfig(CubicWebServerConfig):
+ port = 9999
+
+ class NewCubicWebServerTC(CubicWebServerTC):
+ configcls = OtherCubicWebServerConfig
+
+For instance, CubicWeb framework windmill tests can be manually run by::
+
+ $ pytest web/test/test_windmill.py
+
+Edit your tests
+---------------
+
+You can toggle the `edit_test` variable to enable test edition.
+
+But if you are using `pytest` as test runner, use the `-i` option directly.
+The test series will be loaded and you can run assertions step-by-step::
+
+ $ pytest -i test/test_windmill.py
+
+In this case, the `firebug` extension will be loaded automatically for you.
+
+Afterwards, don't forget to save your edited test into the right file (no autosave feature).
+
+Best practises
+--------------
+
+Don't run another instance on the same port. You risk to silence some
+regressions (test runner will automatically fail in further versions).
+
+Start your use case by using an assert on the expected primary url page.
+Otherwise all your tests could fail without clear explanation of the used
+navigation.
+
+In the same location of the *test_windmill.py*, create a *windmill/* with your
+windmill recorded use cases.
+
+
+Caveats
+=======
+
+File Upload
+-----------
+
+Windmill can't do file uploads. This is a limitation of browser Javascript
+support / sandboxing, not of Windmill per se. It would be nice if there were
+some command that would prime the Windmill HTTP proxy to add a particular file
+to the next HTTP request that comes through, so that uploads could at least be
+faked.
+
+.. http://groups.google.com/group/windmill-dev/browse_thread/thread/cf9dc969722bd6bb/01aa18fdd652f7ff?lnk=gst&q=input+type+file#01aa18fdd652f7ff
+
+.. http://davisagli.com/blog/in-browser-integration-testing-with-windmill
+
+.. http://groups.google.com/group/windmill-dev/browse_thread/thread/b7bebcc38ed30dc7
+
+
+Preferences
+===========
+
+A *.windmill/prefs.py* could be used to redefine default configuration values.
+
+.. define CubicWeb preferences in the parent test case instead with a dedicated firefox profile
+
+For managing browser extensions, read `advanced topic chapter
+<http://wiki.github.com/windmill/windmill/advanced-topics>`_.
+
+More configuration examples could be seen in *windmill/conf/global_settings.py*
+as template.
+
+