# HG changeset patch # User Sylvain Thénault # Date 1312547035 -7200 # Node ID cbb0a0ce3795c18f66ed52365ff3ca1e98a79209 # Parent d313666c171e9e613beb7f71a65fe284de96817b# Parent 997b8eebd4b42d50b2103f3167ae6b626f90dea3 backport stable diff -r d313666c171e -r cbb0a0ce3795 .hgtags --- a/.hgtags Wed Jul 27 20:17:45 2011 +0200 +++ b/.hgtags Fri Aug 05 14:23:55 2011 +0200 @@ -218,3 +218,5 @@ 9ad5411199e00b2611366439b82f35d7d3285423 cubicweb-debian-version-3.13.2-1 0e82e7e5a34f57d7239c7a42e48ba4d5e53abab2 cubicweb-version-3.13.3 fb48c55cb80234bc0164c9bcc0e2cfc428836e5f cubicweb-debian-version-3.13.3-1 +223ecf0620b6c87d997f8011aca0d9f0ee4750af cubicweb-version-3.13.4 +52f26475d764129c5559b2d80fd57e6ea1bdd6ba cubicweb-debian-version-3.13.4-1 diff -r d313666c171e -r cbb0a0ce3795 README --- a/README Wed Jul 27 20:17:45 2011 +0200 +++ b/README Fri Aug 05 14:23:55 2011 +0200 @@ -5,20 +5,21 @@ developped at Logilab. This package contains: -* a repository server -* a RQL command line client to the repository -* an adaptative modpython interface to the server -* a bunch of other management tools + +- a repository server +- a RQL command line client to the repository +- an adaptative modpython interface to the server +- a bunch of other management tools Install ------- -More details at http://www.cubicweb.org/doc/en/admin/setup +More details at http://docs.cubicweb.org/admin/setup Getting started --------------- -Execute: +Execute:: apt-get install cubicweb cubicweb-dev cubicweb-blog cubicweb-ctl create blog myblog diff -r d313666c171e -r cbb0a0ce3795 __pkginfo__.py --- a/__pkginfo__.py Wed Jul 27 20:17:45 2011 +0200 +++ b/__pkginfo__.py Fri Aug 05 14:23:55 2011 +0200 @@ -22,7 +22,7 @@ modname = distname = "cubicweb" -numversion = (3, 13, 3) +numversion = (3, 13, 4) version = '.'.join(str(num) for num in numversion) description = "a repository of entities / relations for knowledge management" @@ -43,7 +43,7 @@ 'logilab-common': '>= 0.55.2', 'logilab-mtconverter': '>= 0.8.0', 'rql': '>= 0.28.0', - 'yams': '>= 0.32.0', + 'yams': '>= 0.33.0', 'docutils': '>= 0.6', #gettext # for xgettext, msgcat, etc... # web dependancies diff -r d313666c171e -r cbb0a0ce3795 debian/changelog --- a/debian/changelog Wed Jul 27 20:17:45 2011 +0200 +++ b/debian/changelog Fri Aug 05 14:23:55 2011 +0200 @@ -1,3 +1,9 @@ +cubicweb (3.13.4-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Fri, 05 Aug 2011 12:22:11 +0200 + cubicweb (3.13.3-1) unstable; urgency=low * new upstream release diff -r d313666c171e -r cbb0a0ce3795 debian/control --- a/debian/control Wed Jul 27 20:17:45 2011 +0200 +++ b/debian/control Fri Aug 05 14:23:55 2011 +0200 @@ -99,7 +99,7 @@ Package: cubicweb-common Architecture: all XB-Python-Version: ${python:Versions} -Depends: ${misc:Depends}, ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.8.0), python-logilab-common (>= 0.55.2), python-yams (>= 0.32.0), python-rql (>= 0.28.0), python-lxml +Depends: ${misc:Depends}, ${python:Depends}, graphviz, gettext, python-logilab-mtconverter (>= 0.8.0), python-logilab-common (>= 0.55.2), python-yams (>= 0.33.0), python-rql (>= 0.28.0), python-lxml Recommends: python-simpletal (>= 4.0), python-crypto Conflicts: cubicweb-core Replaces: cubicweb-core diff -r d313666c171e -r cbb0a0ce3795 devtools/__init__.py --- a/devtools/__init__.py Wed Jul 27 20:17:45 2011 +0200 +++ b/devtools/__init__.py Fri Aug 05 14:23:55 2011 +0200 @@ -657,6 +657,24 @@ class SQLiteTestDataBaseHandler(TestDataBaseHandler): DRIVER = 'sqlite' + __TMPDB = set() + + @classmethod + def _cleanup_all_tmpdb(cls): + for dbpath in cls.__TMPDB: + cls._cleanup_database(dbpath) + + + + def __init__(self, *args, **kwargs): + super(SQLiteTestDataBaseHandler, self).__init__(*args, **kwargs) + # use a dedicated base for each process. + if 'global-db-name' not in self.system_source: + self.system_source['global-db-name'] = self.system_source['db-name'] + process_db = self.system_source['db-name'] + str(os.getpid()) + self.__TMPDB.add(process_db) + self.system_source['db-name'] = process_db + @staticmethod def _cleanup_database(dbfile): try: @@ -665,6 +683,10 @@ except OSError: pass + @property + def dbname(self): + return self.system_source['global-db-name'] + def absolute_dbfile(self): """absolute path of current database file""" dbfile = join(self._ensure_test_backup_db_dir(), @@ -707,6 +729,9 @@ self._cleanup_database(self.absolute_dbfile()) init_repository(self.config, interactive=False) +import atexit +atexit.register(SQLiteTestDataBaseHandler._cleanup_all_tmpdb) + def install_sqlite_patch(querier): """This patch hotfixes the following sqlite bug : diff -r d313666c171e -r cbb0a0ce3795 devtools/devctl.py --- a/devtools/devctl.py Wed Jul 27 20:17:45 2011 +0200 +++ b/devtools/devctl.py Fri Aug 05 14:23:55 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -155,6 +155,9 @@ add_msg(w, cstrtype) done = set() for eschema in sorted(schema.entities()): + if eschema.type in libschema: + done.add(eschema.description) + for eschema in sorted(schema.entities()): etype = eschema.type if etype not in libschema: add_msg(w, etype) @@ -203,15 +206,19 @@ w('# (no object form for final or symmetric relation types)\n') w('\n') for rschema in sorted(schema.relations()): + if rschema.type in libschema: + done.add(rschema.type) + done.add(rschema.description) + for rschema in sorted(schema.relations()): rtype = rschema.type if rtype not in libschema: # bw compat, necessary until all translation of relation are done # properly... add_msg(w, rtype) + done.add(rtype) if rschema.description and rschema.description not in done: - done.add(rschema.description) add_msg(w, rschema.description) - done.add(rtype) + done.add(rschema.description) librschema = None else: librschema = libschema.rschema(rtype) @@ -221,7 +228,7 @@ for subjschema in rschema.subjects(): if not subjschema in libsubjects: add_msg(w, rtype, subjschema.type) - if not (schema.rschema(rtype).final or rschema.symmetric): + if not (rschema.final or rschema.symmetric): if rschema not in NO_I18NCONTEXT: libobjects = librschema and librschema.objects() or () for objschema in rschema.objects(): @@ -231,6 +238,14 @@ # bw compat, necessary until all translation of relation are # done properly... add_msg(w, '%s_object' % rtype) + for rdef in rschema.rdefs.itervalues(): + if not rdef.description or rdef.description in done: + continue + if (librschema is None or + (rdef.subject, rdef.object) not in librschema.rdefs or + librschema.rdefs[(rdef.subject, rdef.object)].description != rdef.description): + add_msg(w, rdef.description) + done.add(rdef.description) for objid in _iter_vreg_objids(vreg, vregdone): add_msg(w, '%s_description' % objid) add_msg(w, objid) diff -r d313666c171e -r cbb0a0ce3795 doc/book/en/annexes/rql/language.rst --- a/doc/book/en/annexes/rql/language.rst Wed Jul 27 20:17:45 2011 +0200 +++ b/doc/book/en/annexes/rql/language.rst Fri Aug 05 14:23:55 2011 +0200 @@ -113,9 +113,38 @@ `````````````````````` :: - +, -, *, / ++==========+=====================+===========+========+ +| Operator | Description | Example | Result | ++==========+=====================+===========+========+ +| + | addition | 2 + 3 | 5 | ++----------+---------------------+-----------+--------+ +| - | subtraction | 2 - 3 | -1 | ++----------+---------------------+-----------+--------+ +| * | multiplication | 2 * 3 | 6 | ++----------+---------------------+-----------+--------+ +| / | division | 4 / 2 | 2 | ++----------+---------------------+-----------+--------+ +| % | modulo (remainder) | 5 % 4 | 1 | ++----------+---------------------+-----------+--------+ +| ^ | exponentiation | 2.0 ^ 3.0 | 8 | ++----------+---------------------+-----------+--------+ +| & | bitwise AND | 91 & 15 | 11 | ++----------+---------------------+-----------+--------+ +| | | bitwise OR | 32 | 3 | 35 | ++----------+---------------------+-----------+--------+ +| # | bitwise XOR | 17 # 5 | 20 | ++----------+---------------------+-----------+--------+ +| ~ | bitwise NOT | ~1 | -2 | ++----------+---------------------+-----------+--------+ +| << | bitwise shift left | 1 << 4 | 16 | ++----------+---------------------+-----------+--------+ +| >> | bitwise shift right | 8 >> 2 | 2 | ++----------+---------------------+-----------+--------+ -Those should behave as you expect. + +, -, *, / + +Notice integer division truncates results depending on the backend behaviour. For +instance, postgresql does. .. _RQLComparisonOperators: @@ -191,13 +220,14 @@ Operators priority `````````````````` -#. "(", ")" -#. '*', '/' -#. '+', '-' -#. 'NOT' -#. 'AND' -#. 'OR' -#. ',' +#. `(`, `)` +#. `^`, `<<`, `>>` +#. `*`, `/`, `%`, `&` +#. `+`, `-`, `|`, `#` +#. `NOT` +#. `AND` +#. `OR` +#. `,` .. _RQLSearchQuery: @@ -328,7 +358,7 @@ You must use the `?` behind a variable to specify that the relation toward it is optional. For instance: -- Anomalies of a project attached or not to a version :: +- Bugs of a project attached or not to a version :: Any X, V WHERE X concerns P, P eid 42, X corrected_in V? @@ -340,6 +370,28 @@ Any C, P WHERE C is Card, P? documented_by C +Notice you may also use outer join: + +- on the RHS of attribute relation, e.g. :: + + Any X WHERE X ref XR, Y name XR? + + so that Y is outer joined on X by ref/name attributes comparison + + +- on any side of an `HAVING` expression, e.g. :: + + Any X WHERE X creation_date XC, Y creation_date YC + HAVING YEAR(XC)=YEAR(YC)? + + so that Y is outer joined on X by comparison of the year extracted from their + creation date. :: + + Any X WHERE X creation_date XC, Y creation_date YC + HAVING YEAR(XC)?=YEAR(YC) + + would outer join X on Y instead. + Having restrictions ``````````````````` diff -r d313666c171e -r cbb0a0ce3795 entities/lib.py --- a/entities/lib.py Wed Jul 27 20:17:45 2011 +0200 +++ b/entities/lib.py Fri Aug 05 14:23:55 2011 +0200 @@ -40,6 +40,7 @@ class EmailAddress(AnyEntity): __regid__ = 'EmailAddress' fetch_attrs, fetch_order = fetch_config(['address', 'alias']) + rest_attr = 'eid' def dc_title(self): if self.alias: diff -r d313666c171e -r cbb0a0ce3795 ext/rest.py --- a/ext/rest.py Wed Jul 27 20:17:45 2011 +0200 +++ b/ext/rest.py Fri Aug 05 14:23:55 2011 +0200 @@ -105,11 +105,17 @@ else: rql, vid = text, None _cw.ensure_ro_rql(rql) - rset = _cw.execute(rql, {'userid': _cw.user.eid}) - if vid is None: - vid = vid_from_rset(_cw, rset, _cw.vreg.schema) - view = _cw.vreg['views'].select(vid, _cw, rset=rset) - content = view.render() + try: + rset = _cw.execute(rql, {'userid': _cw.user.eid}) + if rset: + if vid is None: + vid = vid_from_rset(_cw, rset, _cw.vreg.schema) + else: + vid = 'noresult' + view = _cw.vreg['views'].select(vid, _cw, rset=rset) + content = view.render() + except Exception, exc: + content = 'an error occured while interpreting this rql directive: %r' % exc set_classes(options) return [nodes.raw('', content, format='html')], [] diff -r d313666c171e -r cbb0a0ce3795 ext/test/unittest_rest.py --- a/ext/test/unittest_rest.py Wed Jul 27 20:17:45 2011 +0200 +++ b/ext/test/unittest_rest.py Fri Aug 05 14:23:55 2011 +0200 @@ -63,6 +63,16 @@ self.assert_(out.endswith('anon' '\n\n

\n')) + def test_rql_role_with_vid_empty_rset(self): + context = self.context() + out = rest_publish(context, ':rql:`Any X WHERE X is CWUser, X login "nono":table`') + self.assert_(out.endswith('

No result matching query
\n

\n')) + + def test_rql_role_with_unknown_vid(self): + context = self.context() + out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`') + self.assert_(out.startswith("

an error occured while interpreting this rql directive: ObjectNotFound(u'toto',)

")) + def test_rql_role_without_vid(self): context = self.context() out = rest_publish(context, ':rql:`Any X WHERE X is CWUser`') diff -r d313666c171e -r cbb0a0ce3795 hooks/syncsources.py --- a/hooks/syncsources.py Wed Jul 27 20:17:45 2011 +0200 +++ b/hooks/syncsources.py Fri Aug 05 14:23:55 2011 +0200 @@ -19,6 +19,7 @@ from socket import gethostname +from logilab.common.decorators import clear_cache from yams.schema import role_name from cubicweb import ValidationError @@ -66,7 +67,7 @@ SourceRemovedOp(self._cw, uri=self.entity.name) -class SourceUpdatedOp(hook.DataOperationMixIn, hook.Operation): +class SourceConfigUpdatedOp(hook.DataOperationMixIn, hook.Operation): def precommit_event(self): self.__processed = [] @@ -79,13 +80,45 @@ for source, conf in self.__processed: source.repo_source.update_config(source, conf) + +class SourceRenamedOp(hook.LateOperation): + + def precommit_event(self): + source = self.session.repo.sources_by_uri[self.oldname] + if source.copy_based_source: + sql = 'UPDATE entities SET asource=%(newname)s WHERE asource=%(oldname)s' + else: + sql = 'UPDATE entities SET source=%(newname)s, asource=%(newname)s WHERE source=%(oldname)s' + self.session.system_sql(sql, {'oldname': self.oldname, + 'newname': self.newname}) + + def postcommit_event(self): + repo = self.session.repo + # XXX race condition + source = repo.sources_by_uri.pop(self.oldname) + source.uri = self.newname + source.public_config['uri'] = self.newname + repo.sources_by_uri[self.newname] = source + repo._type_source_cache.clear() + clear_cache(repo, 'source_defs') + if not source.copy_based_source: + repo._extid_cache.clear() + repo._clear_planning_caches() + for cnxset in repo.cnxsets: + cnxset.source_cnxs[self.oldname] = cnxset.source_cnxs.pop(self.oldname) + + class SourceUpdatedHook(SourceHook): __regid__ = 'cw.sources.configupdate' __select__ = SourceHook.__select__ & is_instance('CWSource') - events = ('after_update_entity',) + events = ('before_update_entity',) def __call__(self): if 'config' in self.entity.cw_edited: - SourceUpdatedOp.get_instance(self._cw).add_data(self.entity) + SourceConfigUpdatedOp.get_instance(self._cw).add_data(self.entity) + if 'name' in self.entity.cw_edited: + oldname, newname = self.entity.cw_edited.oldnewvalue('name') + SourceRenamedOp(self._cw, oldname=oldname, newname=newname) + class SourceHostConfigUpdatedHook(SourceHook): __regid__ = 'cw.sources.hostconfigupdate' @@ -97,7 +130,7 @@ not 'config' in self.entity.cw_edited: return try: - SourceUpdatedOp.get_instance(self._cw).add_data(self.entity.cwsource) + SourceConfigUpdatedOp.get_instance(self._cw).add_data(self.entity.cwsource) except IndexError: # XXX no source linked to the host config yet pass diff -r d313666c171e -r cbb0a0ce3795 i18n/de.po --- a/i18n/de.po Wed Jul 27 20:17:45 2011 +0200 +++ b/i18n/de.po Fri Aug 05 14:23:55 2011 +0200 @@ -1250,6 +1250,9 @@ msgid "auto" msgstr "automatisch" +msgid "autocomputed attribute used to ensure transition coherency" +msgstr "" + msgid "automatic" msgstr "automatisch" @@ -2288,9 +2291,6 @@ msgid "eid" msgstr "" -msgid "email address to use for notification" -msgstr "E-Mail-Adresse für Mitteilungen." - msgid "emails successfully sent" msgstr "E-Mails erfolgreich versandt." @@ -2619,6 +2619,18 @@ msgid "groups" msgstr "Gruppen" +msgid "groups allowed to add entities/relations of this type" +msgstr "" + +msgid "groups allowed to delete entities/relations of this type" +msgstr "" + +msgid "groups allowed to read entities/relations of this type" +msgstr "" + +msgid "groups allowed to update entities/relations of this type" +msgstr "" + msgid "groups grant permissions to the user" msgstr "die Gruppen geben dem Nutzer Rechte" @@ -3604,6 +3616,18 @@ msgid "right" msgstr "rechts" +msgid "rql expression allowing to add entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to delete entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to read entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to update entities/relations of this type" +msgstr "" + msgid "rql expressions" msgstr "RQL-Ausdrücke" @@ -4323,6 +4347,9 @@ msgid "user preferences" msgstr "Nutzereinstellungen" +msgid "user's email account" +msgstr "" + msgid "users" msgstr "Nutzer" @@ -4521,3 +4548,6 @@ #, python-format msgid "you should un-inline relation %s which is supported and may be crossed " msgstr "" + +#~ msgid "email address to use for notification" +#~ msgstr "E-Mail-Adresse für Mitteilungen." diff -r d313666c171e -r cbb0a0ce3795 i18n/en.po --- a/i18n/en.po Wed Jul 27 20:17:45 2011 +0200 +++ b/i18n/en.po Fri Aug 05 14:23:55 2011 +0200 @@ -1205,6 +1205,9 @@ msgid "auto" msgstr "automatic" +msgid "autocomputed attribute used to ensure transition coherency" +msgstr "" + msgid "automatic" msgstr "" @@ -2233,9 +2236,6 @@ msgid "eid" msgstr "" -msgid "email address to use for notification" -msgstr "" - msgid "emails successfully sent" msgstr "" @@ -2554,6 +2554,18 @@ msgid "groups" msgstr "" +msgid "groups allowed to add entities/relations of this type" +msgstr "" + +msgid "groups allowed to delete entities/relations of this type" +msgstr "" + +msgid "groups allowed to read entities/relations of this type" +msgstr "" + +msgid "groups allowed to update entities/relations of this type" +msgstr "" + msgid "groups grant permissions to the user" msgstr "" @@ -3511,6 +3523,18 @@ msgid "right" msgstr "" +msgid "rql expression allowing to add entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to delete entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to read entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to update entities/relations of this type" +msgstr "" + msgid "rql expressions" msgstr "" @@ -4209,6 +4233,9 @@ msgid "user preferences" msgstr "" +msgid "user's email account" +msgstr "" + msgid "users" msgstr "" diff -r d313666c171e -r cbb0a0ce3795 i18n/es.po --- a/i18n/es.po Wed Jul 27 20:17:45 2011 +0200 +++ b/i18n/es.po Fri Aug 05 14:23:55 2011 +0200 @@ -1261,6 +1261,9 @@ msgid "auto" msgstr "Automático" +msgid "autocomputed attribute used to ensure transition coherency" +msgstr "" + msgid "automatic" msgstr "Automático" @@ -2327,9 +2330,6 @@ msgid "eid" msgstr "eid" -msgid "email address to use for notification" -msgstr "Dirección electrónica a utilizarse para notificar" - msgid "emails successfully sent" msgstr "Mensajes enviados con éxito" @@ -2661,6 +2661,18 @@ msgid "groups" msgstr "Grupos" +msgid "groups allowed to add entities/relations of this type" +msgstr "" + +msgid "groups allowed to delete entities/relations of this type" +msgstr "" + +msgid "groups allowed to read entities/relations of this type" +msgstr "" + +msgid "groups allowed to update entities/relations of this type" +msgstr "" + msgid "groups grant permissions to the user" msgstr "Los grupos otorgan los permisos al usuario" @@ -3654,6 +3666,18 @@ msgid "right" msgstr "Derecha" +msgid "rql expression allowing to add entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to delete entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to read entities/relations of this type" +msgstr "" + +msgid "rql expression allowing to update entities/relations of this type" +msgstr "" + msgid "rql expressions" msgstr "Expresiones RQL" @@ -4373,6 +4397,9 @@ msgid "user preferences" msgstr "Preferencias" +msgid "user's email account" +msgstr "" + msgid "users" msgstr "Usuarios" @@ -4576,3 +4603,6 @@ #~ msgctxt "CWAttribute" #~ msgid "cw_schema_object" #~ msgstr "mapeado por" + +#~ msgid "email address to use for notification" +#~ msgstr "Dirección electrónica a utilizarse para notificar" diff -r d313666c171e -r cbb0a0ce3795 i18n/fr.po --- a/i18n/fr.po Wed Jul 27 20:17:45 2011 +0200 +++ b/i18n/fr.po Fri Aug 05 14:23:55 2011 +0200 @@ -164,7 +164,7 @@ #, python-format msgid "" "'%s' action for in_state relation should at least have 'linkattr=name' option" -msgstr "" +msgstr "l'action '%s' pour la relation in_state doit au moins avoir l'option 'linkattr=name'" #, python-format msgid "'%s' action requires 'linkattr' option" @@ -1174,7 +1174,7 @@ #, python-format msgid "allowed values for \"action\" are %s" -msgstr "" +msgstr "les valeurs autorisées pour \"action\" sont %s" msgid "allowed_transition" msgstr "transitions autorisées" @@ -1259,6 +1259,9 @@ msgid "auto" msgstr "automatique" +msgid "autocomputed attribute used to ensure transition coherency" +msgstr "attribut calculé automatiquement pour assurer la cohérence de la transition" + msgid "automatic" msgstr "automatique" @@ -2326,9 +2329,6 @@ msgid "eid" msgstr "eid" -msgid "email address to use for notification" -msgstr "adresse email à utiliser pour la notification" - msgid "emails successfully sent" msgstr "courriels envoyés avec succès" @@ -2660,6 +2660,18 @@ msgid "groups" msgstr "groupes" +msgid "groups allowed to add entities/relations of this type" +msgstr "groupes autorisés à ajouter des entités/relations de ce type" + +msgid "groups allowed to delete entities/relations of this type" +msgstr "groupes autorisés à supprimer des entités/relations de ce type" + +msgid "groups allowed to read entities/relations of this type" +msgstr "groupes autorisés à lire des entités/relations de ce type" + +msgid "groups allowed to update entities/relations of this type" +msgstr "groupes autorisés à mettre à jour des entités/relations de ce type" + msgid "groups grant permissions to the user" msgstr "les groupes donnent des permissions à l'utilisateur" @@ -3239,10 +3251,10 @@ msgstr "aucune permission associée" msgid "no content next link" -msgstr "" +msgstr "pas de lien 'suivant'" msgid "no content prev link" -msgstr "" +msgstr "pas de lien 'précédent'" msgid "no edited fields specified" msgstr "aucun champ à éditer spécifié" @@ -3655,6 +3667,18 @@ msgid "right" msgstr "droite" +msgid "rql expression allowing to add entities/relations of this type" +msgstr "expression rql autorisant à ajouter des entités/relations de ce type" + +msgid "rql expression allowing to delete entities/relations of this type" +msgstr "expression rql autorisant à supprimer des entités/relations de ce type" + +msgid "rql expression allowing to read entities/relations of this type" +msgstr "expression rql autorisant à lire des entités/relations de ce type" + +msgid "rql expression allowing to update entities/relations of this type" +msgstr "expression rql autorisant à mettre à jour des entités/relations de ce type" + msgid "rql expressions" msgstr "conditions rql" @@ -4013,10 +4037,10 @@ msgstr "la valeur \"%s\" est déjà utilisée, veuillez utiliser une autre valeur" msgid "there is no next page" -msgstr "" +msgstr "il n'y a pas de page suivante" msgid "there is no previous page" -msgstr "" +msgstr "il n'y a pas de page précédente" msgid "this action is not reversible!" msgstr "" @@ -4372,6 +4396,9 @@ msgid "user preferences" msgstr "préférences utilisateur" +msgid "user's email account" +msgstr "email de l'utilisateur" + msgid "users" msgstr "utilisateurs" @@ -4572,7 +4599,3 @@ msgstr "" "vous devriez enlevé la mise en ligne de la relation %s qui est supportée et " "peut-être croisée" - -#~ msgctxt "CWAttribute" -#~ msgid "cw_schema_object" -#~ msgstr "mappé par" diff -r d313666c171e -r cbb0a0ce3795 misc/migration/bootstrapmigration_repository.py --- a/misc/migration/bootstrapmigration_repository.py Wed Jul 27 20:17:45 2011 +0200 +++ b/misc/migration/bootstrapmigration_repository.py Fri Aug 05 14:23:55 2011 +0200 @@ -36,7 +36,7 @@ commit(ask_confirm=False) if applcubicwebversion <= (3, 13, 0) and cubicwebversion >= (3, 13, 1): - sql('ALTER TABLE entities ADD COLUMN asource VARCHAR(64)') + sql('ALTER TABLE entities ADD asource VARCHAR(64)') sql('UPDATE entities SET asource=cw_name ' 'FROM cw_CWSource, cw_source_relation ' 'WHERE entities.eid=cw_source_relation.eid_from AND cw_source_relation.eid_to=cw_CWSource.cw_eid') diff -r d313666c171e -r cbb0a0ce3795 schemas/base.py --- a/schemas/base.py Wed Jul 27 20:17:45 2011 +0200 +++ b/schemas/base.py Fri Aug 05 14:23:55 2011 +0200 @@ -42,12 +42,6 @@ firstname = String(maxsize=64) surname = String(maxsize=64) last_login_time = Datetime(description=_('last connection date')) - # allowing an email to be the primary email of multiple entities is necessary for - # test at least :-/ - primary_email = SubjectRelation('EmailAddress', cardinality='??', - description=_('email address to use for notification')) - use_email = SubjectRelation('EmailAddress', cardinality='*?', composite='subject') - in_group = SubjectRelation('CWGroup', cardinality='+*', constraints=[RQLConstraint('NOT O name "owners"')], description=_('groups grant permissions to the user')) @@ -71,17 +65,35 @@ to indicate which is the preferred form.')) class use_email(RelationType): - """ """ + fulltext_container = 'subject' + + +class use_email_relation(RelationDefinition): + """user's email account""" + name = "use_email" __permissions__ = { 'read': ('managers', 'users', 'guests',), 'add': ('managers', RRQLExpression('U has_update_permission S'),), 'delete': ('managers', RRQLExpression('U has_update_permission S'),), } - fulltext_container = 'subject' + subject = "CWUser" + object = "EmailAddress" + cardinality = '*?' + composite = 'subject' + -class primary_email(RelationType): +class primary_email(RelationDefinition): """the prefered email""" - __permissions__ = use_email.__permissions__ + __permissions__ = { + 'read': ('managers', 'users', 'guests',), + 'add': ('managers', RRQLExpression('U has_update_permission S'),), + 'delete': ('managers', RRQLExpression('U has_update_permission S'),), + } + subject = "CWUser" + object = "EmailAddress" + cardinality = '??' + constraints= [RQLConstraint('S use_email O')] + class prefered_form(RelationType): __permissions__ = { diff -r d313666c171e -r cbb0a0ce3795 server/repository.py --- a/server/repository.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/repository.py Fri Aug 05 14:23:55 2011 +0200 @@ -505,12 +505,7 @@ This is a public method, not requiring a session id. """ - try: - # necessary to support pickling used by pyro - self.schema.__hashmode__ = 'pickle' - return self.schema - finally: - self.schema.__hashmode__ = None + return self.schema def get_cubes(self): """Return the list of cubes used by this instance. diff -r d313666c171e -r cbb0a0ce3795 server/rqlannotation.py --- a/server/rqlannotation.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/rqlannotation.py Fri Aug 05 14:23:55 2011 +0200 @@ -109,8 +109,9 @@ ostinfo = rhs.children[0].variable.stinfo else: ostinfo = lhs.variable.stinfo - if not any(orel for orel in ostinfo['relations'] - if orel.optional and orel is not rel): + if not (ostinfo.get('optcomparisons') or + any(orel for orel in ostinfo['relations'] + if orel.optional and orel is not rel)): break if rschema.final or (onlhs and rschema.inlined): if rschema.type != 'has_text': diff -r d313666c171e -r cbb0a0ce3795 server/session.py --- a/server/session.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/session.py Fri Aug 05 14:23:55 2011 +0200 @@ -1180,7 +1180,8 @@ def _build_descr(self, result, basedescription, todetermine): description = [] etype_from_eid = self.describe - for row in result: + todel = [] + for i, row in enumerate(result): row_descr = basedescription[:] for index, isfinal in todetermine: value = row[index] @@ -1194,10 +1195,14 @@ try: row_descr[index] = etype_from_eid(value)[0] except UnknownEid: - self.critical('wrong eid %s in repository, you should ' - 'db-check the database' % value) - row_descr[index] = row[index] = None - description.append(tuple(row_descr)) + self.error('wrong eid %s in repository, you should ' + 'db-check the database' % value) + todel.append(i) + break + else: + description.append(tuple(row_descr)) + for i in reversed(todel): + del result[i] return description # deprecated ############################################################### diff -r d313666c171e -r cbb0a0ce3795 server/sources/datafeed.py --- a/server/sources/datafeed.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/sources/datafeed.py Fri Aug 05 14:23:55 2011 +0200 @@ -218,7 +218,7 @@ """ entity = super(DataFeedSource, self).before_entity_insertion( session, lid, etype, eid, sourceparams) - entity.cw_edited['cwuri'] = unicode(lid) + entity.cw_edited['cwuri'] = lid.decode('utf-8') entity.cw_edited.set_defaults() sourceparams['parser'].before_entity_copy(entity, sourceparams) return entity @@ -275,6 +275,8 @@ else: source = self.source sourceparams['parser'] = self + if isinstance(uri, unicode): + uri = uri.encode('utf-8') try: eid = session.repo.extid2eid(source, str(uri), etype, session, complete=False, commit=False, @@ -351,10 +353,10 @@ def parse(self, url): if url.startswith('http'): - from cubicweb.sobjects.parsers import HOST_MAPPING - for mappedurl in HOST_MAPPING: + from cubicweb.sobjects.parsers import URL_MAPPING + for mappedurl in URL_MAPPING: if url.startswith(mappedurl): - url = url.replace(mappedurl, HOST_MAPPING[mappedurl], 1) + url = url.replace(mappedurl, URL_MAPPING[mappedurl], 1) break self.source.info('GET %s', url) stream = _OPENER.open(url) diff -r d313666c171e -r cbb0a0ce3795 server/sources/rql2sql.py --- a/server/sources/rql2sql.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/sources/rql2sql.py Fri Aug 05 14:23:55 2011 +0200 @@ -1238,35 +1238,47 @@ def _visit_outer_join_inlined_relation(self, relation, rschema): - leftvar, leftconst, rightvar, rightconst = relation_info(relation) - assert not (leftconst and rightconst), "doesn't make sense" - if relation.optional != 'right': - leftvar, rightvar = rightvar, leftvar - leftconst, rightconst = rightconst, leftconst - outertype = 'FULL' if relation.optional == 'both' else 'LEFT' - leftalias = self._var_table(leftvar) + lhsvar, lhsconst, rhsvar, rhsconst = relation_info(relation) + assert not (lhsconst and rhsconst), "doesn't make sense" attr = 'eid' if relation.r_type == 'identity' else relation.r_type - lhs, rhs = relation.get_variable_parts() + lhsalias = self._var_table(lhsvar) + rhsalias = rhsvar and self._var_table(rhsvar) try: - lhssql = self._varmap['%s.%s' % (lhs.name, attr)] + lhssql = self._varmap['%s.%s' % (lhsvar.name, attr)] except KeyError: - lhssql = '%s.%s%s' % (self._var_table(lhs.variable), SQL_PREFIX, attr) - if rightvar is not None: - rightalias = self._var_table(rightvar) - if rightalias is None: - if rightconst is not None: - # inlined relation with invariant as rhs - condition = '%s=%s' % (lhssql, rightconst.accept(self)) - if relation.r_type != 'identity': - condition = '(%s OR %s IS NULL)' % (condition, lhssql) - if not leftvar.stinfo.get('optrelations'): - return condition - self._state.add_outer_join_condition(leftalias, condition) - return - if leftalias is None: - leftalias = leftvar._q_sql.split('.', 1)[0] - self._state.replace_tables_by_outer_join( - leftalias, rightalias, outertype, '%s=%s' % (lhssql, rhs.accept(self))) + if lhsalias is None: + lhssql = lhsconst.accept(self) + else: + lhssql = '%s.%s%s' % (lhsalias, SQL_PREFIX, attr) + condition = '%s=%s' % (lhssql, (rhsconst or rhsvar).accept(self)) + # this is not a typo, rhs optional variable means lhs outer join and vice-versa + if relation.optional == 'left': + lhsvar, rhsvar = rhsvar, lhsvar + lhsconst, rhsconst = rhsconst, lhsconst + lhsalias, rhsalias = rhsalias, lhsalias + outertype = 'LEFT' + elif relation.optional == 'both': + outertype = 'FULL' + else: + outertype = 'LEFT' + if rhsalias is None: + if rhsconst is not None: + # inlined relation with invariant as rhs + if relation.r_type != 'identity': + condition = '(%s OR %s IS NULL)' % (condition, lhssql) + if not lhsvar.stinfo.get('optrelations'): + return condition + self._state.add_outer_join_condition(lhsalias, condition) + return + if lhsalias is None: + if lhsconst is not None and not rhsvar.stinfo.get('optrelations'): + return condition + lhsalias = lhsvar._q_sql.split('.', 1)[0] + if lhsalias == rhsalias: + self._state.add_outer_join_condition(lhsalias, condition) + else: + self._state.replace_tables_by_outer_join( + lhsalias, rhsalias, outertype, condition) return '' def _visit_var_attr_relation(self, relation, rhs_vars): @@ -1442,6 +1454,10 @@ pass return '(%s %s %s)'% (lhs.accept(self), operator, rhs.accept(self)) + def visit_unaryexpression(self, uexpr): + """generate SQL for a unary expression""" + return '%s%s'% (uexpr.operator, uexpr.children[0].accept(self)) + def visit_function(self, func): """generate SQL name for a function""" if func.name == 'FTIRANK': diff -r d313666c171e -r cbb0a0ce3795 server/test/unittest_datafeed.py --- a/server/test/unittest_datafeed.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/test/unittest_datafeed.py Fri Aug 05 14:23:55 2011 +0200 @@ -94,9 +94,26 @@ self.assertTrue(dfsource.latest_retrieval) self.assertTrue(dfsource.fresh()) + # test_rename_source + req = self.request() + req.execute('SET S name "myrenamedfeed" WHERE S is CWSource, S name "myfeed"') + self.commit() + entity = self.execute('Card X').get_entity(0, 0) + self.assertEqual(entity.cwuri, 'http://www.cubicweb.org/') + self.assertEqual(entity.cw_source[0].name, 'myrenamedfeed') + self.assertEqual(entity.cw_metainformation(), + {'type': 'Card', + 'source': {'uri': 'myrenamedfeed', 'type': 'datafeed', 'use-cwuri-as-url': True}, + 'extid': 'http://www.cubicweb.org/'} + ) + self.assertEqual(self.repo._type_source_cache[entity.eid], + ('Card', 'system', 'http://www.cubicweb.org/', 'myrenamedfeed')) + self.assertEqual(self.repo._extid_cache[('http://www.cubicweb.org/', 'system')], + entity.eid) + # test_delete_source req = self.request() - req.execute('DELETE CWSource S WHERE S name "myfeed"') + req.execute('DELETE CWSource S WHERE S name "myrenamedfeed"') self.commit() self.failIf(self.execute('Card X WHERE X title "cubicweb.org"')) self.failIf(self.execute('Any X WHERE X has_text "cubicweb.org"')) diff -r d313666c171e -r cbb0a0ce3795 server/test/unittest_repository.py --- a/server/test/unittest_repository.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/test/unittest_repository.py Fri Aug 05 14:23:55 2011 +0200 @@ -366,7 +366,6 @@ schema = cnx.get_schema() self.failUnless(cnx.vreg) self.failUnless('etypes'in cnx.vreg) - self.assertEqual(schema.__hashmode__, None) cu = cnx.cursor() rset = cu.execute('Any U,G WHERE U in_group G') user = iter(rset.entities()).next() diff -r d313666c171e -r cbb0a0ce3795 server/test/unittest_rql2sql.py --- a/server/test/unittest_rql2sql.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/test/unittest_rql2sql.py Fri Aug 05 14:23:55 2011 +0200 @@ -88,7 +88,6 @@ ] BASIC = [ - ("Any AS WHERE AS is Affaire", '''SELECT _AS.cw_eid FROM cw_Affaire AS _AS'''), @@ -201,7 +200,12 @@ ('Any X WHERE X title V, NOT X wikiid V, NOT X title "parent", X is Card', '''SELECT _X.cw_eid FROM cw_Card AS _X -WHERE NOT (_X.cw_wikiid=_X.cw_title) AND NOT (_X.cw_title=parent)''') +WHERE NOT (_X.cw_wikiid=_X.cw_title) AND NOT (_X.cw_title=parent)'''), + + ("Any -AS WHERE AS is Affaire", + '''SELECT -_AS.cw_eid +FROM cw_Affaire AS _AS'''), + ] BASIC_WITH_LIMIT = [ @@ -972,7 +976,7 @@ ('Any CASE, CALIBCFG, CFG ' 'WHERE CASE eid 1, CFG ecrit_par CASE, CALIBCFG? ecrit_par CASE', '''SELECT _CFG.cw_ecrit_par, _CALIBCFG.cw_eid, _CFG.cw_eid -FROM cw_Note AS _CFG LEFT OUTER JOIN cw_Note AS _CALIBCFG ON (_CALIBCFG.cw_ecrit_par=_CFG.cw_ecrit_par) +FROM cw_Note AS _CFG LEFT OUTER JOIN cw_Note AS _CALIBCFG ON (_CALIBCFG.cw_ecrit_par=1) WHERE _CFG.cw_ecrit_par=1'''), ('Any U,G WHERE U login UL, G name GL, G is CWGroup HAVING UPPER(UL)=UPPER(GL)?', @@ -986,6 +990,17 @@ ('Any U,G WHERE U login UL, G name GL, G is CWGroup HAVING UPPER(UL)?=UPPER(GL)?', '''SELECT _U.cw_eid, _G.cw_eid FROM cw_CWUser AS _U FULL OUTER JOIN cw_CWGroup AS _G ON (UPPER(_U.cw_login)=UPPER(_G.cw_name))'''), + + ('Any H, COUNT(X), SUM(XCE)/1000 ' + 'WHERE X type "0", X date XSCT, X para XCE, X? ecrit_par F, F eid 999999, F is Personne, ' + 'DH is Affaire, DH ref H ' + 'HAVING XSCT?=H', + '''SELECT _DH.cw_ref, COUNT(_X.cw_eid), (SUM(_X.cw_para) / 1000) +FROM cw_Affaire AS _DH LEFT OUTER JOIN cw_Note AS _X ON (_X.cw_date=_DH.cw_ref AND _X.cw_type=0 AND _X.cw_ecrit_par=999999)'''), + + ('Any C WHERE X ecrit_par C?, X? inline1 F, F eid 1, X type XT, Z is Personne, Z nom ZN HAVING ZN=XT?', + '''SELECT _X.cw_ecrit_par +FROM cw_Personne AS _Z LEFT OUTER JOIN cw_Note AS _X ON (_Z.cw_nom=_X.cw_type AND _X.cw_inline1=1)'''), ] VIRTUAL_VARS = [ @@ -1721,7 +1736,7 @@ class SqlServer2005SQLGeneratorTC(PostgresSQLGeneratorTC): backend = 'sqlserver2005' def _norm_sql(self, sql): - return sql.strip().replace(' SUBSTR', ' SUBSTRING').replace(' || ', ' + ').replace(' ILIKE ', ' LIKE ') + return sql.strip().replace(' SUBSTR', ' SUBSTRING').replace(' || ', ' + ').replace(' ILIKE ', ' LIKE ').replace('TRUE', '1').replace('FALSE', '0') def test_has_text(self): for t in self._parse(HAS_TEXT_LG_INDEXER): diff -r d313666c171e -r cbb0a0ce3795 server/test/unittest_session.py --- a/server/test/unittest_session.py Wed Jul 27 20:17:45 2011 +0200 +++ b/server/test/unittest_session.py Fri Aug 05 14:23:55 2011 +0200 @@ -78,5 +78,15 @@ self.assertEqual(session._tx_data, {}) self.assertEqual(session.cnxset, None) + def test_build_descr(self): + rset = self.execute('(Any U,L WHERE U login L) UNION (Any G,N WHERE G name N, G is CWGroup)') + orig_length = len(rset) + rset.rows[0][0] = 9999999 + description = self.session.build_description(rset.syntax_tree(), None, rset.rows) + self.assertEqual(len(description), orig_length - 1) + self.assertEqual(len(rset.rows), orig_length - 1) + self.failIf(rset.rows[0][0] == 9999999) + + if __name__ == '__main__': unittest_main() diff -r d313666c171e -r cbb0a0ce3795 sobjects/parsers.py --- a/sobjects/parsers.py Wed Jul 27 20:17:45 2011 +0200 +++ b/sobjects/parsers.py Fri Aug 05 14:23:55 2011 +0200 @@ -459,10 +459,10 @@ def registration_callback(vreg): vreg.register_all(globals().values(), __name__) - global HOST_MAPPING - HOST_MAPPING = {} + global URL_MAPPING + URL_MAPPING = {} if vreg.config.apphome: - host_mapping_file = osp.join(vreg.config.apphome, 'hostmapping.py') - if osp.exists(host_mapping_file): - HOST_MAPPING = eval(file(host_mapping_file).read()) - vreg.info('using host mapping %s from %s', HOST_MAPPING, host_mapping_file) + url_mapping_file = osp.join(vreg.config.apphome, 'urlmapping.py') + if osp.exists(url_mapping_file): + URL_MAPPING = eval(file(url_mapping_file).read()) + vreg.info('using url mapping %s from %s', URL_MAPPING, url_mapping_file) diff -r d313666c171e -r cbb0a0ce3795 web/data/cubicweb.reset.css --- a/web/data/cubicweb.reset.css Wed Jul 27 20:17:45 2011 +0200 +++ b/web/data/cubicweb.reset.css Fri Aug 05 14:23:55 2011 +0200 @@ -1,53 +1,48 @@ -/* http://meyerweb.com/eric/tools/css/reset/ */ -/* v1.0 | 20080212 */ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0 | 20110126 + License: none (public domain) +*/ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, -del, dfn, em, font, img, ins, kbd, q, s, samp, +del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td { - margin: 0; - padding: 0; - border: 0; - outline: 0; - font-size: 100%; - vertical-align: baseline; - background: transparent; +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; } body { - line-height: 1; + line-height: 1; } ol, ul { - list-style: none; + list-style: none; } blockquote, q { - quotes: none; + quotes: none; } blockquote:before, blockquote:after, q:before, q:after { - content: ''; - content: none; -} - -/* remember to define focus styles! */ -:focus { - outline: 0; + content: ''; + content: none; } - -/* remember to highlight inserts somehow! */ -ins { - text-decoration: none; -} -del { - text-decoration: line-through; -} - -/* tables still need 'cellspacing="0"' in the markup */ table { - border-collapse: collapse; - border-spacing: 0; + border-collapse: collapse; + border-spacing: 0; } \ No newline at end of file diff -r d313666c171e -r cbb0a0ce3795 web/test/unittest_views_editforms.py --- a/web/test/unittest_views_editforms.py Wed Jul 27 20:17:45 2011 +0200 +++ b/web/test/unittest_views_editforms.py Fri Aug 05 14:23:55 2011 +0200 @@ -77,9 +77,9 @@ # (appears here while expected in hidden self.assertListEqual([x for x in rbc(e, 'main', 'relations') if x != ('tags', 'object')], - [('primary_email', 'subject'), - ('connait', 'subject'), + [('connait', 'subject'), ('custom_workflow', 'subject'), + ('primary_email', 'subject'), ('checked_by', 'object'), ]) self.assertListEqual(rbc(e, 'main', 'inlined'), diff -r d313666c171e -r cbb0a0ce3795 web/views/actions.py --- a/web/views/actions.py Wed Jul 27 20:17:45 2011 +0200 +++ b/web/views/actions.py Fri Aug 05 14:23:55 2011 +0200 @@ -135,8 +135,13 @@ params = self._cw.form.copy() for param in ('vid', '__message') + controller.NAV_FORM_PARAMETERS: params.pop(param, None) - return self._cw.build_url(self._cw.relative_path(includeparams=False), - **params) + if self._cw.json_request: + path = 'view' + if self.cw_rset is not None: + params = {'rql': self.cw_rset.printable_rql()} + else: + path = self._cw.relative_path(includeparams=False) + return self._cw.build_url(path, **params) class ModifyAction(action.Action): @@ -163,7 +168,7 @@ order = 10 def url(self): - return self._cw.build_url('view', rql=self.cw_rset.rql, vid='muledit') + return self._cw.build_url('view', rql=self.cw_rset.printable_rql(), vid='muledit') # generic "more" actions ####################################################### diff -r d313666c171e -r cbb0a0ce3795 web/views/cwuser.py --- a/web/views/cwuser.py Wed Jul 27 20:17:45 2011 +0200 +++ b/web/views/cwuser.py Fri Aug 05 14:23:55 2011 +0200 @@ -168,6 +168,10 @@ class CWUserManagementView(StartupView): __regid__ = 'cw.user-management' + # XXX one could wish to display for instance only user's firstname/surname + # for non managers but filtering out NULL cause crash with an ldapuser + # source. + __select__ = StartupView.__select__ & match_user_groups('managers') rql = ('Any U,USN,F,S,U,UAA,UDS, L,UAA,UDSN ORDERBY L WHERE U is CWUser, ' 'U login L, U firstname F, U surname S, ' 'U in_state US, US name USN, ' diff -r d313666c171e -r cbb0a0ce3795 web/views/emailaddress.py --- a/web/views/emailaddress.py Wed Jul 27 20:17:45 2011 +0200 +++ b/web/views/emailaddress.py Fri Aug 05 14:23:55 2011 +0200 @@ -15,9 +15,8 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -"""Specific views for email addresses entities +"""Specific views for email addresses entities""" -""" __docformat__ = "restructuredtext en" from logilab.mtconverter import xml_escape @@ -85,8 +84,7 @@ class EmailAddressOneLineView(baseviews.OneLineView): __select__ = is_instance('EmailAddress') - def cell_call(self, row, col, **kwargs): - entity = self.cw_rset.get_entity(row, col) + def entity_call(self, entity, **kwargs): if entity.reverse_primary_email: self.w(u'') if entity.alias: @@ -106,8 +104,7 @@ __regid__ = 'mailto' __select__ = is_instance('EmailAddress') - def cell_call(self, row, col, **kwargs): - entity = self.cw_rset.get_entity(row, col) + def entity_call(self, entity, **kwargs): if entity.reverse_primary_email: self.w(u'') if entity.alias: @@ -130,7 +127,10 @@ __select__ = is_instance('EmailAddress') def cell_call(self, row, col, **kwargs): - self.wview('mailto', self.cw_rset, row=row, col=col, **kwargs) + if self._cw.vreg.config['mangle-emails']: + self.wview('oneline', self.cw_rset, row=row, col=col, **kwargs) + else: + self.wview('mailto', self.cw_rset, row=row, col=col, **kwargs) class EmailAddressTextView(baseviews.TextView): diff -r d313666c171e -r cbb0a0ce3795 web/views/forms.py --- a/web/views/forms.py Wed Jul 27 20:17:45 2011 +0200 +++ b/web/views/forms.py Fri Aug 05 14:23:55 2011 +0200 @@ -384,7 +384,8 @@ else: msg = self._cw._('entity linked') if msg: - self.add_hidden('__message', msg) + msgid = self._cw.set_redirect_message(msg) + self.add_hidden('_cwmsgid', msgid) def session_key(self): """return the key that may be used to store / retreive data about a diff -r d313666c171e -r cbb0a0ce3795 web/views/tabs.py --- a/web/views/tabs.py Wed Jul 27 20:17:45 2011 +0200 +++ b/web/views/tabs.py Fri Aug 05 14:23:55 2011 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb.