--- a/common/migration.py Thu Feb 19 20:19:05 2009 +0100
+++ b/common/migration.py Thu Feb 19 20:21:10 2009 +0100
@@ -312,12 +312,18 @@
"""a configuration option's type has changed"""
self._option_changes.append(('typechanged', optname, oldtype, newvalue))
- def cmd_add_cube(self, cube):
+ def cmd_add_cubes(self, cubes):
+ """modify the list of used cubes in the in-memory config
+ returns newly inserted cubes, including dependencies
+ """
+ if isinstance(cubes, basestring):
+ cubes = (cubes,)
origcubes = self.config.cubes()
- newcubes = [p for p in self.config.expand_cubes([cube])
+ newcubes = [p for p in self.config.expand_cubes(cubes)
if not p in origcubes]
if newcubes:
- assert cube in newcubes
+ for cube in cubes:
+ assert cube in newcubes
self.config.add_cubes(newcubes)
return newcubes
--- a/common/selectors.py Thu Feb 19 20:19:05 2009 +0100
+++ b/common/selectors.py Thu Feb 19 20:21:10 2009 +0100
@@ -161,13 +161,20 @@
def paginated_rset(cls, req, rset, *args, **kwargs):
"""accept result sets with more rows than the page size
"""
- if rset is None or len(rset) <= req.property_value('navigation.page-size'):
+ page_size = kwargs.get('page_size')
+ if page_size is None:
+ page_size = req.form.get('page_size')
+ if page_size is None:
+ page_size = req.property_value('navigation.page-size')
+ else:
+ page_size = int(page_size)
+ if rset is None or len(rset) <= page_size:
return 0
return 1
largerset_selector = deprecated_function(paginated_rset)
@lltrace
-def sorted_rset(cls, req, rset, row=None, col=None):
+def sorted_rset(cls, req, rset, row=None, col=None, **kwargs):
"""accept sorted result set"""
rqlst = rset.syntax_tree()
if len(rqlst.children) > 1 or not rqlst.children[0].orderby:
--- a/common/test/unittest_entity.py Thu Feb 19 20:19:05 2009 +0100
+++ b/common/test/unittest_entity.py Thu Feb 19 20:21:10 2009 +0100
@@ -250,8 +250,7 @@
self.assertListEquals(rbc(e.relations_by_category('generic')),
[('primary_email', 'subject'),
('evaluee', 'subject'),
- ('for_user', 'object'),
- ('bookmarked_by', 'object')])
+ ('for_user', 'object')])
# owned_by is defined both as subject and object relations on EUser
self.assertListEquals(rbc(e.relations_by_category('generated')),
[('last_login_time', 'subject'),
@@ -263,7 +262,8 @@
('owned_by', 'subject'),
('created_by', 'object'),
('wf_info_for', 'object'),
- ('owned_by', 'object')])
+ ('owned_by', 'object'),
+ ('bookmarked_by', 'object')])
e = self.etype_instance('Personne')
self.assertListEquals(rbc(e.relations_by_category('primary')),
[('nom', 'subject'), ('eid', 'subject')])
--- a/devtools/repotest.py Thu Feb 19 20:19:05 2009 +0100
+++ b/devtools/repotest.py Thu Feb 19 20:21:10 2009 +0100
@@ -3,7 +3,7 @@
This module contains functions to initialize a new repository.
:organization: Logilab
-:copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2003-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
@@ -249,7 +249,8 @@
_orig_select_principal = rqlannotation._select_principal
def _select_principal(scope, relations):
- return _orig_select_principal(scope, sorted(relations, key=lambda x: x.r_type))
+ return _orig_select_principal(scope, relations,
+ _sort=lambda rels: sorted(rels, key=lambda x: x.r_type))
try:
from cubicweb.server.msplanner import PartPlanInformation
--- a/doc/book/en/B0031-define-entities.en.txt Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/B0031-define-entities.en.txt Thu Feb 19 20:21:10 2009 +0100
@@ -55,13 +55,21 @@
It is possible to manage attributes/relations in the simple or multiple
editing form thanks to the following *rtags*:
-* `primary`, indicates that an attribute or a relation has to be inserted
- in the simple or multiple editing forms. In the case of a relation,
- the related entity editing form will be included in the editing form.
+* `primary`, indicates that an attribute or a relation has to be
+ inserted **in the simple or multiple editing forms**. In the case of
+ a relation, the related entity editing form will be included in the
+ editing form and represented as a combobox. Each item of the
+ combobox is a link to an existing entity.
-* `secondary`, indicates that an attribute or a relation has to be inserted
- in the simple editing form only. In the case of a relation, the related
- entity editing form sill be included in the editing form.
+* `secondary`, indicates that an attribute or a relation has to be
+ inserted **in the simple editing form only**. In the case of a
+ relation, the related entity editing form will be included in the
+ editing form and represented as a combobox. Each item of the combobox
+ is a link to an existing entity.
+
+* `inlineview`, includes the target entity's form in the editing form
+ of the current entity. It allows to create the target entity in the
+ same time as the current entity.
* `generic`, indicates that a relation has to be inserted in the simple
editing form, in the generic box of relation creation.
--- a/doc/book/en/C012-create-instance.en.txt Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/C012-create-instance.en.txt Thu Feb 19 20:21:10 2009 +0100
@@ -24,11 +24,11 @@
A cube defines entities, their views, their schemas and workflows
in an independant directory located in ``/path/to/forest/cubicweb/cubes/``
-for a Mercurila installation or in ``/usr/share/cubicweb/cubes`` for
-a debian packages installation.
+for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for
+a debian package installation.
When an instance is created, you list one or more cubes that your instance
-will use. Use a cube means having the entities defined in your cube's schema
+will use. Using a cube means having the entities defined in your cube's schema
available in your instance as well as their views and workflows.
.. note::
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z010-beginners.en.txt Thu Feb 19 20:21:10 2009 +0100
@@ -0,0 +1,12 @@
+.. -*- coding: utf-8 -*-
+
+.. _QuickInstall:
+
+===========================================
+Quick Installation of a `CubicWeb` instance
+===========================================
+
+.. include:: C011-installation.en.txt
+.. include:: Z012-create-instance.en.txt
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/book/en/Z012-create-instance.en.txt Thu Feb 19 20:21:10 2009 +0100
@@ -0,0 +1,79 @@
+.. -*- coding: utf-8 -*-
+
+Creation of your first instance
+===============================
+
+What is an instance?
+--------------------
+
+A `CubicWeb` instance is a container that
+refers to cubes and configuration parameters for your web application.
+Each instance is stored as a directory in ``~/etc/cubicweb.d`` which enables
+us to run your application.
+
+What is a cube?
+---------------
+
+Cubes represent data and basic building bricks of your web applications :
+blogs, person, date, addressbook and a lot more.
+
+.. XXX They related to each other by a 'Schema' which is also the PostGres representation.
+
+Each cube defines entities, their views, their schemas and workflows
+in an independant directory located in ``/path/to/forest/cubicweb/cubes/``
+for a Mercurial installation or in ``/usr/share/cubicweb/cubes`` for
+a debian package installation. For example, the 'blog' cube defines the entities
+blogs and blogentries.
+
+When an `CubicWeb` instance is created, you list the cubes that you want to use.
+Using a cube means having the entities defined in your cube's schema
+available in your instance as well as their views and workflows.
+
+
+Creating a basic `CubicWeb` Instance
+------------------------------------
+
+We can create an instance to view our
+application in a web browser. ::
+
+ cubicweb-ctl create blog myblog
+
+.. XXX or ::
+
+.. XXX cubicweb-ctl create forge myforge
+
+
+.. note::
+ The commands used below are more detailled in the section dedicated to
+ :ref:`cubicweb-ctl`.
+
+A series of questions will be prompted to you, the default answer is usually
+sufficient. You can allways modify the parameters later by editing
+configuration files. When a user/psswd is requested to access the database
+please use the login you create at the time you configured the database
+(:ref:`ConfigurationPostgres`).
+
+It is important to distinguish here the user used to access the database and
+the user used to login to the cubicweb application. When a `CubicWeb` application
+starts, it uses the login/psswd for the database to get the schema and handle
+low level transaction. But, when ``cubicweb-ctl create`` asks for
+a manager login/psswd of `CubicWeb`, it refers to an application user
+to administrate your web application.
+The configuration files are stored in *~/etc/cubicweb.d/myblog/*.
+
+To launch the web application, you just type ::
+
+ cubicweb-ctl start myblog
+
+You can see how it looks by
+visiting the URL `http://localhost:8080`.
+To login, please use the cubicweb administrator login/psswd you
+defined when you created the instance.
+
+To shutdown the instance ::
+
+ cubicweb-ctl stop myinstance
+
+.. XXX something like `cubicweb-ctl live-server intra` would be nice
+
+
--- a/doc/book/en/index.txt Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/index.txt Thu Feb 19 20:21:10 2009 +0100
@@ -29,7 +29,9 @@
The hacker will join development at the forge_.
-The impatient will move right away to :ref:`MiseEnPlaceEnv`.
+The impatient will go strait away to :ref:`QuickInstall`.
+
+The impatient developper will move right away to :ref:`MiseEnPlaceEnv`.
.. _Logilab: http://www.logilab.fr/
.. _forge: http://www.cubicweb.org/project/
--- a/doc/book/en/makefile Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/en/makefile Thu Feb 19 20:21:10 2009 +0100
@@ -43,7 +43,7 @@
#apydoc:
# epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py
apidoc:
- epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../
+ epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
# run sphinx ###
html:
--- a/doc/book/fr/makefile Thu Feb 19 20:19:05 2009 +0100
+++ b/doc/book/fr/makefile Thu Feb 19 20:21:10 2009 +0100
@@ -43,7 +43,7 @@
#apydoc:
# epydoc --html -o epydoc/ -n ../server/*.py ../core/*.py ../common/*.py ../server/*/*.py ../modpython/*/*.py ../common/*/*.py
apidoc:
- epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../
+ epydoc --html -o apidoc -n "cubicweb" --exclude=setup --exclude=__pkginfo__ ../../../
# run sphinx ###
html:
--- a/entities/authobjs.py Thu Feb 19 20:19:05 2009 +0100
+++ b/entities/authobjs.py Thu Feb 19 20:21:10 2009 +0100
@@ -1,3 +1,10 @@
+"""entity classes user and group entities
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
from logilab.common.decorators import cached
from cubicweb import Unauthorized
@@ -26,6 +33,7 @@
'in_group' : 'primary',
('owned_by', '*', 'object') : ('generated', 'link'),
('created_by','*','object') : ('generated', 'link'),
+ ('bookmarked_by', '*', 'object'): ('generated', 'create'),
}
# used by repository to check if the user can log in or not
@@ -85,6 +93,13 @@
"""
return self.matching_groups(group) == 1
+ def is_anonymous(self):
+ """ checks if user is an anonymous user"""
+ #FIXME on the web-side anonymous user is detected according
+ # to config['anonymous-user'], we don't have this info on
+ # the server side.
+ return self.groups == frozenset(('guests', ))
+
def owns(self, eid):
if hasattr(self.req, 'unsafe_execute'):
# use unsafe_execute on the repository side, in case
--- a/entities/lib.py Thu Feb 19 20:19:05 2009 +0100
+++ b/entities/lib.py Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
"""entity classes for optional library entities
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
--- a/goa/test/unittest_editcontroller.py Thu Feb 19 20:19:05 2009 +0100
+++ b/goa/test/unittest_editcontroller.py Thu Feb 19 20:21:10 2009 +0100
@@ -17,7 +17,7 @@
config.global_set_option('use-google-auth', False)
config.global_set_option('schema-type', 'yams')
config.global_set_option('included-cubes', ())
- config.global_set_option('included-yams-cubes', ('eblog',))
+ config.global_set_option('included-yams-cubes', ('blog',))
MODEL_CLASSES = ()
from cubicweb.web.views import editcontroller
--- a/i18n/en.po Thu Feb 19 20:19:05 2009 +0100
+++ b/i18n/en.po Thu Feb 19 20:21:10 2009 +0100
@@ -376,6 +376,9 @@
msgid "Problem occured"
msgstr ""
+msgid "Project linked data"
+msgstr ""
+
msgid "RQLExpression"
msgstr "RQL expression"
@@ -717,6 +720,9 @@
msgid "add"
msgstr ""
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr "bookmark"
+
msgid "add EEType add_permission RQLExpression subject"
msgstr "rql expression for the add permission"
@@ -1311,6 +1317,9 @@
msgid "created_by_object"
msgstr "has created"
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr "creating bookmark for %(linkto)s"
+
msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
msgstr "creating constraint for attribute %(linkto)s"
@@ -1668,12 +1677,18 @@
msgid "february"
msgstr ""
+msgid "file tree view"
+msgstr ""
+
msgid "final"
msgstr ""
msgid "firstname"
msgstr ""
+msgid "foaf"
+msgstr ""
+
msgid "follow"
msgstr ""
@@ -1997,6 +2012,9 @@
msgid "list"
msgstr ""
+msgid "loading"
+msgstr ""
+
msgid "log in"
msgstr ""
@@ -2025,6 +2043,9 @@
msgid "manage bookmarks"
msgstr ""
+msgid "manage permissions"
+msgstr ""
+
msgid "manage security"
msgstr ""
@@ -2137,6 +2158,9 @@
msgid "not authorized"
msgstr ""
+msgid "not selected"
+msgstr ""
+
msgid "not specified"
msgstr ""
@@ -2173,6 +2197,15 @@
msgid "ordernum"
msgstr "order"
+msgid "owl (tbox+abox)"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
+msgid "owlaboxlight"
+msgstr ""
+
msgid "owned_by"
msgstr "owned by"
@@ -2416,6 +2449,9 @@
msgid "select this entity"
msgstr ""
+msgid "selected"
+msgstr ""
+
msgid "semantic description of this attribute"
msgstr ""
@@ -2541,6 +2577,9 @@
msgid "task progression"
msgstr ""
+msgid "tbox"
+msgstr ""
+
msgid "text"
msgstr ""
@@ -2617,6 +2656,9 @@
msgid "transition_of_object"
msgstr "use transitions"
+msgid "tree view"
+msgstr ""
+
msgid "tuesday"
msgstr ""
--- a/i18n/es.po Thu Feb 19 20:19:05 2009 +0100
+++ b/i18n/es.po Thu Feb 19 20:21:10 2009 +0100
@@ -381,6 +381,9 @@
msgid "Problem occured"
msgstr "Ha ocurrido un error"
+msgid "Project linked data"
+msgstr ""
+
msgid "RQLExpression"
msgstr "Expresión RQL"
@@ -738,6 +741,9 @@
msgid "add"
msgstr "agregar"
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr ""
+
msgid "add EEType add_permission RQLExpression subject"
msgstr "Definir una expresión RQL de agregación"
@@ -1359,6 +1365,9 @@
msgid "created_by_object"
msgstr "ha creado"
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr ""
+
msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
msgstr "creación condicionada por el atributo %(linkto)s"
@@ -1745,12 +1754,18 @@
msgid "february"
msgstr "febrero"
+msgid "file tree view"
+msgstr ""
+
msgid "final"
msgstr "final"
msgid "firstname"
msgstr "nombre"
+msgid "foaf"
+msgstr ""
+
msgid "follow"
msgstr "seguir la liga"
@@ -2090,6 +2105,9 @@
msgid "list"
msgstr "liste"
+msgid "loading"
+msgstr ""
+
msgid "log in"
msgstr "s'identifier"
@@ -2118,6 +2136,9 @@
msgid "manage bookmarks"
msgstr "gÈrer les signets"
+msgid "manage permissions"
+msgstr ""
+
msgid "manage security"
msgstr "gestion de la sÈcuritÈ"
@@ -2232,6 +2253,9 @@
msgid "not authorized"
msgstr "non autorisÈ"
+msgid "not selected"
+msgstr ""
+
msgid "not specified"
msgstr "non spÈcifiÈ"
@@ -2268,6 +2292,15 @@
msgid "ordernum"
msgstr "ordre"
+msgid "owl (tbox+abox)"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
+msgid "owlaboxlight"
+msgstr ""
+
msgid "owned_by"
msgstr "appartient ‡"
@@ -2521,6 +2554,9 @@
msgid "select this entity"
msgstr "sÈlectionner cette entitÈ"
+msgid "selected"
+msgstr ""
+
msgid "semantic description of this attribute"
msgstr "description sÈmantique de cet attribut"
@@ -2649,6 +2685,9 @@
msgid "task progression"
msgstr "avancement de la t‚che"
+msgid "tbox"
+msgstr ""
+
msgid "text"
msgstr "text"
@@ -2726,6 +2765,9 @@
msgid "transition_of_object"
msgstr "a pour transition"
+msgid "tree view"
+msgstr ""
+
msgid "tuesday"
msgstr "mardi"
--- a/i18n/fr.po Thu Feb 19 20:19:05 2009 +0100
+++ b/i18n/fr.po Thu Feb 19 20:21:10 2009 +0100
@@ -381,6 +381,9 @@
msgid "Problem occured"
msgstr "Une erreur est survenue"
+msgid "Project linked data"
+msgstr ""
+
msgid "RQLExpression"
msgstr "Expression RQL"
@@ -740,6 +743,9 @@
msgid "add"
msgstr "ajouter"
+msgid "add Bookmark bookmarked_by EUser object"
+msgstr "signet"
+
msgid "add EEType add_permission RQLExpression subject"
msgstr "définir une expression RQL d'ajout"
@@ -1197,7 +1203,7 @@
msgstr "la barre de requête rql, dans l'en-tête de page"
msgid "components_rss_feed_url"
-msgstr ""
+msgstr "syndication rss"
msgid "components_rss_feed_url_description"
msgstr ""
@@ -1361,14 +1367,17 @@
msgid "created_by_object"
msgstr "a créé"
+msgid "creating Bookmark (Bookmark bookmarked_by EUser %(linkto)s)"
+msgstr "création d'un signet pour %(linkto)s"
+
msgid "creating EConstraint (EFRDef %(linkto)s constrained_by EConstraint)"
-msgstr "création contrainte pour l'attribut %(linkto)s"
+msgstr "création d'une contrainte pour l'attribut %(linkto)s"
msgid "creating EConstraint (ENFRDef %(linkto)s constrained_by EConstraint)"
-msgstr "création contrainte pour la relation %(linkto)s"
+msgstr "création d'une contrainte pour la relation %(linkto)s"
msgid "creating EFRDef (EFRDef relation_type ERType %(linkto)s)"
-msgstr "création attribut %(linkto)s"
+msgstr "création d'un attribut %(linkto)s"
msgid "creating ENFRDef (ENFRDef relation_type ERType %(linkto)s)"
msgstr "création relation %(linkto)s"
@@ -1744,12 +1753,18 @@
msgid "february"
msgstr "février"
+msgid "file tree view"
+msgstr "arborescence (fichiers)"
+
msgid "final"
msgstr "final"
msgid "firstname"
msgstr "prénom"
+msgid "foaf"
+msgstr "foaf"
+
msgid "follow"
msgstr "suivre le lien"
@@ -2091,6 +2106,9 @@
msgid "list"
msgstr "liste"
+msgid "loading"
+msgstr "chargement"
+
msgid "log in"
msgstr "s'identifier"
@@ -2119,6 +2137,9 @@
msgid "manage bookmarks"
msgstr "gérer les signets"
+msgid "manage permissions"
+msgstr "gestion des permissions"
+
msgid "manage security"
msgstr "gestion de la sécurité"
@@ -2233,6 +2254,9 @@
msgid "not authorized"
msgstr "non autorisé"
+msgid "not selected"
+msgstr "non sélectionné"
+
msgid "not specified"
msgstr "non spécifié"
@@ -2269,6 +2293,15 @@
msgid "ordernum"
msgstr "ordre"
+msgid "owl (tbox+abox)"
+msgstr ""
+
+msgid "owlabox"
+msgstr ""
+
+msgid "owlaboxlight"
+msgstr ""
+
msgid "owned_by"
msgstr "appartient à"
@@ -2522,6 +2555,9 @@
msgid "select this entity"
msgstr "sélectionner cette entité"
+msgid "selected"
+msgstr "sélectionné"
+
msgid "semantic description of this attribute"
msgstr "description sémantique de cet attribut"
@@ -2650,6 +2686,9 @@
msgid "task progression"
msgstr "avancement de la tâche"
+msgid "tbox"
+msgstr ""
+
msgid "text"
msgstr "text"
@@ -2727,6 +2766,9 @@
msgid "transition_of_object"
msgstr "a pour transition"
+msgid "tree view"
+msgstr "arborescence"
+
msgid "tuesday"
msgstr "mardi"
--- a/interfaces.py Thu Feb 19 20:19:05 2009 +0100
+++ b/interfaces.py Thu Feb 19 20:21:10 2009 +0100
@@ -238,3 +238,7 @@
def rss_feed_url(self):
"""return an url which layout sub-entities item
"""
+class ISIOC(Interface):
+ """interface for entities with sioc views"""
+
+
--- a/rset.py Thu Feb 19 20:19:05 2009 +0100
+++ b/rset.py Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
"""The `ResultSet` class which is returned as result of a rql query
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
@@ -60,11 +60,15 @@
def __repr__(self):
if not self.rows:
return '<empty resultset for %r>' % self.rql
+ rows = self.rows
+ if len(rows) > 10:
+ rows = rows[:10] + ['...']
if not self.description:
- return '<resultset %r: %s>' % (self.rql, '\n'.join(str(r) for r in self.rows))
- return '<resultset %r: %s>' % (self.rql,
- '\n'.join('%s (%s)' % (r, d)
- for r, d in zip(self.rows, self.description)))
+ return '<resultset %r (%s rows): %s>' % (self.rql, len(self.rows),
+ '\n'.join(str(r) for r in rows))
+ return '<resultset %r (%s rows): %s>' % (self.rql, len(self.rows),
+ '\n'.join('%s (%s)' % (r, d)
+ for r, d in zip(rows, self.description)))
@cached
def possible_actions(self):
@@ -464,7 +468,8 @@
rqlst = self.syntax_tree()
etype = self.description[row][col]
if self.vreg.schema.eschema(etype).is_final():
- # final type, find a better (ambiguous) one
+ # final type, find a better one to locate the correct subquery
+ # (ambiguous if possible)
for i in xrange(len(rqlst.children[0].selection)):
if i == col:
continue
@@ -476,18 +481,17 @@
locate_query_col = i
if len(self.column_types(i)) > 1:
break
- # UNION query, find the subquery from which this entity has been
- # found
+ # UNION query, find the subquery from which this entity has been found
select = rqlst.locate_subquery(locate_query_col, etype, self.args)
try:
myvar = select.selection[col].variable
except AttributeError:
- # no .selection attribute is available
+ # not a variable
return None, None
rel = myvar.main_relation()
if rel is not None:
index = rel.children[0].variable.selected_index()
- if index is not None:
+ if index is not None and self.rows[row][index]:
return self.get_entity(row, index), rel.r_type
return None, None
--- a/server/migractions.py Thu Feb 19 20:19:05 2009 +0100
+++ b/server/migractions.py Thu Feb 19 20:21:10 2009 +0100
@@ -264,13 +264,15 @@
self.commit()
def cmd_add_cube(self, cube, update_database=True):
+ self.cmd_add_cubes( (cube,), update_database)
+
+ def cmd_add_cubes(self, cubes, update_database=True):
"""update_database is telling if the database schema should be updated
or if only the relevant eproperty should be inserted (for the case where
a cube has been extracted from an existing application, so the
cube schema is already in there)
"""
- newcubes = super(ServerMigrationHelper, self).cmd_add_cube(
- cube)
+ newcubes = super(ServerMigrationHelper, self).cmd_add_cubes(cubes)
if not newcubes:
return
for pack in newcubes:
@@ -279,22 +281,22 @@
if not update_database:
self.commit()
return
- self.new_schema = self.config.load_schema()
+ with_new_cubes = self.config.load_schema()
new = set()
# execute pre-create files
for pack in reversed(newcubes):
self.exec_event_script('precreate', self.config.cube_dir(pack))
# add new entity and relation types
- for rschema in self.new_schema.relations():
+ for rschema in with_new_cubes.relations():
if not rschema in self.repo.schema:
self.cmd_add_relation_type(rschema.type)
new.add(rschema.type)
- for eschema in self.new_schema.entities():
+ for eschema in with_new_cubes.entities():
if not eschema in self.repo.schema:
self.cmd_add_entity_type(eschema.type)
new.add(eschema.type)
# check if attributes has been added to existing entities
- for rschema in self.new_schema.relations():
+ for rschema in with_new_cubes.relations():
existingschema = self.repo.schema.rschema(rschema.type)
for (fromtype, totype) in rschema.iter_rdefs():
if existingschema.has_rdef(fromtype, totype):
--- a/server/repository.py Thu Feb 19 20:19:05 2009 +0100
+++ b/server/repository.py Thu Feb 19 20:21:10 2009 +0100
@@ -490,7 +490,7 @@
session = self.internal_session()
try:
if session.execute('EUser X WHERE X login %(login)s', {'login': login}):
- return
+ return False
# we have to create the user
user = self.vreg.etype_class('EUser')(session, None)
if isinstance(password, unicode):
@@ -505,6 +505,7 @@
session.commit()
finally:
session.close()
+ return True
def connect(self, login, password, cnxprops=None):
"""open a connection for a given user
--- a/server/rqlannotation.py Thu Feb 19 20:19:05 2009 +0100
+++ b/server/rqlannotation.py Thu Feb 19 20:21:10 2009 +0100
@@ -146,16 +146,17 @@
class CantSelectPrincipal(Exception): pass
-def _select_principal(sqlscope, relations):
+def _select_principal(sqlscope, relations, _sort=lambda x:x):
"""given a list of rqlst relations, select one which will be used to
represent an invariant variable (e.g. using on extremity of the relation
instead of the variable's type table
"""
+ # _sort argument is there for test
diffscope_rels = {}
has_same_scope_rel = False
ored_rels = set()
diffscope_rels = set()
- for rel in relations:
+ for rel in _sort(relations):
# note: only eid and has_text among all final relations may be there
if rel.r_type in ('eid', 'identity'):
has_same_scope_rel = rel.sqlscope is sqlscope
@@ -175,18 +176,17 @@
if isinstance(common_parent(rel1, rel2), Or):
ored_rels.discard(rel1)
ored_rels.discard(rel2)
- for rel in ored_rels:
+ for rel in _sort(ored_rels):
if rel.sqlscope is sqlscope:
return rel
diffscope_rels.add(rel)
# if DISTINCT query, can use variable from a different scope as principal
# since introduced duplicates will be removed
if sqlscope.stmt.distinct and diffscope_rels:
- return iter(diffscope_rels).next()
+ return iter(_sort(diffscope_rels)).next()
# XXX could use a relation for a different scope if it can't generate
# duplicates, so we would have to check cardinality
- raise CantSelectPrincipal()
-
+ raise CantSelectPrincipal()
def _select_main_var(relations):
"""given a list of rqlst relations, select one which will be used as main
--- a/server/session.py Thu Feb 19 20:19:05 2009 +0100
+++ b/server/session.py Thu Feb 19 20:21:10 2009 +0100
@@ -21,6 +21,18 @@
from cubicweb.common.utils import make_uid
from cubicweb.server.rqlrewrite import RQLRewriter
+_ETYPE_PYOBJ_MAP = { bool: 'Boolean',
+ int: 'Int',
+ long: 'Int',
+ float: 'Float',
+ Decimal: 'Decimal',
+ unicode: 'String',
+ NoneType: None,
+ Binary: 'Bytes',
+ DateTimeType: 'Datetime',
+ DateTimeDeltaType: 'Interval',
+ }
+
def etype_from_pyobj(value):
"""guess yams type from python value"""
# note:
@@ -28,17 +40,7 @@
# * use type(value) and not value.__class__ since mx instances have no
# __class__ attribute
# * XXX Date, Time
- return {bool: 'Boolean',
- int: 'Int',
- long: 'Int',
- float: 'Float',
- Decimal: 'Decimal',
- unicode: 'String',
- NoneType: None,
- Binary: 'Bytes',
- DateTimeType: 'Datetime',
- DateTimeDeltaType: 'Interval',
- }[type(value)]
+ return _ETYPE_PYOBJ_MAP[type(value)]
def is_final(rqlst, variable, args):
# try to find if this is a final var or not
@@ -58,35 +60,8 @@
description.append(term.get_type(solution, args))
return description
-#XXX rql <= 0.18.3 bw compat
from rql import stmts
-if not hasattr(stmts.Union, 'get_variable_variables'):
- def _union_get_variable_variables(self):
- """return the set of variable names which take different type according to
- the solution
- """
- change = set()
- values = {}
- for select in self.children:
- change.update(select.get_variable_variables(values))
- return change
- stmts.Union.get_variable_variables = _union_get_variable_variables
-
- def _select_get_variable_variables(self, _values=None):
- """return the set of variable names which take different type according to
- the solution
- """
- change = set()
- if _values is None:
- _values = {}
- for solution in self.solutions:
- for vname, etype in solution.iteritems():
- if not vname in _values:
- _values[vname] = etype
- elif _values[vname] != etype:
- change.add(vname)
- return change
- stmts.Select.get_variable_variables = _select_get_variable_variables
+assert hasattr(stmts.Union, 'get_variable_variables'), "You need RQL > 0.18.3"
class Session(RequestSessionMixIn):
"""tie session id, user, connections pool and other session data all
--- a/server/test/unittest_rql2sql.py Thu Feb 19 20:19:05 2009 +0100
+++ b/server/test/unittest_rql2sql.py Thu Feb 19 20:21:10 2009 +0100
@@ -805,7 +805,7 @@
'F name "read", F require_group E, U in_group E)), U eid 1',
'''SELECT A.eid, rel_documented_by0.eid_to
FROM Affaire AS A LEFT OUTER JOIN documented_by_relation AS rel_documented_by0 ON (rel_documented_by0.eid_from=A.eid)
-WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_from=1 AND rel_in_group3.eid_to=rel_require_group2.eid_to)))'''),
+WHERE ((rel_documented_by0.eid_to IS NULL) OR (EXISTS(SELECT 1 FROM require_permission_relation AS rel_require_permission1, EPermission AS F, require_group_relation AS rel_require_group2, in_group_relation AS rel_in_group3 WHERE rel_documented_by0.eid_to=rel_require_permission1.eid_from AND rel_require_permission1.eid_to=F.eid AND F.name=read AND rel_require_group2.eid_from=F.eid AND rel_in_group3.eid_to=rel_require_group2.eid_to AND rel_in_group3.eid_from=1)))'''),
("Any X WHERE X eid 12, P? connait X",
'''SELECT X.eid
--- a/test/unittest_rset.py Thu Feb 19 20:19:05 2009 +0100
+++ b/test/unittest_rset.py Thu Feb 19 20:21:10 2009 +0100
@@ -300,7 +300,13 @@
attr = etype == 'Bookmark' and 'title' or 'name'
self.assertEquals(entity[attr], n)
-
+ def test_related_entity_optional(self):
+ e = self.add_entity('Bookmark', title=u'aaaa', path=u'path')
+ rset = self.execute('Any B,U,L WHERE B bookmarked_by U?, U login L')
+ entity, rtype = rset.related_entity(0, 2)
+ self.assertEquals(entity, None)
+ self.assertEquals(rtype, None)
+
def test_related_entity_union_subquery(self):
e = self.add_entity('Bookmark', title=u'aaaa', path=u'path')
rset = self.execute('Any X,N ORDERBY N WITH X,N BEING '
--- a/vregistry.py Thu Feb 19 20:19:05 2009 +0100
+++ b/vregistry.py Thu Feb 19 20:21:10 2009 +0100
@@ -20,7 +20,7 @@
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
@@ -105,7 +105,10 @@
"can't be used together")
if '__select__' not in classdict and '__selectors__' in classdict:
selectors = classdict['__selectors__']
- classdict['__select__'] = classmethod(chainall(*selectors))
+ if len(selectors) > 1:
+ classdict['__select__'] = classmethod(chainall(*selectors))
+ else:
+ classdict['__select__'] = classmethod(selectors[0])
return super(autoselectors, mcs).__new__(mcs, name, bases, classdict)
def __setattr__(self, attr, value):
--- a/web/application.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/application.py Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
"""CubicWeb web client application object
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
@@ -317,6 +317,7 @@
try:
ctrlid, rset = self.url_resolver.process(req, path)
controller = self.select_controller(ctrlid, req)
+ req.update_search_state()
result = controller.publish(rset=rset)
if req.cnx is not None:
# req.cnx is None if anonymous aren't allowed and we are
--- a/web/component.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/component.py Thu Feb 19 20:21:10 2009 +0100
@@ -73,6 +73,19 @@
selected_page_link_templ = u'<span class="selectedSlice"><a href="%s" title="%s">%s</a></span>'
previous_page_link_templ = next_page_link_templ = page_link_templ
no_previous_page_link = no_next_page_link = u''
+
+ @classmethod
+ def selected(cls, req, rset, row=None, col=None, page_size=None, **kwargs):
+ """by default web app objects are usually instantiated on
+ selection according to a request, a result set, and optional
+ row and col
+ """
+ instance = super(NavigationComponent, cls).selected(req, rset, row, col, **kwargs)
+ if page_size is not None:
+ instance.page_size = page_size
+ elif 'page_size' in req.form:
+ instance.page_size = int(req.form['page_size'])
+ return instance
def __init__(self, req, rset):
super(NavigationComponent, self).__init__(req, rset)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/data/cubicweb.preferences.js Thu Feb 19 20:21:10 2009 +0100
@@ -0,0 +1,10 @@
+/* toggle visibility of an element by its id
+ * & set current visibility status in a cookie
+ * XXX whenever used outside of preferences, don't forget to
+ * move me in a more appropriate place
+ */
+function toggle_and_remember_visibility(elemId, cookiename) {
+ jqNode(elemId).toggleClass('hidden');
+ async_remote_exec('set_cookie', cookiename,
+ jQuery('#' + elemId).attr('class'));
+}
--- a/web/data/cubicweb.tabs.js Thu Feb 19 20:19:05 2009 +0100
+++ b/web/data/cubicweb.tabs.js Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,6 @@
-function set_tab(tabname) {
+function set_tab(tabname, cookiename) {
// set appropriate cookie
- // XXX see if we can no just do it with jQuery
- async_remote_exec('remember_active_tab', tabname);
+ async_remote_exec('set_cookie', cookiename, tabname);
// trigger show + tabname event
trigger_load(tabname);
}
--- a/web/data/jquery.corner.js Thu Feb 19 20:19:05 2009 +0100
+++ b/web/data/jquery.corner.js Thu Feb 19 20:21:10 2009 +0100
@@ -1,1 +1,178 @@
-if(!document.createElement('canvas').getContext){(function(){var m=Math;var y=m.round;var z=m.sin;var A=m.cos;var Z=10;var B=Z/2;function getContext(){if(this.context_){return this.context_}return this.context_=new CanvasRenderingContext2D_(this)}var C=Array.prototype.slice;function bind(f,b,c){var a=C.call(arguments,2);return function(){return f.apply(b,a.concat(C.call(arguments)))}}var D={init:function(a){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var b=a||document;b.createElement('canvas');b.attachEvent('onreadystatechange',bind(this.init_,this,b))}},init_:function(a){if(!a.namespaces['g_vml_']){a.namespaces.add('g_vml_','urn:schemas-microsoft-com:vml')}if(!a.styleSheets['ex_canvas_']){var b=a.createStyleSheet();b.owningElement.id='ex_canvas_';b.cssText='canvas{display:inline-block;overflow:hidden;'+'text-align:left;width:300px;height:150px}'+'g_vml_\\:*{behavior:url(#default#VML)}'}},i:function(a){if(!a.getContext){a.getContext=getContext;a.attachEvent('onpropertychange',onPropertyChange);a.attachEvent('onresize',onResize);var b=a.attributes;if(b.width&&b.width.specified){a.style.width=b.width.nodeValue+'px'}else{a.width=a.clientWidth}if(b.height&&b.height.specified){a.style.height=b.height.nodeValue+'px'}else{a.height=a.clientHeight}}return a}};function onPropertyChange(e){var a=e.srcElement;switch(e.propertyName){case'width':a.style.width=a.attributes.width.nodeValue+'px';a.getContext().clearRect();break;case'height':a.style.height=a.attributes.height.nodeValue+'px';a.getContext().clearRect();break}}function onResize(e){var a=e.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+'px';a.firstChild.style.height=a.clientHeight+'px'}}D.init();var E=[];for(var i=0;i<16;i++){for(var j=0;j<16;j++){E[i*16+j]=i.toString(16)+j.toString(16)}}function createMatrixIdentity(){return[[1,0,0],[0,1,0],[0,0,1]]}function processStyle(a){var b,alpha=1;a=String(a);if(a.substring(0,3)=='rgb'){var c=a.indexOf('(',3);var d=a.indexOf(')',c+1);var e=a.substring(c+1,d).split(',');b='#';for(var i=0;i<3;i++){b+=E[Number(e[i])]}if(e.length==4&&a.substr(3,1)=='a'){alpha=e[3]}}else{b=a}return[b,alpha]}function processLineCap(a){switch(a){case'butt':return'flat';case'round':return'round';case'square':default:return'square'}}function CanvasRenderingContext2D_(a){this.m_=createMatrixIdentity();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.strokeStyle='#000';this.fillStyle='#000';this.lineWidth=1;this.lineJoin='miter';this.lineCap='butt';this.miterLimit=Z*1;this.globalAlpha=1;this.canvas=a;var b=a.ownerDocument.createElement('div');b.style.width=a.clientWidth+'px';b.style.height=a.clientHeight+'px';b.style.overflow='hidden';b.style.position='absolute';a.appendChild(b);this.element_=b;this.arcScaleX_=1;this.arcScaleY_=1}var F=CanvasRenderingContext2D_.prototype;F.clearRect=function(){this.element_.innerHTML='';this.currentPath_=[]};F.beginPath=function(){this.currentPath_=[]};F.moveTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'moveTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.lineTo=function(a,b){var p=this.getCoords_(a,b);this.currentPath_.push({type:'lineTo',x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.bezierCurveTo=function(a,b,c,d,e,f){var p=this.getCoords_(e,f);var g=this.getCoords_(a,b);var h=this.getCoords_(c,d);this.currentPath_.push({type:'bezierCurveTo',cp1x:g.x,cp1y:g.y,cp2x:h.x,cp2y:h.y,x:p.x,y:p.y});this.currentX_=p.x;this.currentY_=p.y};F.fillRect=function(a,b,c,d){this.beginPath();this.moveTo(a,b);this.lineTo(a+c,b);this.lineTo(a+c,b+d);this.lineTo(a,b+d);this.closePath();this.fill();this.currentPath_=[]};F.createLinearGradient=function(a,b,c,d){return new CanvasGradient_('gradient')};F.createRadialGradient=function(a,b,c,d,e,f){var g=new CanvasGradient_('gradientradial');g.radius1_=c;g.radius2_=f;g.focus_.x=a;g.focus_.y=b;return g};F.stroke=function(d){var e=[];var f=false;var a=processStyle(d?this.fillStyle:this.strokeStyle);var g=a[0];var h=a[1]*this.globalAlpha;var W=10;var H=10;e.push('<g_vml_:shape',' fillcolor="',g,'"',' filled="',Boolean(d),'"',' style="position:absolute;width:',W,';height:',H,';"',' coordorigin="0 0" coordsize="',Z*W,' ',Z*H,'"',' stroked="',!d,'"',' strokeweight="',this.lineWidth,'"',' strokecolor="',g,'"',' path="');var j=false;var k={x:null,y:null};var l={x:null,y:null};for(var i=0;i<this.currentPath_.length;i++){var p=this.currentPath_[i];var c;switch(p.type){case'moveTo':e.push(' m ');c=p;e.push(y(p.x),',',y(p.y));break;case'lineTo':e.push(' l ');e.push(y(p.x),',',y(p.y));break;case'close':e.push(' x ');p=null;break;case'bezierCurveTo':e.push(' c ');e.push(y(p.cp1x),',',y(p.cp1y),',',y(p.cp2x),',',y(p.cp2y),',',y(p.x),',',y(p.y));break;case'at':case'wa':e.push(' ',p.type,' ');e.push(y(p.x-this.arcScaleX_*p.radius),',',y(p.y-this.arcScaleY_*p.radius),' ',y(p.x+this.arcScaleX_*p.radius),',',y(p.y+this.arcScaleY_*p.radius),' ',y(p.xStart),',',y(p.yStart),' ',y(p.xEnd),',',y(p.yEnd));break}if(p){if(k.x==null||p.x<k.x){k.x=p.x}if(l.x==null||p.x>l.x){l.x=p.x}if(k.y==null||p.y<k.y){k.y=p.y}if(l.y==null||p.y>l.y){l.y=p.y}}}e.push(' ">');if(typeof this.fillStyle=='object'){var m={x:'50%',y:'50%'};var n=l.x-k.x;var o=l.y-k.y;var q=n>o?n:o;m.x=y(this.fillStyle.focus_.x/n*100+50)+'%';m.y=y(this.fillStyle.focus_.y/o*100+50)+'%';var r=[];if(this.fillStyle.type_=='gradientradial'){var s=this.fillStyle.radius1_/q*100;var t=this.fillStyle.radius2_/q*100-s}else{var s=0;var t=100}var u={offset:null,color:null};var v={offset:null,color:null};this.fillStyle.colors_.sort(function(a,b){return a.offset-b.offset});for(var i=0;i<this.fillStyle.colors_.length;i++){var w=this.fillStyle.colors_[i];r.push(w.offset*t+s,'% ',w.color,',');if(w.offset>u.offset||u.offset==null){u.offset=w.offset;u.color=w.color}if(w.offset<v.offset||v.offset==null){v.offset=w.offset;v.color=w.color}}r.pop();e.push('<g_vml_:fill',' color="',v.color,'"',' color2="',u.color,'"',' type="',this.fillStyle.type_,'"',' focusposition="',m.x,', ',m.y,'"',' colors="',r.join(''),'"',' opacity="',h,'" />')}else if(d){e.push('<g_vml_:fill color="',g,'" opacity="',h,'" />')}else{var x=Math.max(this.arcScaleX_,this.arcScaleY_)*this.lineWidth;e.push('<g_vml_:stroke',' opacity="',h,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',processLineCap(this.lineCap),'"',' weight="',x,'px"',' color="',g,'" />')}e.push('</g_vml_:shape>');this.element_.insertAdjacentHTML('beforeEnd',e.join(''))};F.fill=function(){this.stroke(true)};F.closePath=function(){this.currentPath_.push({type:'close'})};F.getCoords_=function(a,b){return{x:Z*(a*this.m_[0][0]+b*this.m_[1][0]+this.m_[2][0])-B,y:Z*(a*this.m_[0][1]+b*this.m_[1][1]+this.m_[2][1])-B}};function CanvasPattern_(){}G_vmlCMjrc=D})()}if(jQuery.browser.msie){document.execCommand("BackgroundImageCache",false,true)}(function($){var N=$.browser.msie;var O=N&&!window.XMLHttpRequest;var P=$.browser.opera;var Q=typeof document.createElement('canvas').getContext=="function";var R=function(i){return parseInt(i,10)||0};var S=function(a,b,c){var x=a,y;if(x.currentStyle){y=x.currentStyle[b]}else if(window.getComputedStyle){if(typeof arguments[2]=="string")b=c;y=document.defaultView.getComputedStyle(x,null).getPropertyValue(b)}return y};var T=function(a,p){return S(a,'border'+p+'Color','border-'+p.toLowerCase()+'-color')};var U=function(a,p){if(a.currentStyle&&!P){w=a.currentStyle['border'+p+'Width'];if(w=='thin')w=2;if(w=='medium'&&!(a.currentStyle['border'+p+'Style']=='none'))w=4;if(w=='thick')w=6}else{p=p.toLowerCase();w=document.defaultView.getComputedStyle(a,null).getPropertyValue('border-'+p+'-width')}return R(w)};var V=function(a,i){return a.tagName.toLowerCase()==i};var W=function(e,a,b,c,d){if(e=='tl')return a;if(e=='tr')return b;if(e=='bl')return c;if(e=='br')return d};var X=function(a,b,c,d,e,f,g){var h,curve_to;if(d.indexOf('rgba')!=-1){var i=/^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/;var j=i.exec(d);if(j){var k=[R(j[1]),R(j[2]),R(j[3])];d='rgb('+k[0]+', '+k[1]+', '+k[2]+')'}}var l=a.getContext('2d');if(b==1||g=='notch'){if(e>0&&b>1){l.fillStyle=f;l.fillRect(0,0,b,b);l.fillStyle=d;h=W(c,[0-e,0-e],[e,0-e],[0-e,e],[e,e]);l.fillRect(h[0],h[1],b,b)}else{l.fillStyle=d;l.fillRect(0,0,b,b)}return a}else if(g=='bevel'){h=W(c,[0,0,0,b,b,0,0,0],[0,0,b,b,b,0,0,0],[0,0,b,b,0,b,0,0],[b,b,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.lineTo(h[4],h[5]);l.lineTo(h[6],h[7]);l.fill();if(e>0&&e<b){l.strokeStyle=f;l.lineWidth=e;l.beginPath();h=W(c,[0,b,b,0],[0,0,b,b],[b,b,0,0],[0,b,b,0]);l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);l.stroke()}return a}h=W(c,[0,0,b,0,b,0,0,b,0,0],[b,0,b,b,b,0,0,0,0,0],[0,b,b,b,0,b,0,0,0,b],[b,b,b,0,b,0,0,b,b,b]);l.fillStyle=d;l.beginPath();l.moveTo(h[0],h[1]);l.lineTo(h[2],h[3]);if(c=='br')l.bezierCurveTo(h[4],h[5],b,b,h[6],h[7]);else l.bezierCurveTo(h[4],h[5],0,0,h[6],h[7]);l.lineTo(h[8],h[9]);l.fill();if(e>0&&e<b){var m=e/2;var n=b-m;h=W(c,[n,m,n,m,m,n],[n,n,n,m,m,m],[n,n,m,n,m,m,m,n],[n,m,n,m,m,n,n,n]);curve_to=W(c,[0,0],[0,0],[0,0],[b,b]);l.strokeStyle=f;l.lineWidth=e;l.beginPath();l.moveTo(h[0],h[1]);l.bezierCurveTo(h[2],h[3],curve_to[0],curve_to[1],h[4],h[5]);l.stroke()}return a};var Y=function(p,a){var b=document.createElement('canvas');b.setAttribute("height",a);b.setAttribute("width",a);b.style.display="block";b.style.position="absolute";b.className="jrCorner";Z(p,b);if(!Q&&N){if(typeof G_vmlCanvasManager=="object"){b=G_vmlCanvasManager.initElement(b)}else if(typeof G_vmlCMjrc=="object"){b=G_vmlCMjrc.i(b)}else{throw Error('Could not find excanvas');}}return b};var Z=function(p,a){if(p.is("table")){p.children("tbody").children("tr:first").children("td:first").append(a);p.css('display','block')}else if(p.is("td")){if(p.children(".JrcTdContainer").length===0){p.html('<div class="JrcTdContainer" style="padding:0px;position:relative;margin:-1px;zoom:1;">'+p.html()+'</div>');p.css('zoom','1');if(O){p.children(".JrcTdContainer").get(0).style.setExpression("height","this.parentNode.offsetHeight")}}p.children(".JrcTdContainer").append(a)}else{p.append(a)}};if(N){var ba=document.createStyleSheet();ba.media='print';ba.cssText='.jrcIECanvasDiv { display:none !important; }'}var bb=function(D){if(this.length==0||!(Q||N)){return this}if(D=="destroy"){return this.each(function(){var p,elm=$(this);if(elm.is(".jrcRounded")){if(typeof elm.data("ie6tmr.jrc")=='number')window.clearInterval(elm.data("ie6tmr.jrc"));if(elm.is("table"))p=elm.children("tbody").children("tr:first").children("td:first");else if(elm.is("td"))p=elm.children(".JrcTdContainer");else p=elm;p.children(".jrCorner").remove();elm.unbind('mouseleave.jrc').unbind('mouseenter.jrc').removeClass('jrcRounded').removeData('ie6tmr.jrc');if(elm.is("td"))elm.html(elm.children(".JrcTdContainer").html())}})}var o=(D||"").toLowerCase();var E=R((o.match(/(\d+)px/)||[])[1])||"auto";var F=((o.match(/(#[0-9a-f]+)/)||[])[1])||"auto";var G=/round|bevel|notch/;var H=((o.match(G)||['round'])[0]);var I=/hover/.test(o);var J=/oversized/.test(o);var K=o.match("hiddenparent");if(N){var G=/ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/;var L=((o.match(G)||['ie6fixinit'])[0])}var M={tl:/top|left|tl/.test(o),tr:/top|right|tr/.test(o),bl:/bottom|left|bl/.test(o),br:/bottom|right|br/.test(o)};if(!M.tl&&!M.tr&&!M.bl&&!M.br)M={tl:1,tr:1,bl:1,br:1};this.each(function(){var d=$(this),rbg=null,bg,s,b,pr;var a=this;var e=S(this,'display');var f=S(this,'position');var g=S(this,'lineHeight','line-height');if(F=="auto"){s=d.siblings(".jrcRounded:eq(0)");if(s.length>0){b=s.data("rbg.jrc");if(typeof b=="string"){rbg=b}}}if(K||rbg===null){var h=this.parentNode,hidden_parents=new Array(),a=0;while((typeof h=='object')&&!V(h,'html')){if(K&&S(h,'display')=='none'){hidden_parents.push({originalvisibility:S(h,'visibility'),elm:h});h.style.display='block';h.style.visibility='hidden'}var j=S(h,'backgroundColor','background-color');if(rbg===null&&j!="transparent"&&j!="rgba(0, 0, 0, 0)"){rbg=j}h=h.parentNode}if(rbg===null)rbg="#ffffff"}if(F=="auto"){bg=rbg;d.data("rbg.jrc",rbg)}else{bg=F}if(e=='none'){var k=S(this,'visibility');this.style.display='block';this.style.visibility='hidden';var l=true}else{var m=false}var n=d.height();var p=d.width();if(I){var q=o.replace(/hover|ie6nofix|ie6fixinit|ie6fixexpr|ie6fixonload|ie6fixwidthint|ie6fixheightint|ie6fixbothint/g,"");if(L!='ie6nofix')q="ie6fixinit "+q;d.bind("mouseenter.jrc",function(){d.addClass('jrcHover');d.corner(q)});d.bind("mouseleave.jrc",function(){d.removeClass('jrcHover');d.corner(q)})}if(O&&L!='ie6nofix'){this.style.zoom=1;if(L!='ie6fixexpr'){if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}$(window).load(function(){if(L=='ie6fixonload'){if(d.css('height')=='auto')d.height(d.css('height'));if(d.width()%2!=0)d.width(d.width()+1);if(d.height()%2!=0)d.height(d.height()+1)}else if(L=='ie6fixwidthint'||L=='ie6fixheightint'||L=='ie6fixbothint'){var c,ie6FixFunction;if(L=='ie6fixheightint'){ie6FixFunction=function(){d.height('auto');var a=d.height();if(a%2!=0)a=a+1;d.css({height:a})}}else if(L=='ie6fixwidthint'){ie6FixFunction=function(){d.width('auto');var a=d.width();if(a%2!=0)a=a+1;d.css({width:a});d.data('lastWidth.jrc',d.get(0).offsetWidth)}}else if(L=='ie6fixbothint'){ie6FixFunction=function(){d.width('auto');d.height('auto');var a=d.width();var b=d.height();if(b%2!=0)b=b+1;if(a%2!=0)a=a+1;d.css({width:a,height:b})}}c=window.setInterval(ie6FixFunction,100);d.data("ie6tmr.jrc",c)}})}var r=n<p?this.offsetHeight:this.offsetWidth;if(E=="auto"){E=r/2;if(E>10)E=r/4}if(E>r/2&&!J){E=r/2}E=Math.floor(E);var t=U(this,'Top');var u=U(this,'Right');var v=U(this,'Bottom');var w=U(this,'Left');if(f=='static'&&!V(this,'td')){this.style.position='relative'}else if(f=='fixed'&&N&&!(document.compatMode=='CSS1Compat'&&!O)){this.style.position='absolute'}if(t+u+v+w>0){this.style.overflow='visible'}if(l)d.css({display:'none',visibility:k});if(typeof hidden_parents!="undefined"){for(var i=0;i<hidden_parents.length;i++){hidden_parents[i].elm.style.display='none';hidden_parents[i].elm.style.visibility=hidden_parents[i].originalvisibility}}var x=0-t,p_right=0-u,p_bottom=0-v,p_left=0-w;var y=(d.find("canvas").length>0);if(y){if(V(this,'table'))pr=d.children("tbody").children("tr:first").children("td:first");else if(V(this,'td'))pr=d.children(".JrcTdContainer");else pr=d}if(M.tl){bordersWidth=t<w?t:w;if(y)pr.children("canvas.jrcTL").remove();var z=X(Y(d,E),E,'tl',bg,bordersWidth,T(this,'Top'),H);$(z).css({left:p_left,top:x}).addClass('jrcTL')}if(M.tr){bordersWidth=t<u?t:u;if(y)pr.children("canvas.jrcTR").remove();var A=X(Y(d,E),E,'tr',bg,bordersWidth,T(this,'Top'),H);$(A).css({right:p_right,top:x}).addClass('jrcTR')}if(M.bl){bordersWidth=v<w?v:w;if(y)pr.children("canvas.jrcBL").remove();var B=X(Y(d,E),E,'bl',bg,bordersWidth,T(this,'Bottom'),H);$(B).css({left:p_left,bottom:p_bottom}).addClass('jrcBL')}if(M.br){bordersWidth=v<u?v:u;if(y)pr.children("canvas.jrcBR").remove();var C=X(Y(d,E),E,'br',bg,bordersWidth,T(this,'Bottom'),H);$(C).css({right:p_right,bottom:p_bottom}).addClass('jrcBR')}if(N)d.children('canvas.jrCorner').children('div').addClass('jrcIECanvasDiv');if(O&&L=='ie6fixexpr'){if(M.bl){B.style.setExpression("bottom","this.parentNode.offsetHeight % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])+1)")}if(M.br){C.style.setExpression("right","this.parentNode.offsetWidth % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])+1)");C.style.setExpression("bottom","this.parentNode.offsetHeight % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderBottomWidth'])+1)")}if(M.tr){A.style.setExpression("right","this.parentNode.offsetWidth % 2 == 0 || this.parentNode.offsetWidth % 2 == 0 ? 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])) : 0-(parseInt(this.parentNode.currentStyle['borderRightWidth'])+1)")}}d.addClass('jrcRounded')});if(typeof arguments[1]=="function")arguments[1](this);return this};$.fn.corner=bb})(jQuery);
\ No newline at end of file
+/*
+ * jQuery corner plugin
+ *
+ * version 1.92 (12/18/2007)
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+/**
+ * The corner() method provides a simple way of styling DOM elements.
+ *
+ * corner() takes a single string argument: $().corner("effect corners width")
+ *
+ * effect: The name of the effect to apply, such as round or bevel.
+ * If you don't specify an effect, rounding is used.
+ *
+ * corners: The corners can be one or more of top, bottom, tr, tl, br, or bl.
+ * By default, all four corners are adorned.
+ *
+ * width: The width specifies the width of the effect; in the case of rounded corners this
+ * will be the radius of the width.
+ * Specify this value using the px suffix such as 10px, and yes it must be pixels.
+ *
+ * For more details see: http://methvin.com/jquery/jq-corner.html
+ * For a full demo see: http://malsup.com/jquery/corner/
+ *
+ *
+ * @example $('.adorn').corner();
+ * @desc Create round, 10px corners
+ *
+ * @example $('.adorn').corner("25px");
+ * @desc Create round, 25px corners
+ *
+ * @example $('.adorn').corner("notch bottom");
+ * @desc Create notched, 10px corners on bottom only
+ *
+ * @example $('.adorn').corner("tr dog 25px");
+ * @desc Create dogeared, 25px corner on the top-right corner only
+ *
+ * @example $('.adorn').corner("round 8px").parent().css('padding', '4px').corner("round 10px");
+ * @desc Create a rounded border effect by styling both the element and its parent
+ *
+ * @name corner
+ * @type jQuery
+ * @param String options Options which control the corner style
+ * @cat Plugins/Corner
+ * @return jQuery
+ * @author Dave Methvin (dave.methvin@gmail.com)
+ * @author Mike Alsup (malsup@gmail.com)
+ */
+(function($) {
+
+$.fn.corner = function(o) {
+ var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent);
+ function sz(el, p) { return parseInt($.css(el,p))||0; };
+ function hex2(s) {
+ var s = parseInt(s).toString(16);
+ return ( s.length < 2 ) ? '0'+s : s;
+ };
+ function gpc(node) {
+ for ( ; node && node.nodeName.toLowerCase() != 'html'; node = node.parentNode ) {
+ var v = $.css(node,'backgroundColor');
+ if ( v.indexOf('rgb') >= 0 ) {
+ if ($.browser.safari && v == 'rgba(0, 0, 0, 0)')
+ continue;
+ var rgb = v.match(/\d+/g);
+ return '#'+ hex2(rgb[0]) + hex2(rgb[1]) + hex2(rgb[2]);
+ }
+ if ( v && v != 'transparent' )
+ return v;
+ }
+ return '#ffffff';
+ };
+ function getW(i) {
+ switch(fx) {
+ case 'round': return Math.round(width*(1-Math.cos(Math.asin(i/width))));
+ case 'cool': return Math.round(width*(1+Math.cos(Math.asin(i/width))));
+ case 'sharp': return Math.round(width*(1-Math.cos(Math.acos(i/width))));
+ case 'bite': return Math.round(width*(Math.cos(Math.asin((width-i-1)/width))));
+ case 'slide': return Math.round(width*(Math.atan2(i,width/i)));
+ case 'jut': return Math.round(width*(Math.atan2(width,(width-i-1))));
+ case 'curl': return Math.round(width*(Math.atan(i)));
+ case 'tear': return Math.round(width*(Math.cos(i)));
+ case 'wicked': return Math.round(width*(Math.tan(i)));
+ case 'long': return Math.round(width*(Math.sqrt(i)));
+ case 'sculpt': return Math.round(width*(Math.log((width-i-1),width)));
+ case 'dog': return (i&1) ? (i+1) : width;
+ case 'dog2': return (i&2) ? (i+1) : width;
+ case 'dog3': return (i&3) ? (i+1) : width;
+ case 'fray': return (i%2)*width;
+ case 'notch': return width;
+ case 'bevel': return i+1;
+ }
+ };
+ o = (o||"").toLowerCase();
+ var keep = /keep/.test(o); // keep borders?
+ var cc = ((o.match(/cc:(#[0-9a-f]+)/)||[])[1]); // corner color
+ var sc = ((o.match(/sc:(#[0-9a-f]+)/)||[])[1]); // strip color
+ var width = parseInt((o.match(/(\d+)px/)||[])[1]) || 10; // corner width
+ var re = /round|bevel|notch|bite|cool|sharp|slide|jut|curl|tear|fray|wicked|sculpt|long|dog3|dog2|dog/;
+ var fx = ((o.match(re)||['round'])[0]);
+ var edges = { T:0, B:1 };
+ var opts = {
+ TL: /top|tl/.test(o), TR: /top|tr/.test(o),
+ BL: /bottom|bl/.test(o), BR: /bottom|br/.test(o)
+ };
+ if ( !opts.TL && !opts.TR && !opts.BL && !opts.BR )
+ opts = { TL:1, TR:1, BL:1, BR:1 };
+ var strip = document.createElement('div');
+ strip.style.overflow = 'hidden';
+ strip.style.height = '1px';
+ strip.style.backgroundColor = sc || 'transparent';
+ strip.style.borderStyle = 'solid';
+ return this.each(function(index){
+ var pad = {
+ T: parseInt($.css(this,'paddingTop'))||0, R: parseInt($.css(this,'paddingRight'))||0,
+ B: parseInt($.css(this,'paddingBottom'))||0, L: parseInt($.css(this,'paddingLeft'))||0
+ };
+
+ if ($.browser.msie) this.style.zoom = 1; // force 'hasLayout' in IE
+ if (!keep) this.style.border = 'none';
+ strip.style.borderColor = cc || gpc(this.parentNode);
+ var cssHeight = $.curCSS(this, 'height');
+
+ for (var j in edges) {
+ var bot = edges[j];
+ // only add stips if needed
+ if ((bot && (opts.BL || opts.BR)) || (!bot && (opts.TL || opts.TR))) {
+ strip.style.borderStyle = 'none '+(opts[j+'R']?'solid':'none')+' none '+(opts[j+'L']?'solid':'none');
+ var d = document.createElement('div');
+ $(d).addClass('jquery-corner');
+ var ds = d.style;
+
+ bot ? this.appendChild(d) : this.insertBefore(d, this.firstChild);
+
+ if (bot && cssHeight != 'auto') {
+ if ($.css(this,'position') == 'static')
+ this.style.position = 'relative';
+ ds.position = 'absolute';
+ ds.bottom = ds.left = ds.padding = ds.margin = '0';
+ if ($.browser.msie)
+ ds.setExpression('width', 'this.parentNode.offsetWidth');
+ else
+ ds.width = '100%';
+ }
+ else if (!bot && $.browser.msie) {
+ if ($.css(this,'position') == 'static')
+ this.style.position = 'relative';
+ ds.position = 'absolute';
+ ds.top = ds.left = ds.right = ds.padding = ds.margin = '0';
+
+ // fix ie6 problem when blocked element has a border width
+ var bw = 0;
+ if (ie6 || !$.boxModel)
+ bw = sz(this,'borderLeftWidth') + sz(this,'borderRightWidth');
+ ie6 ? ds.setExpression('width', 'this.parentNode.offsetWidth - '+bw+'+ "px"') : ds.width = '100%';
+ }
+ else {
+ ds.margin = !bot ? '-'+pad.T+'px -'+pad.R+'px '+(pad.T-width)+'px -'+pad.L+'px' :
+ (pad.B-width)+'px -'+pad.R+'px -'+pad.B+'px -'+pad.L+'px';
+ }
+
+ for (var i=0; i < width; i++) {
+ var w = Math.max(0,getW(i));
+ var e = strip.cloneNode(false);
+ e.style.borderWidth = '0 '+(opts[j+'R']?w:0)+'px 0 '+(opts[j+'L']?w:0)+'px';
+ bot ? d.appendChild(e) : d.insertBefore(e, d.firstChild);
+ }
+ }
+ }
+ });
+};
+
+$.fn.uncorner = function(o) { return $('.jquery-corner', this).remove(); };
+
+})(jQuery);
--- a/web/request.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/request.py Thu Feb 19 20:21:10 2009 +0100
@@ -201,7 +201,7 @@
def update_search_state(self):
"""update the current search state"""
searchstate = self.form.get('__mode')
- if not searchstate:
+ if not searchstate and self.cnx is not None:
searchstate = self.get_session_data('search_state', 'normal')
self.set_search_state(searchstate)
@@ -212,7 +212,8 @@
else:
self.search_state = ('linksearch', searchstate.split(':'))
assert len(self.search_state[-1]) == 4
- self.set_session_data('search_state', searchstate)
+ if self.cnx is not None:
+ self.set_session_data('search_state', searchstate)
def update_breadcrumbs(self):
"""stores the last visisted page in session data"""
--- a/web/test/test_views.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/test/test_views.py Thu Feb 19 20:21:10 2009 +0100
@@ -39,9 +39,9 @@
self.view('table', rset, template=None, displayfilter=True, displaycols=[0,2])
rset = self.execute('Any P,F,S LIMIT 1 WHERE P is EUser, P firstname F, P surname S')
rset.req.form['rtype'] = 'firstname'
- self.view('editrelation', rset, template=None, htmlcheck=False)
+ self.view('editrelation', rset, template=None)
rset.req.form['rtype'] = 'use_email'
- self.view('editrelation', rset, template=None, htmlcheck=False)
+ self.view('editrelation', rset, template=None)
def test_sortable_js_added(self):
--- a/web/test/unittest_viewselector.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/test/unittest_viewselector.py Thu Feb 19 20:21:10 2009 +0100
@@ -19,6 +19,7 @@
treeview, idownloadable, wdoc, debug)
from cubicweb.entities.lib import Card
from cubicweb.interfaces import IMileStone
+from cubicweb.web.views import owl
USERACTIONS = [('myprefs', actions.UserPreferencesAction),
('myinfos', actions.UserInfoAction),
@@ -74,7 +75,7 @@
('index', startup.IndexView),
('info', management.ProcessInformationView),
('manage', startup.ManageView),
- ('owl', startup.OWLView),
+ ('owl', owl.OWLView),
('schema', startup.SchemaView),
('systemepropertiesform', management.SystemEpropertiesForm)])
# no entity but etype
@@ -97,6 +98,7 @@
('filetree', treeview.FileTreeView),
('list', baseviews.ListView),
('oneline', baseviews.OneLineView),
+ ('owlabox', owl.OWLABOXView),
('primary', baseviews.PrimaryView),
('rsetxml', baseviews.XMLRsetView),
('rss', baseviews.RssView),
@@ -117,6 +119,7 @@
('filetree', treeview.FileTreeView),
('list', baseviews.ListView),
('oneline', baseviews.OneLineView),
+ ('owlabox', owl.OWLABOXView),
('primary', baseviews.PrimaryView),
('rsetxml', baseviews.XMLRsetView),
('rss', baseviews.RssView),
@@ -137,6 +140,7 @@
('filetree', treeview.FileTreeView),
('list', baseviews.ListView),
('oneline', baseviews.OneLineView),
+ ('owlabox', owl.OWLABOXView),
('primary', baseviews.PrimaryView),
('rsetxml', baseviews.XMLRsetView),
('rss', baseviews.RssView),
@@ -163,8 +167,10 @@
('ecsvexport', baseviews.CSVEntityView),
('editable-table', tableview.EditableTableView),
('filetree', treeview.FileTreeView),
+ ('foaf', euser.FoafView),
('list', baseviews.ListView),
('oneline', baseviews.OneLineView),
+ ('owlabox', owl.OWLABOXView),
('primary', euser.EUserPrimaryView),
('rsetxml', baseviews.XMLRsetView),
('rss', baseviews.RssView),
--- a/web/views/basecontrollers.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/basecontrollers.py Thu Feb 19 20:21:10 2009 +0100
@@ -60,7 +60,6 @@
def publish(self, rset=None):
"""publish a request, returning an encoded string"""
- self.req.update_search_state()
template = self.req.property_value('ui.main-template')
if template not in self.vreg.registry('templates') :
template = self.template
@@ -453,7 +452,14 @@
# link the new entity to the main entity
rql = 'SET F %(rel)s T WHERE F eid %(eid_to)s, T eid %(eid_from)s' % {'rel' : rel, 'eid_to' : eid_to, 'eid_from' : eid_from}
return eid_from
-
+
+ def js_set_cookie(self, cookiename, cookievalue):
+ # XXX we should consider jQuery.Cookie
+ cookiename, cookievalue = str(cookiename), str(cookievalue)
+ cookies = self.req.get_cookie()
+ cookies[cookiename] = cookievalue
+ self.req.set_cookie(cookies, cookiename)
+
class SendMailController(Controller):
id = 'sendmail'
require_groups = ('managers', 'users')
--- a/web/views/baseforms.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/baseforms.py Thu Feb 19 20:21:10 2009 +0100
@@ -2,7 +2,7 @@
or a list of entities of the same type
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
@@ -33,6 +33,9 @@
title = _('delete')
domid = 'deleteconf'
onsubmit = None
+ # don't use navigation, all entities asked to be deleted should be displayed
+ # else we will only delete the displayed page
+ need_navigation = False
def call(self):
"""ask for confirmation before real deletion"""
@@ -392,17 +395,20 @@
if rschema != 'eid']
def relations_form(self, entity, kwargs):
+ srels_by_cat = entity.srelations_by_category(('generic', 'metadata'), 'add')
+ if not srels_by_cat:
+ return u''
req = self.req
_ = self.req._
label = u'%s :' % _('This %s' % entity.e_schema).capitalize()
eid = entity.eid
html = []
- pendings = list(self.restore_pending_inserts(entity))
w = html.append
w(u'<fieldset class="subentity">')
w(u'<legend class="iformTitle">%s</legend>' % label)
w(u'<table id="relatedEntities">')
for row in self.relations_table(entity):
+ # already linked entities
if row[2]:
w(u'<tr><th class="labelCol">%s</th>' % row[0].display_name(req, row[1]))
w(u'<td>')
@@ -415,10 +421,12 @@
w(u'</ul>')
w(u'</td>')
w(u'</tr>')
+ pendings = list(self.restore_pending_inserts(entity))
if not pendings:
w(u'<tr><th> </th><td> </td></tr>')
else:
for row in pendings:
+ # soon to be linked to entities
w(u'<tr id="tr%s">' % row[1])
w(u'<th>%s</th>' % row[3])
w(u'<td>')
@@ -434,7 +442,8 @@
w(u'<select id="relationSelector_%s" tabindex="%s" onchange="javascript:showMatchingSelect(this.options[this.selectedIndex].value,%s);">'
% (eid, req.next_tabindex(), html_escape(dumps(eid))))
w(u'<option value="">%s</option>' % _('select a relation'))
- for i18nrtype, rschema, target in entity.srelations_by_category(('generic', 'metadata'), 'add'):
+ for i18nrtype, rschema, target in srels_by_cat:
+ # more entities to link to
w(u'<option value="%s_%s">%s</option>' % (rschema, target, i18nrtype))
w(u'</select>')
w(u'</th>')
--- a/web/views/basetemplates.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/basetemplates.py Thu Feb 19 20:21:10 2009 +0100
@@ -2,16 +2,18 @@
"""default templates for CubicWeb web client
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
+
from logilab.mtconverter import html_escape
from cubicweb import NoSelectableObject, ObjectNotFound
from cubicweb.common.view import Template, MainTemplate, NOINDEX, NOFOLLOW
from cubicweb.common.utils import make_uid
+from cubicweb.common.utils import UStringIO
from cubicweb.web.views.baseviews import vid_from_rset
@@ -163,7 +165,10 @@
self.req, self.rset)
if etypefilter and etypefilter.propval('visible'):
etypefilter.dispatch(w=self.w)
- self.pagination(self.req, self.rset, self.w, not (view and view.need_navigation))
+ self.nav_html = UStringIO()
+ self.pagination(self.req, self.rset, self.nav_html.write,
+ not (view and view.need_navigation))
+ self.w(_(self.nav_html.getvalue()))
self.w(u'<div id="contentmain">\n')
def template_html_header(self, content_type, page_title, additional_headers=()):
@@ -199,6 +204,7 @@
def template_footer(self, view=None):
self.w(u'</div>\n') # close id=contentmain
+ self.w(_(self.nav_html.getvalue()))
self.w(u'</div>\n') # closes id=pageContent
self.content_footer(view)
self.w(u'</td>\n')
@@ -419,7 +425,7 @@
req._(ChangeLogView.title).lower()))
self.w(u'<a href="%s">%s</a> | ' % (req.build_url('doc/about'),
req._('about this site')))
- self.w(u'© 2001-2008 <a href="http://www.logilab.fr">Logilab S.A.</a>')
+ self.w(u'© 2001-2009 <a href="http://www.logilab.fr">Logilab S.A.</a>')
self.w(u'</div>')
--- a/web/views/baseviews.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/baseviews.py Thu Feb 19 20:21:10 2009 +0100
@@ -57,14 +57,14 @@
"""
id = 'final'
- def cell_call(self, row, col, props=None, displaytime=False):
+ def cell_call(self, row, col, props=None, displaytime=False, format='text/html'):
etype = self.rset.description[row][col]
value = self.rset.rows[row][col]
if etype == 'String':
entity, rtype = self.rset.related_entity(row, col)
if entity is not None:
# yes !
- self.w(entity.printable_value(rtype, value))
+ self.w(entity.printable_value(rtype, value, format=format))
return
if etype in ('Time', 'Interval'):
_ = self.req._
@@ -639,7 +639,7 @@
row=rowindex, col=colindex)
else:
val = self.view('final', rset, displaytime=True,
- row=rowindex, col=colindex)
+ row=rowindex, col=colindex, format='text/plain')
w(simple_sgml_tag(tag, val, **attrs))
w(u' </row>\n')
w(u'</%s>\n' % self.xml_root)
@@ -747,7 +747,8 @@
content = self.view('textincontext', rset,
row=rowindex, col=colindex)
else:
- content = self.view('final', rset, displaytime=True,
+ content = self.view('final', rset,
+ displaytime=True, format='text/plain',
row=rowindex, col=colindex)
csvrow.append(content)
writer.writerow(csvrow)
@@ -800,7 +801,7 @@
rset, vid, divid, paginate = self.filter_box_context_info()
self.w(u'<div id="%s">' % divid)
self.pagination(self.req, rset, w=self.w)
- self.wview(vid, rset)
+ self.wview(vid, rset, 'noresult')
self.w(u'</div>')
@cached
@@ -862,13 +863,8 @@
assert rtype is not None, "rtype is mandatory for 'edirelation' view"
targettype = self.req.form.get('targettype', targettype)
role = self.req.form.get('role', role)
- mode = entity.rtags.get_mode(rtype, targettype, role)
- if mode == 'create':
- return
category = entity.rtags.get_category(rtype, targettype, role)
- if category in ('generated', 'metadata'):
- return
- elif category in ('primary', 'secondary'):
+ if category in ('primary', 'secondary') or self.schema.rschema(rtype).is_final():
if hasattr(entity, '%s_format' % rtype):
formatwdg = entity.get_widget('%s_format' % rtype, role)
self.w(formatwdg.edit_render(entity))
@@ -879,10 +875,8 @@
self.w(u'%s %s %s' %
(wdg.render_error(entity), wdg.edit_render(entity),
wdg.render_help(entity),))
- elif category == 'generic':
+ else:
self._render_generic_relation(entity, rtype, role)
- else:
- self.error("oops, wrong category %s", category)
def _render_generic_relation(self, entity, relname, role):
text = self.req.__('add %s %s %s' % (entity.e_schema, relname, role))
--- a/web/views/boxes.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/boxes.py Thu Feb 19 20:21:10 2009 +0100
@@ -10,14 +10,14 @@
* startup views box
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
from logilab.mtconverter import html_escape
-from cubicweb.common.selectors import (any_rset, appobject_selectable)
+from cubicweb.common.selectors import any_rset, appobject_selectable
from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, BoxHtml, RawBoxItem
from cubicweb.web.box import BoxTemplate, ExtResourcesBoxTemplate
@@ -175,17 +175,16 @@
def call(self, **kwargs):
box = BoxWidget(self.req._(self.title), self.id)
- actions = [v for v in self.vreg.possible_views(self.req, self.rset)
- if v.category != 'startupview']
- for category, actions in self.sort_actions(actions):
+ views = [v for v in self.vreg.possible_views(self.req, self.rset)
+ if v.category != 'startupview']
+ for category, views in self.sort_actions(views):
menu = BoxMenu(category)
- for action in actions:
- menu.append(self.box_action(action))
+ for view in views:
+ menu.append(self.box_action(view))
box.append(menu)
if not box.is_empty():
box.render(self.w)
-
class RSSIconBox(ExtResourcesBoxTemplate):
"""just display the RSS icon on uniform result set"""
@@ -203,23 +202,6 @@
self.w(u'<a href="%s"><img src="%s" alt="rss"/></a>\n' % (html_escape(url), rss))
-## warning("schemabox ne marche plus pour le moment")
-## class SchemaBox(BoxTemplate):
-## """display a box containing link to list of entities by type"""
-## id = 'schema_box'
-## visible = False # disabled by default
-## title = _('entity list')
-## order = 60
-
-## def call(self, **kwargs):
-## box = BoxWidget(self.req._(title), self.id)
-## for etype in self.config.etypes(self.req.user, 'read'):
-## view = self.vreg.select_view('list', self.req, self.etype_rset(etype))
-## box.append(self.mk_action(display_name(self.req, etype, 'plural'),
-## view.url(), etype=etype))
-## if not box.is_empty():
-## box.render(self.w)
-
class StartupViewsBox(BoxTemplate):
"""display a box containing links to all startup views"""
id = 'startup_views_box'
--- a/web/views/euser.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/euser.py Thu Feb 19 20:21:10 2009 +0100
@@ -14,12 +14,6 @@
from cubicweb.web.form import EntityForm
from cubicweb.web.views.baseviews import PrimaryView, EntityView
-try:
- from hashlib import sha1 as sha
-
-except ImportError:
- from sha import sha
-
class EUserPrimaryView(PrimaryView):
accepts = ('EUser',)
skip_attrs = ('firstname', 'surname')
@@ -38,7 +32,6 @@
return rschema.type in ['interested_in', 'tags',
'todo_by', 'bookmarked_by',
]
-
class FoafView(EntityView):
id = 'foaf'
accepts = ('EUser',)
@@ -47,10 +40,10 @@
content_type = 'text/xml'
def call(self):
- self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
- self.w(u'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\n')
- self.w(u'xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"\n')
- self.w(u'xmlns:foaf="http://xmlns.com/foaf/0.1/">\n')
+ self.w('''<?xml version="1.0" encoding="%s"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
+ xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
for i in xrange(self.rset.rowcount):
self.cell_call(i, 0)
self.w(u'</rdf:RDF>\n')
@@ -72,10 +65,15 @@
% html_escape(entity.firstname))
emailaddr = entity.get_email()
if emailaddr:
- self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(unicode(emailaddr)))
- self.w(u'</foaf:Person>\n')
+ self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
+ self.w(u'</foaf:Person>\n')
-
+class FoafUsableView(FoafView):
+ id = 'foaf_usable'
+
+ def call(self):
+ self.cell_call(0, 0)
+
class EditGroups(EntityForm):
"""displays a simple euser / egroups editable table"""
--- a/web/views/facets.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/facets.py Thu Feb 19 20:21:10 2009 +0100
@@ -1,7 +1,7 @@
"""the facets box and some basic facets
:organization: Logilab
-:copyright: 2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2008-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
--- a/web/views/linkedData.py Thu Feb 19 20:19:05 2009 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-from logilab.mtconverter import html_escape
-
-from cubicweb.common.view import EntityView
-
-from urlparse import urlparse
-
-class LinkedDataProjectView(EntityView):
- id = 'project_linked_data'
- title = _('Project linked data')
- accepts = ('Project',)
- templatable = False
- content_type = 'text/xml'
-
- def call(self):
- '''display all project attribut and project dependencies and external project (in doap format) if
- it is related to'''
-
- self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self.req.encoding)
- self.w(u'''<rdf:RDF
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
- xmlns:owl="http://www.w3.org/2002/07/owl#"
- xmlns:doap="http://usefulinc.com/ns/doap#"
- >\n''')
- for i in xrange(self.rset.rowcount):
- self.cell_call(row=i, col=0)
- self.w(u'</rdf:RDF>\n')
-
- def cell_call(self, row, col):
- self.wview('project_linked_data_item', self.rset, row=row, col=col)
-
-class LinkedDataProjectItemView(EntityView):
- id = 'project_linked_data_item'
- accepts = ('Project',)
-
- def cell_call(self, row, col):
- entity = self.complete_entity(row, col)
- self.w(u'<Project rdf:about="%s">\n' % html_escape(entity.absolute_url()))
- self.w(u' <name>%s</name>\n' % html_escape(unicode(entity.dc_title())))
- self.w(u' <doap:created>%s</doap:created>\n' % (entity.creation_date.strftime('%Y-%m-%d')))
- self.w(u' <summary>%s</summary>\n' % html_escape(unicode(entity.summary)))
- self.w(u' <doap:description>%s</doap:description>\n' % html_escape(unicode(entity.description)))
- self.w(u' <url>%s</url>\n' % html_escape(entity.url or entity.absolute_url()))
- if entity.modification_date:
- self.w(u'<doap:revision>%s</doap:revision>\n'% (entity.modification_date.strftime('%Y-%m-%d')))
- if entity.vcsurl:
- self.w(u'''<vcurl>
- <doap:browse rdf:resource="%s" />
- </vcurl>''' % html_escape(entity.vcsurl))
- if entity.reporturl:
- self.w(u'<reporturl>"%s"</vcurl>' % html_escape(entity.vcsurl))
-
- if entity.downloadurl:
- self.w(u' <doap:file-release>%s</doap:file-release>\n' % html_escape(entity.downloadurl))
- liste = urlparse(entity.absolute_url())
- internal_address = liste[1]
- for externalproject in entity.uses:
- self.w(u'<uses>\n')
- if externalproject.e_schema == 'ExtProject':
- if externalproject.absolute_url().find(internal_address) > 0:
- self.w(u'<!--wrong external url-->')
- self.w(u' <ExtProject>%s</ExtProject>'% externalproject.absolute_url())
- else:
- self.w(u'<Project>%s</Project>'% externalproject.absolute_url())
- self.w(u'</uses>\n')
- for externalproject in entity.recommends:
- self.w(u'<recommends>\n')
- if externalproject.e_schema == 'ExtProject':
- if externalproject.absolute_url().find(internal_address) > 0:
- self.w(u'<!--wrong external url-->')
- self.w(u'<ExtProject>%s</ExtProject>'% externalproject.absolute_url())
- else:
- self.w(u'<Project>%s</Project>'% externalproject.absolute_url())
- self.w(u'%s</recommends>'% externalproject.absolute_url())
-
- self.w(u'</Project>\n')
-
-
--- a/web/views/management.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/management.py Thu Feb 19 20:21:10 2009 +0100
@@ -13,17 +13,16 @@
from cubicweb.common.utils import UStringIO
from cubicweb.common.view import AnyRsetView, StartupView, EntityView
-from cubicweb.common.uilib import (html_traceback, rest_traceback, html_escape,
- toggle_link)
+from cubicweb.common.uilib import html_traceback, rest_traceback
from cubicweb.common.selectors import (yes, one_line_rset,
- accept_rset, none_rset,
- chainfirst, chainall)
+ accept_rset, none_rset,
+ chainfirst, chainall)
from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, stdmsgs
from cubicweb.web.widgets import StaticComboBoxWidget
from cubicweb.web.form import FormMixIn
_ = unicode
-
+
def begin_form(w, entity, redirectvid, redirectpath=None, msg=None):
w(u'<form method="post" action="%s">\n' % entity.req.build_url('edit'))
w(u'<fieldset>\n')
@@ -42,10 +41,10 @@
"""display security information for a given entity"""
id = 'security'
title = _('security')
-
+
def cell_call(self, row, col):
- self.req.add_js('cubicweb.edition.js')
- self.req.add_css('cubicweb.acl.css')
+ self.req.add_js('cubicweb.edition.js')
+ self.req.add_css('cubicweb.acl.css')
entity = self.entity(row, col)
w = self.w
_ = self.req._
@@ -90,7 +89,7 @@
w(u'<td>%s</td>' % u'<br/>'.join(expr.expression for expr in rqlexprs))
w(u'</tr>\n')
w(u'</table>')
-
+
def owned_by_edit_form(self, entity):
self.w('<h3>%s</h3>' % self.req._('ownership'))
begin_form(self.w, entity, 'security', msg= _('ownerships have been changed'))
@@ -169,7 +168,7 @@
wdg = newperm.get_widget('label')
w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
wdg = newperm.get_widget('require_group')
- w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
+ w(u'<td>%s</td>\n' % wdg.edit_render(newperm))
w(u'<td>%s</td></tr>\n' % self.button_ok())
w(u'</table>')
w(u'</fieldset></form>\n')
@@ -178,12 +177,12 @@
return (u'<input class="validateButton" type="submit" name="submit" value="%s"/>'
% self.req._(stdmsgs.BUTTON_OK))
-
+
class ErrorView(AnyRsetView):
"""default view when no result has been found"""
__selectors__ = (yes,)
id = 'error'
-
+
def page_title(self):
"""returns a title according to the result set - used for the
title in the HTML header
@@ -192,11 +191,11 @@
def call(self):
req = self.req.reset_headers()
- _ = req._
+ _ = req._; w = self.w
ex = req.data.get('ex')#_("unable to find exception information"))
excinfo = req.data.get('excinfo')
title = _('an error occured')
- self.w(u'<h2>%s</h2>' % title)
+ w(u'<h2>%s</h2>' % title)
if 'errmsg' in req.data:
ex = req.data['errmsg']
exclass = None
@@ -205,53 +204,53 @@
ex = exc_message(ex, req.encoding)
if excinfo is not None and self.config['print-traceback']:
if exclass is None:
- self.w(u'<div class="tb">%s</div>'
+ w(u'<div class="tb">%s</div>'
% html_escape(ex).replace("\n","<br />"))
else:
- self.w(u'<div class="tb">%s: %s</div>'
+ w(u'<div class="tb">%s: %s</div>'
% (exclass, html_escape(ex).replace("\n","<br />")))
- self.w(u'<hr />')
- self.w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
+ w(u'<hr />')
+ w(u'<div class="tb">%s</div>' % html_traceback(excinfo, ex, ''))
else:
- self.w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
+ w(u'<div class="tb">%s</div>' % (html_escape(ex).replace("\n","<br />")))
# if excinfo is not None, it's probably not a bug
if excinfo is None:
return
vcconf = self.config.vc_config()
- self.w(u"<div>")
+ w(u"<div>")
eversion = vcconf.get('cubicweb', _('no version information'))
# NOTE: tuple wrapping needed since eversion is itself a tuple
- self.w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,))
+ w(u"<b>CubicWeb version:</b> %s<br/>\n" % (eversion,))
for pkg in self.config.cubes():
pkgversion = vcconf.get(pkg, _('no version information'))
- self.w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion))
- self.w(u"</div>")
+ w(u"<b>Package %s version:</b> %s<br/>\n" % (pkg, pkgversion))
+ w(u"</div>")
# creates a bug submission link if SUBMIT_URL is set
submiturl = self.config['submit-url']
if submiturl:
binfo = text_error_description(ex, excinfo, req, eversion,
[(pkg, vcconf.get(pkg, _('no version information')))
for pkg in self.config.cubes()])
- self.w(u'<form action="%s" method="post">\n' % html_escape(submiturl))
- self.w(u'<fieldset>\n')
- self.w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo))
- self.w(u'<input type="hidden" name="description_format" value="text/rest"/>')
- self.w(u'<input type="hidden" name="__bugreporting" value="1"/>')
- self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report'))
- self.w(u'</fieldset>\n')
- self.w(u'</form>\n')
+ w(u'<form action="%s" method="post">\n' % html_escape(submiturl))
+ w(u'<fieldset>\n')
+ w(u'<textarea class="hidden" name="description">%s</textarea>' % html_escape(binfo))
+ w(u'<input type="hidden" name="description_format" value="text/rest"/>')
+ w(u'<input type="hidden" name="__bugreporting" value="1"/>')
+ w(u'<input type="submit" value="%s"/>' % _('Submit bug report'))
+ w(u'</fieldset>\n')
+ w(u'</form>\n')
submitmail = self.config['submit-mail']
if submitmail:
binfo = text_error_description(ex, excinfo, req, eversion,
[(pkg, vcconf.get(pkg, _('no version information')))
for pkg in self.config.cubes()])
- self.w(u'<form action="%s" method="post">\n' % req.build_url('reportbug'))
- self.w(u'<fieldset>\n')
- self.w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo))
- self.w(u'<input type="hidden" name="__bugreporting" value="1"/>')
- self.w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail'))
- self.w(u'</fieldset>\n')
- self.w(u'</form>\n')
+ w(u'<form action="%s" method="post">\n' % req.build_url('reportbug'))
+ w(u'<fieldset>\n')
+ w(u'<input type="hidden" name="description" value="%s"/>' % html_escape(binfo))
+ w(u'<input type="hidden" name="__bugreporting" value="1"/>')
+ w(u'<input type="submit" value="%s"/>' % _('Submit bug report by mail'))
+ w(u'</fieldset>\n')
+ w(u'</form>\n')
def exc_message(ex, encoding):
@@ -262,7 +261,7 @@
return unicode(str(ex), encoding, 'replace')
except:
return unicode(repr(ex), encoding, 'replace')
-
+
def text_error_description(ex, excinfo, req, eversion, cubes):
binfo = rest_traceback(excinfo, html_escape(ex))
binfo += u'\n\n:URL: %s\n' % req.url()
@@ -284,23 +283,48 @@
_('components')
_('contentnavigation')
+
+def make_togglable_link(nodeid, label, cookiename):
+ """builds a HTML link that switches the visibility & remembers it"""
+ action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
+ (nodeid, cookiename)
+ return u'<a href="%s">%s</a>' % (action, label)
+
+def css_class(someclass):
+ return someclass and 'class="%s"' % someclass or ''
+
class SystemEpropertiesForm(FormMixIn, StartupView):
controller = 'edit'
id = 'systemepropertiesform'
title = _('site configuration')
require_groups = ('managers',)
category = 'startupview'
-
+
def linkable(self):
return True
-
+
def url(self):
"""return the url associated with this view. We can omit rql here"""
return self.build_url('view', vid=self.id)
-
+
+ def _cookie_name(self, somestr):
+ return str('%s_property_%s' % (self.config.appid, somestr))
+
+ def _group_status(self, group, default=u'hidden'):
+ cookies = self.req.get_cookie()
+ cookiename = self._cookie_name(group)
+ cookie = cookies.get(cookiename)
+ if cookie is None:
+ cookies[cookiename] = default
+ self.req.set_cookie(cookies, cookiename, maxage=None)
+ status = default
+ else:
+ status = cookie.value
+ return status
+
def call(self, **kwargs):
"""The default view representing the application's index"""
- self.req.add_js('cubicweb.edition.js')
+ self.req.add_js(('cubicweb.edition.js', 'cubicweb.preferences.js'))
self.req.add_css('cubicweb.preferences.css')
vreg = self.vreg
values = self.defined_keys
@@ -322,7 +346,7 @@
for group, objects in groupedopts.items():
for oid, keys in objects.items():
groupedopts[group][oid] = self.form(keys, True)
-
+
w = self.w
req = self.req
_ = req._
@@ -330,17 +354,21 @@
w(self.error_message())
for label, group, form in sorted((_(g), g, f)
for g, f in mainopts.iteritems()):
+ status = css_class(self._group_status(group)) #'hidden' (collapsed), or '' (open) ?
w(u'<h2 class="propertiesform">%s</h2>\n' %
- (toggle_link('fieldset_' + group, label)))
- w(u'<div id="fieldset_%s" class="hidden">' % group)
+ (make_togglable_link('fieldset_' + group, label,
+ self._cookie_name(group))))
+ w(u'<div id="fieldset_%s" %s>' % (group, status))
w(u'<fieldset class="subentity">')
w(form)
w(u'</fieldset></div>')
for label, group, objects in sorted((_(g), g, o)
for g, o in groupedopts.iteritems()):
+ status = css_class(self._group_status(group))
w(u'<h2 class="propertiesform">%s</h2>\n' %
- (toggle_link('fieldset_' + group, label)))
- w(u'<div id="fieldset_%s" class="hidden">' % group)
+ (make_togglable_link('fieldset_' + group, label,
+ self._cookie_name(group))))
+ w(u'<div id="fieldset_%s" %s>' % (group, status))
for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
for o, f in objects.iteritems()):
w(u'<fieldset class="subentity">')
@@ -352,21 +380,19 @@
w(form)
w(u'</fieldset>')
w(u'</div>')
-
-
@property
@cached
def eprops_rset(self):
return self.req.execute('Any P,K,V WHERE P is EProperty, P pkey K, P value V, NOT P for_user U')
-
+
@property
def defined_keys(self):
values = {}
for i, entity in enumerate(self.eprops_rset.entities()):
values[entity.pkey] = i
return values
-
+
def entity_for_key(self, key):
values = self.defined_keys
if key in values:
@@ -391,11 +417,11 @@
w(u'<input type="hidden" name="__redirectparams" value="%s"/>\n'
% html_escape(params))
w(u'<input type="hidden" name="__redirectpath" value="%s"/>\n' % path)
- #w(u'<input type="hidden" name="__redirectrql" value=""/>\n')
+ #w(u'<input type="hidden" name="__redirectrql" value=""/>\n')
w(u'<input type="hidden" name="__message" value="%s"/>\n'
% self.req._('changes applied'))
w(u'<table><tr><td>\n')
-
+
w(u'<table>\n')
for key in keys:
w(u'<tr>\n')
@@ -409,7 +435,7 @@
w(u'</fieldset>\n')
w(u'</form>\n')
return stream.getvalue()
-
+
def form_row(self, w, key, splitlabel):
entity = self.entity_for_key(key)
eid = entity.eid
@@ -434,10 +460,10 @@
w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('pkey', eid), key))
w(u'<input type="hidden" name="%s" value="%s"/>' % (eid_param('edits-pkey', eid), ''))
-
+
class EpropertiesForm(SystemEpropertiesForm):
id = 'epropertiesform'
- title = _('preferences')
+ title = _('preferences')
require_groups = ('users', 'managers') # we don't want guests to be able to come here
__selectors__ = chainfirst(none_rset,
chainall(one_line_rset, accept_rset)),
@@ -449,7 +475,7 @@
row = 0
score = super(EpropertiesForm, cls).accept_rset(req, rset, row, col)
# check current user is the rset user or he is in the managers group
- if score and (req.user.eid == rset[row][col or 0]
+ if score and (req.user.eid == rset[row][col or 0]
or req.user.matching_groups('managers')):
return score
return 0
@@ -459,7 +485,7 @@
if self.rset is None:
return self.req.user
return self.rset.get_entity(self.row or 0, self.col or 0)
-
+
@property
@cached
def eprops_rset(self):
@@ -476,9 +502,9 @@
% (eid_param('edits-for_user', eid), INTERNAL_FIELD_VALUE))
w(u'<input type="hidden" name="%s" value="%s"/>'
% (eid_param('for_user', eid), self.user.eid))
-
-
-
+
+
+
class ProcessInformationView(StartupView):
id = 'info'
--- a/web/views/navigation.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/navigation.py Thu Feb 19 20:21:10 2009 +0100
@@ -36,15 +36,17 @@
while start < rset.rowcount:
stop = min(start + page_size - 1, rset.rowcount - 1)
blocklist.append(self.page_link(basepath, params, start, stop,
- u'%s - %s' % (start+1, stop+1)))
+ self.index_display(start, stop)))
start = stop + 1
w(u'<div class="pagination">')
w(u'%s ' % self.previous_link(params))
w(u'[ %s ]' % u' | '.join(blocklist))
w(u' %s' % self.next_link(params))
w(u'</div>')
+
+ def index_display(self, start, stop):
+ return u'%s - %s' % (start+1, stop+1)
-
class SortedNavigation(NavigationComponent):
"""sorted navigation apply if navigation is needed (according to page size)
and if the result set is sorted
@@ -142,9 +144,11 @@
self.w(u'</div>')
-def limit_rset_using_paged_nav(self, req, rset, w, forcedisplay=False, show_all_option=True):
+def limit_rset_using_paged_nav(self, req, rset, w, forcedisplay=False,
+ show_all_option=True, page_size = None):
showall = forcedisplay or req.form.get('__force_display') is not None
- nav = not showall and self.vreg.select_component('navigation', req, rset)
+ nav = not showall and self.vreg.select_component('navigation', req, rset,
+ page_size=page_size)
if nav:
# get boundaries before component rendering
start, stop = nav.page_boundaries()
--- a/web/views/owl.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/owl.py Thu Feb 19 20:21:10 2009 +0100
@@ -1,4 +1,4 @@
-from logilab.mtconverter import html_escape
+from logilab.mtconverter import TransformError, xml_escape
from cubicweb.common.view import StartupView
from cubicweb.common.view import EntityView
@@ -11,124 +11,76 @@
'*': ''
}
-OWL_CARD_MAP_DATA = {'String': 'xsd:string',
- 'Datetime': 'xsd:dateTime',
- 'Bytes': 'xsd:byte',
- 'Float': 'xsd:float',
- 'Boolean': 'xsd:boolean',
- 'Int': 'xsd:int',
- 'Date':'xsd:date',
- 'Time': 'xsd:time',
- 'Password': 'xsd:byte',
- 'Decimal' : 'xsd:decimal',
- 'Interval': 'xsd:duration'
- }
+OWL_TYPE_MAP = {'String': 'xsd:string',
+ 'Datetime': 'xsd:dateTime',
+ 'Bytes': 'xsd:byte',
+ 'Float': 'xsd:float',
+ 'Boolean': 'xsd:boolean',
+ 'Int': 'xsd:int',
+ 'Date':'xsd:date',
+ 'Time': 'xsd:time',
+ 'Password': 'xsd:byte',
+ 'Decimal' : 'xsd:decimal',
+ 'Interval': 'xsd:duration'
+ }
OWL_OPENING_ROOT = u'''<?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE rdf:RDF [
+<!DOCTYPE rdf:RDF [
<!ENTITY owl "http://www.w3.org/2002/07/owl#" >
<!ENTITY xsd "http://www.w3.org/2001/XMLSchema#" >
- <!ENTITY rdfs "http://www.w3.org/2000/01/rdf-schema#" >
- <!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
- <!ENTITY %s "http://logilab.org/owl/ontologies/%s#" >
-
- ]>
- <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
- xmlns:owl="http://www.w3.org/2002/07/owl#"
- xmlns="http://logilab.org/owl/ontologies/%s#"
- xmlns:%s="http://logilab.org/owl/ontologies/%s#"
- xmlns:base="http://logilab.org/owl/ontologies/%s">
+]>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
+ xmlns:owl="http://www.w3.org/2002/07/owl#"
+ xmlns="http://logilab.org/owl/ontologies/%(appid)s#"
+ xmlns:%(appid)s="http://logilab.org/owl/ontologies/%(appid)s#"
+ xmlns:base="http://logilab.org/owl/ontologies/%(appid)s">
- <owl:Ontology rdf:about="">
- <rdfs:comment>
- %s Cubicweb OWL Ontology
-
- </rdfs:comment>
- </owl:Ontology>'''
+ <owl:Ontology rdf:about="">
+ <rdfs:comment>
+ %(appid)s Cubicweb OWL Ontology
+ </rdfs:comment>
+ </owl:Ontology>'''
OWL_CLOSING_ROOT = u'</rdf:RDF>'
-class OWLView(StartupView):
- """This view export in owl format the whole cubicweb ontologie. First part is the TBOX, second part is an ABOX ligth version."""
- id = 'owl'
- title = _('owl (tbox+abox)')
- templatable =False
- content_type = 'application/xml' # 'text/xml'
+DEFAULT_SKIP_RELS = frozenset(('is', 'is_instance_of', 'identity',
+ 'owned_by', 'created_by'))
- def call(self):
-
- skipmeta = int(self.req.form.get('skipmeta', True))
- self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name))
- self.wview('tbox', None, writeprefix=False)
- entities = [eschema for eschema in self.schema.entities()
- if not eschema.is_final()]
- if skipmeta:
- entities = [eschema for eschema in entities
- if not eschema.meta]
- for entity in entities:
- rql = 'Any X where X is %s'
- rset = self.req.execute(rql% entity)
- if rset:
- self.wview('owlaboxlight', rset, writeprefix=False)
- self.w(OWL_CLOSING_ROOT)
-
-class TBoxView(StartupView):
+class OWLView(StartupView):
"""This view export in owl format schema database. It is the TBOX"""
- id = 'tbox'
- title = _('tbox')
- templatable =False
+ id = 'owl'
+ title = _('owl')
+ templatable = False
content_type = 'application/xml' # 'text/xml'
def call(self, writeprefix=True):
skipmeta = int(self.req.form.get('skipmeta', True))
if writeprefix:
- self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name) )
-
- self.visit_schema(display_relations=True,
- skiprels=('is', 'is_instance_of', 'identity',
- 'owned_by', 'created_by'),
- skipmeta=skipmeta)
+ self.w(OWL_OPENING_ROOT % {'appid': self.schema.name})
+ self.visit_schema(skipmeta=skipmeta)
if writeprefix:
self.w(OWL_CLOSING_ROOT)
- def visit_schema(self, display_relations=0,
- skiprels=(), skipmeta=True):
+ def visit_schema(self, skiprels=DEFAULT_SKIP_RELS, skipmeta=True):
"""get a layout for a whole schema"""
-
- entities = [eschema for eschema in self.schema.entities()
- if not eschema.is_final()]
+ entities = sorted([eschema for eschema in self.schema.entities()
+ if not eschema.is_final()])
if skipmeta:
entities = [eschema for eschema in entities
if not eschema.meta]
- keys = [(eschema.type, eschema) for eschema in entities]
self.w(u'<!-- classes definition -->')
- for key, eschema in sorted(keys):
+ for eschema in entities:
self.visit_entityschema(eschema, skiprels)
- self.w(u'<!-- property definition -->')
- self.w(u'<!-- object property -->')
- for key, eschema in sorted(keys):
- self.visit_property_schema(eschema, skiprels)
- self.w(u'<!-- datatype property -->')
- for key, eschema in sorted(keys):
- self.visit_property_object_schema(eschema, skiprels)
-
- def stereotype(self, name):
- return Span((' <<%s>>' % name,), klass='stereotype')
-
+ self.w(u'<!-- property definition -->')
+ self.visit_property_schema(eschema, skiprels)
+ self.w(u'<!-- datatype property -->')
+ self.visit_property_object_schema(eschema)
+
def visit_entityschema(self, eschema, skiprels=()):
"""get a layout for an entity OWL schema"""
- etype = eschema.type
-
- if eschema.meta:
- self.stereotype('meta')
- self.w(u'''<owl:Class rdf:ID="%s"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
- '''%eschema, stereotype)
- else:
- self.w(u'''<owl:Class rdf:ID="%s"><rdfs:subClassOf rdf:resource="http://www.w3.org/2002/07/owl#Thing"/>
- '''% eschema)
-
+ self.w(u'<owl:Class rdf:ID="%s">'% eschema)
self.w(u'<!-- relations -->')
for rschema, targetschemas, role in eschema.relation_definitions():
if rschema.type in skiprels:
@@ -141,13 +93,15 @@
card = rschema.rproperty(eschema, oeschema, 'cardinality')[0]
else:
card = rschema.rproperty(oeschema, eschema, 'cardinality')[1]
- self.w(u'''<rdfs:subClassOf>
- <owl:Restriction>
- <owl:onProperty rdf:resource="#%s"/>
- %s
- </owl:Restriction>
- </rdfs:subClassOf>
- ''' % (label, OWL_CARD_MAP[card]))
+ cardtag = OWL_CARD_MAP[card]
+ if cardtag:
+ self.w(u'''<rdfs:subClassOf>
+ <owl:Restriction>
+ <owl:onProperty rdf:resource="#%s"/>
+ %s
+ </owl:Restriction>
+</rdfs:subClassOf>
+''' % (label, cardtag))
self.w(u'<!-- attributes -->')
@@ -157,21 +111,17 @@
aname = rschema.type
if aname == 'eid':
continue
- card_data = aschema.type
self.w(u'''<rdfs:subClassOf>
- <owl:Restriction>
- <owl:onProperty rdf:resource="#%s"/>
- <rdf:type rdf:resource="&owl;FunctionalProperty"/>
- </owl:Restriction>
- </rdfs:subClassOf>'''
-
+ <owl:Restriction>
+ <owl:onProperty rdf:resource="#%s"/>
+ <rdf:type rdf:resource="&owl;FunctionalProperty"/>
+ </owl:Restriction>
+</rdfs:subClassOf>'''
% aname)
self.w(u'</owl:Class>')
def visit_property_schema(self, eschema, skiprels=()):
"""get a layout for property entity OWL schema"""
- etype = eschema.type
-
for rschema, targetschemas, role in eschema.relation_definitions():
if rschema.type in skiprels:
continue
@@ -180,78 +130,53 @@
for oeschema in targetschemas:
label = rschema.type
self.w(u'''<owl:ObjectProperty rdf:ID="%s">
- <rdfs:domain rdf:resource="#%s"/>
- <rdfs:range rdf:resource="#%s"/>
- </owl:ObjectProperty>
-
- ''' % (label, eschema, oeschema.type ))
+ <rdfs:domain rdf:resource="#%s"/>
+ <rdfs:range rdf:resource="#%s"/>
+</owl:ObjectProperty>
+''' % (label, eschema, oeschema.type))
- def visit_property_object_schema(self, eschema, skiprels=()):
-
+ def visit_property_object_schema(self, eschema):
for rschema, aschema in eschema.attribute_definitions():
if not (rschema.has_local_role('read') or rschema.has_perm(self.req, 'read')):
continue
aname = rschema.type
if aname == 'eid':
continue
- card_data = aschema.type
self.w(u'''<owl:DatatypeProperty rdf:ID="%s">
- <rdfs:domain rdf:resource="#%s"/>
- <rdfs:range rdf:resource="%s"/>
- </owl:DatatypeProperty>'''
- % (aname, eschema, OWL_CARD_MAP_DATA[card_data]))
-
-class OWLABOXLightView(EntityView):
- '''This view represents the lihgt part of the ABOX for a given entity'''
- id = 'owlaboxlight'
- title = _('owlaboxlight')
- templatable =False
- accepts = ('Any',)
- content_type = 'application/xml' # 'text/xml'
-
- def call(self, writeprefix=True):
+ <rdfs:domain rdf:resource="#%s"/>
+ <rdfs:range rdf:resource="%s"/>
+</owl:DatatypeProperty>'''
+ % (aname, eschema, OWL_TYPE_MAP[aschema.type]))
- skipmeta = int(self.req.form.get('skipmeta', True))
- if writeprefix:
- self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name))
- for i in xrange(self.rset.rowcount):
- self.cell_call(i, 0, skiprels=('is', 'is_instance_of', 'identity',
- 'owned_by', 'created_by'),
- skipmeta=skipmeta)
- if writeprefix:
- self.w(OWL_CLOSING_ROOT)
-
-
- def cell_call(self, row, col, skiprels=(), skipmeta=True):
- entity = self.complete_entity(row, col)
- eschema = entity.e_schema
- self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
- self.w(u'</%s>'% eschema)
-
-
-class OWLABOXEView(EntityView):
+
+class OWLABOXView(EntityView):
'''This view represents a part of the ABOX for a given entity.'''
id = 'owlabox'
title = _('owlabox')
- templatable =False
+ templatable = False
accepts = ('Any',)
content_type = 'application/xml' # 'text/xml'
- def call(self, writeprefix=True):
-
- skipmeta = int(self.req.form.get('skipmeta', True))
- if writeprefix:
- self.w(OWL_OPENING_ROOT % (self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name, self.schema.name))
+ def call(self):
+ self.w(OWL_OPENING_ROOT % {'appid': self.schema.name})
for i in xrange(self.rset.rowcount):
- self.cell_call(i, 0, skiprels=('is', 'is_instance_of', 'identity',
- 'owned_by', 'created_by'),
- skipmeta=skipmeta)
- if writeprefix:
- self.w(OWL_CLOSING_ROOT)
+ self.cell_call(i, 0)
+ self.w(OWL_CLOSING_ROOT)
+
+ def cell_call(self, row, col, skiprels=DEFAULT_SKIP_RELS):
+ self.wview('owlaboxitem', self.rset, row=row, col=col, skiprels=skiprels)
+
+class OWLABOXItemView(EntityView):
+ '''This view represents a part of the ABOX for a given entity.'''
+
+ id = 'owlaboxitem'
+ templatable = False
+ accepts = ('Any',)
+ content_type = 'application/xml' # 'text/xml'
- def cell_call(self, row, col, skiprels=(), skipmeta=True):
+ def cell_call(self, row, col, skiprels=DEFAULT_SKIP_RELS):
entity = self.complete_entity(row, col)
eschema = entity.e_schema
self.w(u'<%s rdf:ID="%s">' % (eschema, entity.eid))
@@ -264,9 +189,12 @@
aname = rschema.type
if aname == 'eid':
continue
- attr = getattr(entity, aname)
- if attr is not None:
- self.w(u'<%s>%s</%s>' % (aname, html_escape(unicode(attr)), aname))
+ try:
+ attr = entity.printable_value(aname, format='text/plain')
+ if attr:
+ self.w(u'<%s>%s</%s>' % (aname, xml_escape(attr), aname))
+ except TransformError:
+ pass
self.w(u'<!--relations -->')
for rschema, targetschemas, role in eschema.relation_definitions():
if rschema.type in skiprels:
--- a/web/views/tabs.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/views/tabs.py Thu Feb 19 20:21:10 2009 +0100
@@ -60,9 +60,13 @@
class TabsMixin(LazyViewMixin):
+ @property
+ def cookie_name(self):
+ return str('%s_active_tab' % self.config.appid)
+
def active_tab(self, tabs, default):
cookie = self.req.get_cookie()
- cookiename = '%s_active_tab' % self.config.appid
+ cookiename = self.cookie_name
activetab = cookie.get(cookiename)
if activetab is None:
cookie[cookiename] = default
@@ -97,7 +101,7 @@
for tab in tabs:
w(u'<li>')
w(u'<a href="#as-%s">' % tab)
- w(u'<span onclick="set_tab(\'%s\')">' % tab)
+ w(u'<span onclick="set_tab(\'%s\', \'%s\')">' % (tab, self.cookie_name))
w(self.req._(tab))
w(u'</span>')
w(u'</a>')
@@ -112,17 +116,11 @@
# because the callback binding needs to be done before
self.req.html_headers.add_onload(u"""
jQuery('#entity-tabs > ul').tabs( { selected: %(tabindex)s });
- set_tab('%(vid)s');
- """ % {'tabindex' : tabs.index(active_tab),
- 'vid' : active_tab})
-
+ set_tab('%(vid)s', '%(cookiename)s');
+ """ % {'tabindex' : tabs.index(active_tab),
+ 'vid' : active_tab,
+ 'cookiename' : self.cookie_name})
-@monkeypatch(JSonController)
-def js_remember_active_tab(self, tabname):
- cookie = self.req.get_cookie()
- cookiename = '%s_active_tab' % self.config.appid
- cookie[cookiename] = tabname
- self.req.set_cookie(cookie, cookiename)
class EntityRelatedTab(EntityView):
"""A view you should inherit from leftmost,
--- a/web/webctl.py Thu Feb 19 20:19:05 2009 +0100
+++ b/web/webctl.py Thu Feb 19 20:21:10 2009 +0100
@@ -2,12 +2,12 @@
web configuration
:organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
-from cubicweb.toolsutils import CommandHandler
+from cubicweb.toolsutils import CommandHandler, confirm
class WebCreateHandler(CommandHandler):
@@ -22,7 +22,10 @@
print '** repository server configuration'
print '-' * 72
config.input_config('pyro-client', inputlevel)
-
+ if confirm('allow anonymous access', False):
+ config.global_set_option('anonymous-user', 'anon')
+ config.global_set_option('anonymous-password', 'anon')
+
def postcreate(self):
"""hooks called once application's initialization has been completed"""