# HG changeset patch # User Sylvain Thénault # Date 1271353195 -7200 # Node ID dfd147de06b27918718fce63d71a1c50098ffcf7 # Parent 66b0987716f98ca7170127b74f8fd378cbe35c8d# Parent f4219a6e62e3ce7b6b769f7e35fceddd37ce4254 backport stable diff -r 66b0987716f9 -r dfd147de06b2 __pkginfo__.py --- a/__pkginfo__.py Thu Apr 15 18:54:13 2010 +0200 +++ b/__pkginfo__.py Thu Apr 15 19:39:55 2010 +0200 @@ -7,7 +7,7 @@ modname = distname = "cubicweb" -numversion = (3, 7, 3) +numversion = (3, 7, 4) version = '.'.join(str(num) for num in numversion) description = "a repository of entities / relations for knowledge management" diff -r 66b0987716f9 -r dfd147de06b2 cwctl.py diff -r 66b0987716f9 -r dfd147de06b2 cwvreg.py --- a/cwvreg.py Thu Apr 15 18:54:13 2010 +0200 +++ b/cwvreg.py Thu Apr 15 19:39:55 2010 +0200 @@ -476,7 +476,7 @@ """set instance'schema and load application objects""" self._set_schema(schema) # now we can load application's web objects - self.reload(self.config.vregistry_path()) + self.reload(self.config.vregistry_path(), force_reload=False) # map lowered entity type names to their actual name self.case_insensitive_etypes = {} for eschema in self.schema.entities(): @@ -490,21 +490,22 @@ if self.is_reload_needed(path): self.reload(path) - def reload(self, path): + def reload(self, path, force_reload=True): """modification detected, reset and reload the vreg""" CW_EVENT_MANAGER.emit('before-registry-reload') - cleanup_sys_modules(path) - cubes = self.config.cubes() - # if the fs code use some cubes not yet registered into the instance we - # should cleanup sys.modules for those as well to avoid potential bad - # class reference pb after reloading - cfg = self.config - for cube in cfg.expand_cubes(cubes, with_recommends=True): - if not cube in cubes: - cpath = cfg.build_vregistry_cube_path([cfg.cube_dir(cube)]) - cleanup_sys_modules(cpath) + if force_reload: + cleanup_sys_modules(path) + cubes = self.config.cubes() + # if the fs code use some cubes not yet registered into the instance + # we should cleanup sys.modules for those as well to avoid potential + # bad class reference pb after reloading + cfg = self.config + for cube in cfg.expand_cubes(cubes, with_recommends=True): + if not cube in cubes: + cpath = cfg.build_vregistry_cube_path([cfg.cube_dir(cube)]) + cleanup_sys_modules(cpath) self.reset() - self.register_objects(path, True) + self.register_objects(path, force_reload) CW_EVENT_MANAGER.emit('after-registry-reload') def _set_schema(self, schema): diff -r 66b0987716f9 -r dfd147de06b2 debian/changelog --- a/debian/changelog Thu Apr 15 18:54:13 2010 +0200 +++ b/debian/changelog Thu Apr 15 19:39:55 2010 +0200 @@ -1,3 +1,9 @@ +cubicweb (3.7.4-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Thu, 15 Apr 2010 18:20:39 +0200 + cubicweb (3.7.3-1) unstable; urgency=low * new upstream release diff -r 66b0987716f9 -r dfd147de06b2 debian/control --- a/debian/control Thu Apr 15 18:54:13 2010 +0200 +++ b/debian/control Thu Apr 15 19:39:55 2010 +0200 @@ -33,7 +33,7 @@ Conflicts: cubicweb-multisources Replaces: cubicweb-multisources Provides: cubicweb-multisources -Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (=> 1.0.2), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2 +Depends: ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.0.2), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2 Recommends: pyro, cubicweb-documentation (= ${source:Version}) Description: server part of the CubicWeb framework CubicWeb is a semantic web application framework. diff -r 66b0987716f9 -r dfd147de06b2 devtools/htmlparser.py --- a/devtools/htmlparser.py Thu Apr 15 18:54:13 2010 +0200 +++ b/devtools/htmlparser.py Thu Apr 15 19:39:55 2010 +0200 @@ -74,6 +74,21 @@ Validator.__init__(self) self.parser = etree.XMLParser() +class XMLDemotingValidator(SaxOnlyValidator): + """ some views produce html instead of xhtml, using demote_to_html + + this is typically related to the use of external dependencies + which do not produce valid xhtml (google maps, ...) + """ + + def preprocess_data(self, data): + if data.startswith(' 200', '200'), ('> 250', '250'), ('> 275', '275'), ('> 300', '300')] - -And that's it: we have two filter boxes automatically displayed on each page -presenting more than one office. The `price` facet is basically the same as the -`surface` one but with a different vocabulary and with ``rtype = 'price'``. +RangeFacet +~~~~~~~~~~ +The ``RangeFacet`` inherits from the ``AttributeFacet``. It allows to filter entities according to certain attributes of numerical type. -(The cube also benefits from the builtin google map views defined by -cubicweb but that's for another blog). +The ``RangeFacet`` displays a slider using `jquery`_ to choose a lower bound and an upper bound. -.. _image: http://www.cubicweb.org/image/197646?vid=download -.. _comment: http://www.cubicweb.org/project/cubicweb-comment -.. _addressbook: http://www.cubicweb.org/project/cubicweb-addressbook +The example below defines a facet to filter a selection of books according to their number of pages. -CubicWeb has this really nice builtin `facet`_ system to -define restrictions `filters`_ really as easily as possible. +.. sourcecode:: python -We've just added two new kind of facets in CubicWeb : + class BookPagesFacet(RangeFacet): + __regid__ = 'priority-facet' + __select__ = RangeFacet.__select__ & implements('Book') + rtype = 'pages' -- The **RangeFacet** which displays a slider using `jquery`_ - to choose a lower bound and an upper bound. The **RangeWidget** - works with either numerical values or date values +The image below display the rendering of the ``RangeFacet``: -- The **HasRelationFacet** which displays a simple checkbox and - lets you refine your selection in order to get only entities - that actually use this relation. +.. image:: ../../images/facet_range.png -.. image :: http://www.cubicweb.org/Image/343498?vid=download +DateRangeFacet +~~~~~~~~~~~~~~ +The ``DateRangeFacet`` inherits from the ``RangeFacet``. It allows to filter entities according to certain attributes of date type. - -Here's an example of code that defines a facet to filter +Here is an example of code that defines a facet to filter musical works according to their composition date: .. sourcecode:: python @@ -116,14 +133,39 @@ # 3. specify the attribute name that actually stores the date in the DB rtype = 'composition_date' -And that's it, on each page displaying tracks, you'll be able to filter them +With this facet, on each page displaying tracks, you'll be able to filter them according to their composition date with a jquery slider. -All this, brought by CubicWeb (in the next 3.3 version) +The image below display the rendering of the ``DateRangeFacet``: + +.. image:: ../../images/facet_date_range.png + + +HasRelationFacet +~~~~~~~~~~~~~~~~ + +The ``DateRangeFacet`` inherits from the ``AbstractFacet``. It will +display a simple checkbox and lets you refine your selection in order +to get only entities that actually use this relation. + +Here is an example of the rendering of the ``HasRelationFacet`` to +filter entities with image and the corresponding code: + +.. image:: ../../images/facet_has_image.png + +.. sourcecode:: python + + class HasImageFacet(HasRelationFacet): + __regid__ = 'hasimage-facet' + __select__ = HasRelationFacet.__select__ & implements('Book') + rtype = 'has_image' + + + +To use ``HasRelationFacet`` on a reverse relation add ``role = 'object'`` in +it's definitions. .. _facet: http://en.wikipedia.org/wiki/Faceted_browser .. _filters: http://www.cubicweb.org/blogentry/154152 .. _jquery: http://www.jqueryui.com/ -To use **HasRelationFacet** on a reverse relation add ``role = 'object'`` in -it's definitions. diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/index.rst --- a/doc/book/en/development/devweb/index.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/index.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,20 +1,21 @@ Web development =============== -In this chapter, we will describe the core api for web development in the *CubicWeb* framework. +In this chapter, we will describe the core APIs for web development in +the *CubicWeb* framework. .. toctree:: :maxdepth: 2 - request publisher controllers - property + request + views/index rtags - views/index + js + css form facets + internationalization + property httpcaching - js - css - internationalization diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/publisher.rst --- a/doc/book/en/development/devweb/publisher.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/publisher.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,4 +1,63 @@ +.. _publisher: + Publisher --------- -XXX cubicweb.web.application; coop diagram for execution of a http query \ No newline at end of file +What happens when an HTTP request is issued ? + +The story begins with the ``CubicWebPublisher.main_publish`` +method. We do not get upper in the bootstrap process because it is +dependant on the used HTTP library. With `twisted`_ however, +``cubicweb.etwist.server.CubicWebRootResource.render_request`` is the +real entry point. + +What main_publish does: + +* get a controller id and a result set from the path (this is actually + delegated to the `urlpublisher` component) + +* the controller is then selected (if not, this is considered an + authorization failure and signaled as sich) 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_rst`) + * 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: diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/request.rst --- a/doc/book/en/development/devweb/request.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/request.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,5 +1,8 @@ The `Request` class (`cubicweb.web`) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +------------------------------------ + +Overview +```````` A request instance is created when an HTTP request is sent to the web server. It contains informations such as form parameters, user authenticated, etc. @@ -16,15 +19,16 @@ But also: -:Session data handling: +* `Session data handling` + * `session_data()`, returns a dictionary containing all the session data * `get_session_data(key, default=None)`, returns a value associated to the given key or the value `default` if the key is not defined * `set_session_data(key, value)`, assign a value to a key * `del_session_data(key)`, suppress the value associated to a key +* `Cookies handling` -: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`, @@ -33,12 +37,14 @@ window) * `remove_cookie(cookie, key)`, forces a value to expire -:URL handling: +* `URL handling` + * `url()`, returns the full URL of the HTTP request * `base_url()`, returns the root URL of the web application * `relative_path()`, returns the relative path of the request -:And more...: +* `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 @@ -56,6 +62,18 @@ most of the interface of `Request` is defined in the session associated to the client. +API +``` -XXX autoclass ! -XXX create_entity +The elements we gave in overview for above are built in three layers, +from ``cubicweb.req.RequestSessionBase``, ``cubicweb.dbapi.DBAPIRequest`` and +``cubicweb.web.CubicWebRequestBase``. + +.. autoclass:: cubicweb.req.RequestSessionBase + :members: + +.. autoclass:: cubicweb.dbapi.DBAPIRequest + :members: + +.. autoclass:: cubicweb.web.request.CubicWebRequestBase + :members: diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/views/basetemplates.rst --- a/doc/book/en/development/devweb/views/basetemplates.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/views/basetemplates.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,176 +1,93 @@ .. -*- coding: utf-8 -*- +.. |cubicweb| replace:: *CubicWeb* + .. _templates: Templates ========= -[WRITE ME] +Templates are the entry point for the |cubicweb| view system. As seen +in :ref:`views_base_class`, there are two kinds of views: the +templatable and non-templatable. + +Non-templatable views are standalone. They are responsible for all the +details such as setting a proper content type (or mime type), the +proper document headers, namespaces, etc. Examples are pure xml views +such as RSS or Semantic Web views (`SIOC`_, `DOAP`_, `FOAF`_, `Linked +Data`_, etc.). -* talk about main templates, etc. +.. _`SIOC`: http://sioc-project.org/ +.. _`DOAP`: http://trac.usefulinc.com/doap +.. _`FOAF`: http://www.foaf-project.org/ +.. _`Linked Data`: http://linkeddata.org/ + +Templatable views are not concerned with such pesky details. They +leave it to the template. Conversely, the template's main job is to: + +* set up the proper document header and content type +* define the general layout of a document +* invoke adequate views in the various sections of the document +Look at :mod:`cubicweb.web.views.basetemplates` and you will find the +base templates used to generate (X)HTML for your application. The most +important template there is `TheMainTemplate`. -Look at ``cubicweb/web/views/basetemplates.py`` and you will -find the base templates used to generate HTML for your application. +.. _the_main_template_layout: + +TheMainTemplate +--------------- + +Layout and sections +``````````````````` A page is composed as indicated on the schema below : .. image:: ../../../images/main_template.png -In this section we will go through a couple of the primary templates -you must be interested in, that is to say, the HTMLPageHeader, -the HTMLPageFooter and the TheMainTemplate. - - -HTMLPageHeader --------------- - -Customize header -~~~~~~~~~~~~~~~~ +The sections dispatches specific views: -Let's now move the search box in the header and remove the login form -from the header. We'll show how to move it to the left column of the application. +* `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: -Let's say we do not want anymore the login menu to be in the header, but we -prefer it to be in the left column just below the logo. As the left column is -rendered by ``TheMainTemplate``, we will show how to do it in TheMainTemplate_. - -First, to remove the login menu, we just need to comment out the display of the -login component such as follows : :: - - class MyHTMLPageHeader(HTMLPageHeader): + * 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 - def main_header(self, view): - """build the top menu with authentification info and the rql box""" - self.w(u'\n') - self.w(u'\n') - # appliname and breadcrumbs - self.w(u'') - # logged user and help - #self.w(u'') - # lastcolumn - self.w(u'\n') - self.w(u'\n') - self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden', - title=False, message=False) + * 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) - - -.. image:: ../../../images/lax-book.06-header-no-login.en.png - -Let's now move the search box in the top-right header area. To do so, we will -first create a method to get the search box display and insert it in the header -table. - -:: +* `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) - from cubicweb.web.views.basetemplates import HTMLPageHeader - class MyHTMLPageHeader(HTMLPageHeader): - def main_header(self, view): - """build the top menu with authentification info and the rql box""" - self.w(u'\n') - self.w(u'\n') - # appliname and breadcrumbs - self.w(u'') - - # logged user and help - #self.w(u'') - - self.w(u'') - # lastcolumn - self.w(u'\n') - self.w(u'\n') - self.template('logform', rset=self.cw_rset, id='popupLoginBox', klass='hidden', - title=False, message=False) +* `contentcol`: this is the central column; it is filled with: - def get_searchbox(self, view, context): - boxes = list(self._cw.vreg.poss_visible_objects('boxes', self._cw, self.cw_rset, - view=view, context=context)) - if boxes: - for box in boxes: - if box.__regid__ == 'search_box': - box.dispatch(w=self.w, view=view) - - - - -HTMLPageFooter --------------- - -If you want to change the footer for example, look -for HTMLPageFooter and override it in your views file as in : -:: + * 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` - form cubicweb.web.views.basetemplates import HTMLPageFooter - class MyHTMLPageFooter(HTMLPageFooter): - def call(self, **kwargs): - self.w(u'') +* `footer`: adds all footer actions -Updating a view does not require any restart of the server. By reloading -the page you can see your new page footer. - +.. note:: -TheMainTemplate ---------------- -.. _TheMainTemplate: - -TheMainTemplate is responsible for the general layout of the entire application. -It defines the template of ``__regid__ = main`` that is used by the instance. + How and why a view object is given to the main template is explained + in the :ref:`publisher` chapter. -The default main template (`cubicweb.web.views.basetemplates.TheMainTemplate`) -builds the page based on the following pattern: - -.. image:: ../../../images/main_template_layout.png - -The rectangle containing `view.dispatch()` represents the area where the content -view has to be displayed. The others represents sub-templates called to complete -the page. A default implementation of those is provided in -`cubicweb.views.basetemplates`. You can, of course, overload those sub-templates -to implement your own customization of the HTML page. +Class attributes +```````````````` We can also control certain aspects of the main template thanks to the following forms parameters: @@ -184,6 +101,13 @@ the dictionary of the forms parameters, before going the classic way (through step 1 and 2 described juste above) -The MainTemplate is a bit complex as it tries to accomodate many -different cases. We are now about to go through it and cutomize entirely -our application. +Other templates +--------------- + +Other standard templates include: + +* `login` and `logout` + +* `error-template` specializes TheMainTemplate to do proper end-user + output if an error occurs during the computation of TheMainTemplate + (it is a fallback view). diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/views/boxes.rst --- a/doc/book/en/development/devweb/views/boxes.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/views/boxes.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,5 +1,7 @@ -Boxes (:mod:`cubicweb.web.views.boxes`) ---------------------------------------------------------------- +Boxes +----- + +(:mod:`cubicweb.web.views.boxes`) *sidebox* This view displays usually a side box of some related entities @@ -24,7 +26,6 @@ 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. diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/views/index.rst --- a/doc/book/en/development/devweb/views/index.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/views/index.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,5 +1,5 @@ -The views system -================ +The View system +=============== .. |cubicweb| replace:: *CubicWeb* @@ -20,11 +20,15 @@ table xmlrss autoform - editforms +.. editforms + +.. toctree:: + :maxdepth: 3 + urlpublish breadcrumbs - facets - wdoc - embedding - idownloadable +.. facets +.. wdoc +.. embedding +.. idownloadable diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/views/startup.rst --- a/doc/book/en/development/devweb/views/startup.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/views/startup.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,5 +1,8 @@ -Startup views (:mod:`cubicweb.web.views.startup`) -------------------------------------------------- +Startup views +------------- + + (:mod:`cubicweb.web.views.startup`) + Usual selector: no_rset or yes. Views that don't apply to a result set diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/views/urlpublish.rst --- a/doc/book/en/development/devweb/views/urlpublish.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/views/urlpublish.rst Thu Apr 15 19:39:55 2010 +0200 @@ -1,7 +1,27 @@ .. -*- coding: utf-8 -*- -URL Rewriting (:mod:`cubicweb.web.views.urlpublish`) and (:mod:`cubicweb.web.views.urlrewrite`) ------------------------------------------------------------------------------------------------- +URL publishing +-------------- + +(:mod:`cubicweb.web.views.urlpublishing`) + +.. automodule:: cubicweb.web.views.urlpublishing + +.. autoclass:: cubicweb.web.views.urlpublishing.URLPublisherComponent + :members: + +URL rewriting +------------- -XXX feed me -show how urls are mapped to selections and views and explain URLRewriting +(: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: + + diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/development/devweb/views/views.rst --- a/doc/book/en/development/devweb/views/views.rst Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/development/devweb/views/views.rst Thu Apr 15 19:39:55 2010 +0200 @@ -13,6 +13,8 @@ XHTML stream, but there are views concerned with email other non-html outputs. +.. _views_base_class: + Basic class for views ~~~~~~~~~~~~~~~~~~~~~ diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/images/facet_date_range.png Binary file doc/book/en/images/facet_date_range.png has changed diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/images/facet_has_image.png Binary file doc/book/en/images/facet_has_image.png has changed diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/images/facet_overview.png Binary file doc/book/en/images/facet_overview.png has changed diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/images/facet_range.png Binary file doc/book/en/images/facet_range.png has changed diff -r 66b0987716f9 -r dfd147de06b2 doc/book/en/images/primaryview_template.svg --- a/doc/book/en/images/primaryview_template.svg Thu Apr 15 18:54:13 2010 +0200 +++ b/doc/book/en/images/primaryview_template.svg Thu Apr 15 19:39:55 2010 +0200 @@ -64,7 +64,10 @@ transform="translate(162.2968,90.697922)"> + 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"> + 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" /> + 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" /> + 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" /> + 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" /> render_side_boxes() + 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" /> + 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" /> + 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" /> 0 - self.cleanup_session_time = vreg.config['cleanup-session-time'] or 43200 - assert self.cleanup_session_time > 0 - self.cleanup_anon_session_time = vreg.config['cleanup-anonymous-session-time'] or 120 + if self.session_time is not None: + assert self.session_time > 0 + self.session_time *= 60 # convert minutes to seconds + self.cleanup_session_time = self.session_time + else: + self.cleanup_session_time = (vreg.config['cleanup-session-time'] or 1440) * 60 + assert self.cleanup_session_time > 0 + self.cleanup_anon_session_time = (vreg.config['cleanup-anonymous-session-time'] or 5) * 60 assert self.cleanup_anon_session_time > 0 - if self.session_time: - assert self.cleanup_session_time < self.session_time - assert self.cleanup_anon_session_time < self.session_time self.authmanager = vreg['components'].select('authmanager', vreg=vreg) def clean_sessions(self): diff -r 66b0987716f9 -r dfd147de06b2 web/request.py --- a/web/request.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/request.py Thu Apr 15 19:39:55 2010 +0200 @@ -526,6 +526,7 @@ def add_css(self, cssfiles, media=u'all', localfile=True, ieonly=False, iespec=u'[if lt IE 8]'): """specify a CSS file to include in the HTML headers + :param cssfiles: a CSS filename or a list of CSS filenames :param media: the CSS's media if necessary :param localfile: if True, the default data dir prefix is added to the @@ -553,15 +554,17 @@ def build_ajax_replace_url(self, nodeid, rql, vid, replacemode='replace', **extraparams): - """builds an ajax url that will replace `nodeid`s content + """builds an ajax url that will replace nodeid's content + :param nodeid: the dom id of the node to replace :param rql: rql to execute :param vid: the view to apply on the resultset :param replacemode: defines how the replacement should be done. + 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 + - '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 """ url = self.build_url('view', rql=rql, vid=vid, __notemplate=1, **extraparams) diff -r 66b0987716f9 -r dfd147de06b2 web/test/unittest_breadcrumbs.py --- a/web/test/unittest_breadcrumbs.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/test/unittest_breadcrumbs.py Thu Apr 15 19:39:55 2010 +0200 @@ -15,7 +15,7 @@ ibc = self.vreg['components'].select('breadcrumbs', self.request(), rset=childrset) self.assertEquals(ibc.render(), """ > folder_plural > par&ent >  -chi&ld""" % f1.eid) +chi&ld""" % (f1.eid, f2.eid)) if __name__ == '__main__': from logilab.common.testlib import unittest_main diff -r 66b0987716f9 -r dfd147de06b2 web/views/facets.py --- a/web/views/facets.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/views/facets.py Thu Apr 15 19:39:55 2010 +0200 @@ -69,7 +69,7 @@ rset, vid, divid, paginate = self._get_context(view) if rset.rowcount < 2: # XXX done by selectors, though maybe necessary when rset has been hijacked return - rqlst = self.cw_rset.syntax_tree() + rqlst = rset.syntax_tree() # union not yet supported if len(rqlst.children) != 1: return () diff -r 66b0987716f9 -r dfd147de06b2 web/views/ibreadcrumbs.py --- a/web/views/ibreadcrumbs.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/views/ibreadcrumbs.py Thu Apr 15 19:39:55 2010 +0200 @@ -62,10 +62,7 @@ def wpath_part(self, part, contextentity, last=False): if isinstance(part, Entity): - if last and part.eid == contextentity.eid: - self.w(xml_escape(part.view('breadcrumbtext'))) - else: - self.w(part.view('breadcrumbs')) + self.w(part.view('breadcrumbs')) elif isinstance(part, tuple): url, title = part textsize = self._cw.property_value('navigation.short-line-size') diff -r 66b0987716f9 -r dfd147de06b2 web/views/urlpublishing.py --- a/web/views/urlpublishing.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/views/urlpublishing.py Thu Apr 15 19:39:55 2010 +0200 @@ -1,28 +1,26 @@ -"""associate url's path to view identifier / rql queries +# organization: Logilab +# copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. +# contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr +# license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +"""Associate url's path to view identifier / rql queries. -It currently handle url's path with the forms +It currently handles url path with the forms: * +* minimal REST publishing: -* minimal REST publishing: * * [//]* - * folder navigation - -You can actually control URL (more exactly path) resolution using URL path -evaluator. - -XXX actionpath and folderpath execute a query whose results is lost -because of redirecting instead of direct traversal +You can actually control URL (more exactly path) resolution using an +URL path evaluator. -:organization: Logilab -:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. -:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr -:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses +.. note:: + + Actionpath and Folderpath execute a query whose results is lost + because of redirecting instead of direct traversal. """ - __docformat__ = "restructuredtext en" from rql import TypeResolverException @@ -37,17 +35,18 @@ """ class URLPublisherComponent(component.Component): - """associate url's path to view identifier / rql queries, - by applying a chain of urlpathevaluator components. + """Associate url path to view identifier / rql queries, by + applying a chain of urlpathevaluator components. - An evaluator is a URLPathEvaluator subclass with a .evaluate_path + An evaluator is a URLPathEvaluator subclass with an .evaluate_path method taking the request object and the path to publish as - argument. It will either returns a publishing method identifier - and a rql query on success or raises a `PathDontMatch` exception - on failure. URL evaluators are called according to their `priority` - attribute, with 0 as the greatest priority and greater values as - lower priority. The first evaluator returning a result or raising - something else than `PathDontMatch` will stop the handlers chain. + argument. It will either return a publishing method identifier + and an rql query on success or raise a `PathDontMatch` exception + on failure. URL evaluators are called according to their + `priority` attribute, with 0 as the greatest priority and greater + values as lower priority. The first evaluator returning a result + or raising something else than `PathDontMatch` will stop the + handlers chain. """ __regid__ = 'urlpublisher' vreg = None # XXX necessary until property for deprecation warning is on appobject @@ -64,18 +63,18 @@ self.evaluators = sorted(evaluators, key=lambda x: x.priority) def process(self, req, path): - """given an url (essentialy caracterized by a path on the server, - but additional information may be found in the request object), return - a publishing method identifier (eg controller) and an optional result - set + """Given an url (essentialy caracterized by a path on the + server, but additional information may be found in the request + object), return a publishing method identifier + (e.g. controller) and an optional result set. - :type req: `cubicweb.web.Request` + :type req: `cubicweb.web.request.CubicWebRequestBase` :param req: the request object :type path: str :param path: the path of the resource to publish - :rtype: tuple(str, `cubicweb.utils.ResultSet` or None) + :rtype: tuple(str, `cubicweb.rset.ResultSet` or None) :return: the publishing method identifier and an optional result set :raise NotFound: if no handler is able to decode the given path diff -r 66b0987716f9 -r dfd147de06b2 web/views/urlrewrite.py --- a/web/views/urlrewrite.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/views/urlrewrite.py Thu Apr 15 19:39:55 2010 +0200 @@ -1,4 +1,4 @@ -"""Rules based url rewriter component, to get configurable RESTful urls +"""Rules based url rewriter component, to get configurable RESTful urls. :organization: Logilab :copyright: 2007-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. @@ -40,17 +40,17 @@ class URLRewriter(AppObject): - """base class for URL rewriters + """Base class for URL rewriters. - url rewriters should have a `rules` dict that maps an input URI + Url rewriters should have a `rules` dict that maps an input URI to something that should be used for rewriting. The actual logic that defines how the rules dict is used is implemented - in the `rewrite` method + in the `rewrite` method. A `priority` attribute might be used to indicate which rewriter should be tried first. The higher the priority is, the earlier the - rewriter will be tried + rewriter will be tried. """ __metaclass__ = metarewriter __registry__ = 'urlrewriting' @@ -62,11 +62,11 @@ class SimpleReqRewriter(URLRewriter): - """The SimpleReqRewriters uses a `rules` dict that maps - input URI (regexp or plain string) to a dictionary to update the - request's form + """The SimpleReqRewriters uses a `rules` dict that maps input URI + (regexp or plain string) to a dictionary to update the request's + form. - If the input uri is a regexp, group substitution is allowed + If the input uri is a regexp, group substitution is allowed. """ __regid__ = 'simple' diff -r 66b0987716f9 -r dfd147de06b2 web/webconfig.py --- a/web/webconfig.py Thu Apr 15 18:54:13 2010 +0200 +++ b/web/webconfig.py Thu Apr 15 19:39:55 2010 +0200 @@ -115,27 +115,28 @@ ('http-session-time', {'type' : 'int', 'default': 0, - 'help': 'duration in seconds for HTTP sessions. 0 mean no expiration. '\ - 'Should be greater than RQL server\'s session-time.', + 'help': "duration in minutes of the cookie used to store session " + "identifier. If 0, the cookie will expire when the user exist its " + "browser. Should be 0 or greater than repository\'s session-time.", 'group': 'web', 'inputlevel': 2, }), ('cleanup-session-time', {'type' : 'int', - 'default': 43200, - 'help': 'duration in seconds for which unused connections should be '\ - 'closed, to limit memory consumption. This is different from '\ - 'http-session-time since in some cases you may have an unexpired http '\ - 'session (e.g. valid session cookie) which will trigger transparent '\ - 'creation of a new session. In other cases, sessions may never expire \ - and cause memory leak. Should be smaller than http-session-time, '\ - 'unless it\'s 0. Default to 12 h.', + 'default': 1440, + 'help': 'duration of inactivity in minutes after which a connection ' + 'will be closed, to limit memory consumption (avoid sessions that ' + 'never expire and cause memory leak when http-session-time is 0). ' + 'So even if http-session-time is 0 and the user don\'t close his ' + 'browser, he will have to reauthenticate after this time of ' + 'inactivity. Default to 24h.', 'group': 'web', 'inputlevel': 2, }), ('cleanup-anonymous-session-time', {'type' : 'int', - 'default': 120, - 'help': 'Same as cleanup-session-time but specific to anonymous '\ - 'sessions. Default to 2 min.', + 'default': 5, + 'help': 'Same as cleanup-session-time but specific to anonymous ' + 'sessions. You can have a much smaller timeout here since it will be ' + 'transparent to the user. Default to 5min.', 'group': 'web', 'inputlevel': 2, }), ('force-html-content-type',