# HG changeset patch # User Sylvain Thénault # Date 1334070199 -7200 # Node ID fdb796435d7b6afb4e5b68fdfb97468cdb1edb19 # Parent 622fcca4fe003803233394b5f7973bf8d97744e3# Parent 1a88d201675c210dd9acee7497f35cfd7e1ba74d backport stable diff -r 622fcca4fe00 -r fdb796435d7b __pkginfo__.py --- a/__pkginfo__.py Thu Mar 29 14:20:41 2012 +0200 +++ b/__pkginfo__.py Tue Apr 10 17:03:19 2012 +0200 @@ -54,6 +54,7 @@ # server dependencies 'logilab-database': '>= 1.8.2', 'pysqlite': '>= 2.5.5', # XXX install pysqlite2 + 'passlib': '', } __recommends__ = { diff -r 622fcca4fe00 -r fdb796435d7b bin/clone_deps.py --- a/bin/clone_deps.py Thu Mar 29 14:20:41 2012 +0200 +++ b/bin/clone_deps.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,24 +1,24 @@ #!/usr/bin/python -import os import sys -from subprocess import call, Popen, PIPE -try: - from mercurial.dispatch import dispatch as hg_call -except ImportError: + +from subprocess import call as sbp_call, Popen, PIPE +from urllib import urlopen +from os import path as osp, pardir, chdir + + +def find_mercurial(): + print "trying to find mercurial from the command line ..." print '-' * 20 - print "mercurial module is not reachable from this Python interpreter" - print "trying from command line ..." - tryhg = os.system('hg --version') + tryhg = sbp_call(['hg', '--version']) if tryhg: - print 'mercurial seems to unavailable, please install it' + print 'mercurial seems to be unavailable, please install it' raise - print 'found it, ok' print '-' * 20 def hg_call(args): - call(['hg'] + args) -from urllib import urlopen -from os import path as osp, pardir -from os.path import normpath, join, dirname + return sbp_call(['hg'] + args) + + return hg_call + BASE_URL = 'http://www.logilab.org/hg/' @@ -27,7 +27,7 @@ 'logilab/devtools', 'logilab/mtconverter', 'cubes/blog', 'cubes/calendar', 'cubes/card', 'cubes/comment', 'cubes/datafeed', 'cubes/email', 'cubes/file', 'cubes/folder', - 'cubes/forgotpwd', 'cubes/keyword', 'cubes/link', + 'cubes/forgotpwd', 'cubes/keyword', 'cubes/link', 'cubes/localperms', 'cubes/mailinglist', 'cubes/nosylist', 'cubes/person', 'cubes/preview', 'cubes/registration', 'cubes/rememberme', 'cubes/tag', 'cubes/vcsfile', 'cubes/zone'] @@ -65,9 +65,10 @@ else: sys.stderr.write('usage %s [base_url]\n' % sys.argv[0]) sys.exit(1) + hg_call = find_mercurial() print len(to_clone), 'repositories will be cloned' - base_dir = normpath(join(dirname(__file__), pardir, pardir)) - os.chdir(base_dir) + base_dir = osp.normpath(osp.join(osp.dirname(__file__), pardir, pardir)) + chdir(base_dir) not_updated = [] for repo in to_clone: url = base_url + repo @@ -78,7 +79,7 @@ directory, repo = repo.split('/') if not osp.isdir(directory): os.mkdir(directory) - open(join(directory, '__init__.py'), 'w').close() + open(osp.join(directory, '__init__.py'), 'w').close() target_path = osp.join(directory, repo) if osp.exists(target_path): print target_path, 'seems already cloned. Skipping it.' diff -r 622fcca4fe00 -r fdb796435d7b debian/control --- a/debian/control Thu Mar 29 14:20:41 2012 +0200 +++ b/debian/control Tue Apr 10 17:03:19 2012 +0200 @@ -35,7 +35,7 @@ Conflicts: cubicweb-multisources Replaces: cubicweb-multisources Provides: cubicweb-multisources -Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.8.2), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2 +Depends: ${misc:Depends}, ${python:Depends}, cubicweb-common (= ${source:Version}), cubicweb-ctl (= ${source:Version}), python-logilab-database (>= 1.8.2), cubicweb-postgresql-support | cubicweb-mysql-support | python-pysqlite2, python-passlib Recommends: pyro (<< 4.0.0), cubicweb-documentation (= ${source:Version}) Suggests: python-zmq Description: server part of the CubicWeb framework diff -r 622fcca4fe00 -r fdb796435d7b devtools/data/xvfb-run.sh --- a/devtools/data/xvfb-run.sh Thu Mar 29 14:20:41 2012 +0200 +++ b/devtools/data/xvfb-run.sh Tue Apr 10 17:03:19 2012 +0200 @@ -1,13 +1,11 @@ #!/bin/sh -# $Id: xvfb-run 2027 2004-11-16 14:54:16Z branden $ - # This script starts an instance of Xvfb, the "fake" X server, runs a command # with that server available, and kills the X server when done. The return # value of the command becomes the return value of this script. # # If anyone is using this to build a Debian package, make sure the package -# Build-Depends on xvfb, xbase-clients, and xfonts-base. +# Build-Depends on xvfb and xauth. set -e @@ -15,7 +13,6 @@ SERVERNUM=99 AUTHFILE= ERRORFILE=/dev/null -STARTWAIT=3 XVFBARGS="-screen 0 640x480x8" LISTENTCP="-nolisten tcp" XAUTHPROTO=. @@ -62,8 +59,6 @@ -s ARGS --server-args=ARGS arguments (other than server number and "-nolisten tcp") to pass to the Xvfb server (default: "$XVFBARGS") --w DELAY --wait=DELAY delay in seconds to wait for Xvfb to start - before running COMMAND (default: $STARTWAIT) EOF } @@ -93,7 +88,7 @@ fi fi if [ -n "$XVFBPID" ]; then - kill $XVFBPID + kill "$XVFBPID" fi } @@ -120,7 +115,7 @@ -l|--listen-tcp) LISTENTCP="" ;; -p|--xauth-protocol) XAUTHPROTO="$2"; shift ;; -s|--server-args) XVFBARGS="$2"; shift ;; - -w|--wait) STARTWAIT="$2"; shift ;; + -w|--wait) shift ;; --) shift; break ;; *) error "internal error; getopt permitted \"$1\" unexpectedly" exit 6 @@ -163,10 +158,13 @@ XAUTHORITY=$AUTHFILE xauth source - << EOF >>"$ERRORFILE" 2>&1 add :$SERVERNUM $XAUTHPROTO $MCOOKIE EOF - XAUTHORITY=$AUTHFILE Xvfb ":$SERVERNUM" $XVFBARGS $LISTENTCP >>"$ERRORFILE" 2>&1 & + # handle SIGUSR1 so Xvfb knows to send a signal when it's ready to accept + # connections + trap : USR1 + (trap '' USR1; XAUTHORITY=$AUTHFILE exec Xvfb ":$SERVERNUM" $XVFBARGS $LISTENTCP >>"$ERRORFILE" 2>&1) & XVFBPID=$! - sleep "$STARTWAIT" + wait || : if kill -0 $XVFBPID 2>/dev/null; then break elif [ -n "$AUTONUM" ]; then @@ -176,6 +174,7 @@ continue fi error "Xvfb failed to start" >&2 + XVFBPID= exit 1 done diff -r 622fcca4fe00 -r fdb796435d7b doc/book/en/admin/config.rst --- a/doc/book/en/admin/config.rst Thu Mar 29 14:20:41 2012 +0200 +++ b/doc/book/en/admin/config.rst Tue Apr 10 17:03:19 2012 +0200 @@ -70,53 +70,53 @@ install the `postgresql-client` package on the |cubicweb| host, and others on the database host. -.. Note:: +Database cluster +++++++++++++++++ - If you already have an existing cluster and PostgreSQL server running, you do - not need to execute the initilization step of your PostgreSQL database unless - you want a specific cluster for |cubicweb| databases or if your existing - cluster doesn't use the UTF8 encoding (see note below). +If you already have an existing cluster and PostgreSQL server running, you do +not need to execute the initilization step of your PostgreSQL database unless +you want a specific cluster for |cubicweb| databases or if your existing +cluster doesn't use the UTF8 encoding (see note below). -* First, initialize a PostgreSQL cluster with the command ``initdb``:: +To initialize a PostgreSQL cluster, use the command ``initdb``:: $ initdb -E UTF8 -D /path/to/pgsql - Notice the encoding specification. This is necessary since |cubicweb| usually - want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll - get error like:: +Notice the encoding specification. This is necessary since |cubicweb| usually +want UTF8 encoded database. If you use a cluster with the wrong encoding, you'll +get error like:: - new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII) - HINT: Use the same encoding as in the template database, or use template0 as template. - + new encoding (UTF8) is incompatible with the encoding of the template database (SQL_ASCII) + HINT: Use the same encoding as in the template database, or use template0 as template. - Once initialized, start the database server PostgreSQL with the command:: +Once initialized, start the database server PostgreSQL with the command:: - $ postgres -D /path/to/psql + $ postgres -D /path/to/psql - If you cannot execute this command due to permission issues, please make sure - that your username has write access on the database. :: +If you cannot execute this command due to permission issues, please make sure +that your username has write access on the database. :: - $ chown username /path/to/pgsql + $ chown username /path/to/pgsql -* The database authentication can be either set to `ident sameuser` or `md5`. If - set to `md5`, make sure to use an existing user of your database. If set to - `ident sameuser`, make sure that your client's operating system user name has a - matching user in the database. If not, please do as follow to create a user:: +Database authentication ++++++++++++++++++++++++ - $ su - $ su - postgres - $ createuser -s -P username +The database authentication is configured in `pg_hba.conf`. It can be either set +to `ident sameuser` or `md5`. If set to `md5`, make sure to use an existing +user of your database. If set to `ident sameuser`, make sure that your client's +operating system user name has a matching user in the database. If not, please +do as follow to create a user:: - The option `-P` (for password prompt), will encrypt the password with the - method set in the configuration file :file:`pg_hba.conf`. If you do not use this - option `-P`, then the default value will be null and you will need to set it - with:: + $ su + $ su - postgres + $ createuser -s -P username - $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql" +The option `-P` (for password prompt), will encrypt the password with the +method set in the configuration file :file:`pg_hba.conf`. If you do not use this +option `-P`, then the default value will be null and you will need to set it +with:: -.. Note:: - The authentication method can be configured in file:`pg_hba.conf`. - + $ su postgres -c "echo ALTER USER username WITH PASSWORD 'userpasswd' | psql" The above login/password will be requested when you will create an instance with `cubicweb-ctl create` to initialize the database of your instance. @@ -149,7 +149,6 @@ cat /usr/share/postgresql/8.X/contrib/tsearch2.sql | psql -U username template1 - .. _MySqlConfiguration: MySql @@ -196,12 +195,12 @@ The ALTER DATABASE command above requires some permissions that your user may not have. In that case you will have to ask your local DBA to -run the query for you. +run the query for you. You can check that the setting is correct by running the following query which must return '1':: - SELECT is_read_committed_snapshot_on + SELECT is_read_committed_snapshot_on FROM sys.databases WHERE name=''; @@ -210,6 +209,7 @@ SQLite ~~~~~~ + SQLite has the great advantage of requiring almost no configuration. Simply use 'sqlite' as db-driver, and set path to the dabase as db-name. Don't specify anything for db-user and db-password, they will be ignore anyway. @@ -226,6 +226,7 @@ Pyro name server ~~~~~~~~~~~~~~~~ + If you want to use Pyro to access your instance remotely, or to have multi-source or distributed configuration, it is required to have a Pyro name server running on your network. By default it is detected by a broadcast request, but you can diff -r 622fcca4fe00 -r fdb796435d7b doc/book/en/admin/setup.rst --- a/doc/book/en/admin/setup.rst Thu Mar 29 14:20:41 2012 +0200 +++ b/doc/book/en/admin/setup.rst Tue Apr 10 17:03:19 2012 +0200 @@ -63,9 +63,9 @@ deb http://download.logilab.org/production/ lucid/ - Note that for Ubuntu Maverick and newer, you shall use the `lucid` - repository and install the ``libgecode19`` package from `lucid - universe `_. +Note that for Ubuntu Maverick and newer, you shall use the `lucid` +repository and install the ``libgecode19`` package from `lucid +universe `_. The repositories are signed with the `Logilab's gnupg key`_. You can download and register the key to avoid warnings:: diff -r 622fcca4fe00 -r fdb796435d7b etwist/server.py --- a/etwist/server.py Thu Mar 29 14:20:41 2012 +0200 +++ b/etwist/server.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. diff -r 622fcca4fe00 -r fdb796435d7b md5crypt.py --- a/md5crypt.py Thu Mar 29 14:20:41 2012 +0200 +++ b/md5crypt.py Tue Apr 10 17:03:19 2012 +0200 @@ -51,18 +51,16 @@ v = v >> 6 return ret -def crypt(pw, salt, magic=None): +def crypt(pw, salt): if isinstance(pw, unicode): pw = pw.encode('utf-8') - if magic is None: - magic = MAGIC # Take care of the magic string if present - if salt[:len(magic)] == magic: - salt = salt[len(magic):] + if salt.startswith(MAGIC): + salt = salt[len(MAGIC):] # salt can have up to 8 characters: salt = salt.split('$', 1)[0] salt = salt[:8] - ctx = pw + magic + salt + ctx = pw + MAGIC + salt final = md5(pw + salt + pw).digest() for pl in xrange(len(pw), 0, -16): if pl > 16: @@ -114,4 +112,4 @@ |(int(ord(final[10])) << 8) |(int(ord(final[5]))), 4) passwd = passwd + to64((int(ord(final[11]))), 2) - return salt + '$' + passwd + return passwd diff -r 622fcca4fe00 -r fdb796435d7b misc/migration/3.14.3_Any.py --- a/misc/migration/3.14.3_Any.py Thu Mar 29 14:20:41 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -# keep the same behavior on existing instance but use the new one on new instance. -config['https-deny-anonymous'] = True diff -r 622fcca4fe00 -r fdb796435d7b misc/migration/3.14.7_Any.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/migration/3.14.7_Any.py Tue Apr 10 17:03:19 2012 +0200 @@ -0,0 +1,4 @@ +# migrate default format for TriInfo `comment_format` attribute +sync_schema_props_perms('TrInfo') + +commit() diff -r 622fcca4fe00 -r fdb796435d7b schemas/workflow.py --- a/schemas/workflow.py Thu Mar 29 14:20:41 2012 +0200 +++ b/schemas/workflow.py Tue Apr 10 17:03:19 2012 +0200 @@ -185,7 +185,7 @@ # make by_transition optional because we want to allow managers to set # entity into an arbitrary state without having to respect wf transition by_transition = SubjectRelation('BaseTransition', cardinality='?*') - comment = RichString(fulltextindexed=True) + comment = RichString(fulltextindexed=True, default_format='text/plain') tr_count = Int(description='autocomputed attribute used to ensure transition coherency') # get actor and date time using owned_by and creation_date diff -r 622fcca4fe00 -r fdb796435d7b server/querier.py --- a/server/querier.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/querier.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -417,7 +417,7 @@ if rqlexpr.check(session, eid): break else: - raise Unauthorized() + raise Unauthorized('No read acces on %r with eid %i.' % (var, eid)) restricted_vars.update(localcheck) localchecks.setdefault(tuple(localcheck.iteritems()), []).append(solution) # raise Unautorized exception if the user can't access to any solution @@ -723,7 +723,7 @@ rqlst = rqlst.copy() self._annotate(rqlst) if args: - # different SQL generated when some argument is None or not (IS + # different SQL generated when some argument is None or not (IS # NULL). This should be considered when computing sql cache key cachekey += tuple(sorted([k for k,v in args.iteritems() if v is None])) diff -r 622fcca4fe00 -r fdb796435d7b server/rqlannotation.py --- a/server/rqlannotation.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/rqlannotation.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -28,12 +28,13 @@ from rql.utils import common_parent def _annotate_select(annotator, rqlst): + has_text_query = False for subquery in rqlst.with_: - annotator._annotate_union(subquery.query) + if annotator._annotate_union(subquery.query): + has_text_query = True #if server.DEBUG: # print '-------- sql annotate', repr(rqlst) getrschema = annotator.schema.rschema - has_text_query = False need_distinct = rqlst.distinct for rel in rqlst.iget_nodes(Relation): if getrschema(rel.r_type).symmetric and not isinstance(rel.parent, Exists): @@ -154,6 +155,11 @@ sstinfo['scope'] = common_parent(sstinfo['scope'], stinfo['scope']).scope except CantSelectPrincipal: stinfo['invariant'] = False + # see unittest_rqlannotation. test_has_text_security_cache_bug + # XXX probably more to do, but yet that work without more... + for col_alias in rqlst.aliases.itervalues(): + if col_alias.stinfo.get('ftirels'): + has_text_query = True rqlst.need_distinct = need_distinct return has_text_query @@ -272,8 +278,7 @@ def _annotate_union(self, union): has_text_query = False for select in union.children: - htq = _annotate_select(self, select) - if htq: + if _annotate_select(self, select): has_text_query = True return has_text_query diff -r 622fcca4fe00 -r fdb796435d7b server/sources/native.py --- a/server/sources/native.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/sources/native.py Tue Apr 10 17:03:19 2012 +0200 @@ -1626,7 +1626,7 @@ # if pwd is None but a password is provided, something is wrong raise AuthenticationError('bad password') # passwords are stored using the Bytes type, so we get a StringIO - args['pwd'] = Binary(crypt_password(password, pwd.getvalue()[:2])) + args['pwd'] = Binary(crypt_password(password, pwd.getvalue())) # get eid from login and (crypted) password rset = self.source.syntax_tree_search(session, self._auth_rqlst, args) try: diff -r 622fcca4fe00 -r fdb796435d7b server/test/unittest_postgres.py --- a/server/test/unittest_postgres.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/test/unittest_postgres.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,20 +1,20 @@ # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # -# This file is part of Logilab-common. +# This file is part of CubicWeb. # -# Logilab-common is free software: you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by the -# Free Software Foundation, either version 2.1 of the License, or (at your -# option) any later version. +# CubicWeb is free software: you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation, either version 2.1 of the License, or (at your option) +# any later version. # -# Logilab-common is distributed in the hope that it will be useful, but WITHOUT +# CubicWeb is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License along -# with Logilab-common. If not, see . +# with CubicWeb. If not, see . from __future__ import with_statement diff -r 622fcca4fe00 -r fdb796435d7b server/test/unittest_querier.py --- a/server/test/unittest_querier.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/test/unittest_querier.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -18,6 +18,8 @@ # with CubicWeb. If not, see . """unit tests for modules cubicweb.server.querier and cubicweb.server.ssplanner """ +from __future__ import with_statement + from datetime import date, datetime, timedelta, tzinfo from logilab.common.testlib import TestCase, unittest_main @@ -28,7 +30,7 @@ from cubicweb.server.utils import crypt_password from cubicweb.server.sources.native import make_schema from cubicweb.devtools import get_test_db_handler, TestServerConfiguration - +from cubicweb.devtools.testlib import CubicWebTC from cubicweb.devtools.repotest import tuplify, BaseQuerierTC from unittest_session import Variable @@ -70,14 +72,15 @@ ('C0 text,C1 integer', {'A': 'table0.C0', 'B': 'table0.C1'})) -def setUpModule(*args): +def setUpClass(cls, *args): global repo, cnx config = TestServerConfiguration(apphome=UtilsTC.datadir) handler = get_test_db_handler(config) handler.build_db_cache() repo, cnx = handler.get_repo_and_cnx() + cls.repo = repo -def tearDownModule(*args): +def tearDownClass(cls, *args): global repo, cnx cnx.close() repo.shutdown() @@ -85,9 +88,8 @@ class UtilsTC(BaseQuerierTC): - def setUp(self): - self.__class__.repo = repo - super(UtilsTC, self).setUp() + setUpClass = classmethod(setUpClass) + tearDownClass = classmethod(tearDownClass) def get_max_eid(self): # no need for cleanup here @@ -242,9 +244,8 @@ class QuerierTC(BaseQuerierTC): - def setUp(self): - self.__class__.repo = repo - super(QuerierTC, self).setUp() + setUpClass = classmethod(setUpClass) + tearDownClass = classmethod(tearDownClass) def test_encoding_pb(self): self.assertRaises(RQLSyntaxError, self.execute, @@ -1259,7 +1260,7 @@ cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) passwd = str(cursor.fetchone()[0]) - self.assertEqual(passwd, crypt_password('toto', passwd[:2])) + self.assertEqual(passwd, crypt_password('toto', passwd)) rset = self.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", {'pwd': Binary(passwd)}) self.assertEqual(len(rset.rows), 1) @@ -1274,7 +1275,7 @@ cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) passwd = str(cursor.fetchone()[0]) - self.assertEqual(passwd, crypt_password('tutu', passwd[:2])) + self.assertEqual(passwd, crypt_password('tutu', passwd)) rset = self.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", {'pwd': Binary(passwd)}) self.assertEqual(len(rset.rows), 1) @@ -1501,5 +1502,20 @@ self.assertFalse(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': None})) self.assertTrue(self.execute('Any X WHERE X is CWEType, X name %(name)s', {'name': 'CWEType'})) + +class NonRegressionTC(CubicWebTC): + + def test_has_text_security_cache_bug(self): + req = self.request() + self.create_user(req, 'user', ('users',)) + aff1 = req.create_entity('Societe', nom=u'aff1') + aff2 = req.create_entity('Societe', nom=u'aff2') + self.commit() + with self.login('user', password='user'): + res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff1'}) + self.assertEqual(res.rows, [[aff1.eid]]) + res = self.execute('Any X WHERE X has_text %(text)s', {'text': 'aff2'}) + self.assertEqual(res.rows, [[aff2.eid]]) + if __name__ == '__main__': unittest_main() diff -r 622fcca4fe00 -r fdb796435d7b server/test/unittest_rqlannotation.py --- a/server/test/unittest_rqlannotation.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/test/unittest_rqlannotation.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,5 +1,5 @@ # -*- coding: iso-8859-1 -*- -# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -350,6 +350,12 @@ self.assertEqual(rqlst.defined_vars['X']._q_invariant, False) self.assertEqual(rqlst.defined_vars['Y']._q_invariant, True) + + def test_has_text_security_cache_bug(self): + rqlst = self._prepare('Any X WHERE X has_text "toto" WITH X BEING ' + '(Any C WHERE C is Societe, C nom CS)') + self.assertTrue(rqlst.parent.has_text_query) + if __name__ == '__main__': from logilab.common.testlib import unittest_main unittest_main() diff -r 622fcca4fe00 -r fdb796435d7b server/utils.py --- a/server/utils.py Thu Mar 29 14:20:41 2012 +0200 +++ b/server/utils.py Tue Apr 10 17:03:19 2012 +0200 @@ -28,27 +28,49 @@ from cubicweb.server import SOURCE_TYPES -try: - from crypt import crypt -except ImportError: - # crypt is not available (eg windows) - from cubicweb.md5crypt import crypt +from passlib.utils import handlers as uh, to_hash_str +from passlib.context import CryptContext + +from cubicweb.md5crypt import crypt as md5crypt -def getsalt(chars=string.letters + string.digits): - """generate a random 2-character 'salt'""" - return choice(chars) + choice(chars) +class CustomMD5Crypt(uh.HasSalt, uh.GenericHandler): + name = 'cubicweb-md5crypt' + setting_kwds = ("salt",) + min_salt_size = 0 + max_salt_size = 8 + salt_chars = uh.H64_CHARS + @classmethod + def from_string(cls, hash): + if hash is None: + raise ValueError("no hash specified") + if hash.count('$') != 1: + raise ValueError("invalid cubicweb-md5 hash") + salt = hash.split('$', 1)[0] + chk = hash.split('$', 1)[1] + return cls(salt=salt, checksum=chk, strict=True) + + def to_string(self): + return to_hash_str(u'%s$%s' % (self.salt, self.checksum or u'')) + + def calc_checksum(self, secret): + return md5crypt(secret, self.salt.encode('ascii')) + +myctx = CryptContext(['sha512_crypt', CustomMD5Crypt, 'des_crypt']) def crypt_password(passwd, salt=None): """return the encrypted password using the given salt or a generated one """ - if passwd is None: - return None if salt is None: - salt = getsalt() - return crypt(passwd, salt) - + return myctx.encrypt(passwd) + # empty hash, accept any password for backwards compat + if salt == '': + return salt + if myctx.verify(passwd, salt): + return salt + # wrong password + return '' def cartesian_product(seqin): """returns a generator which returns the cartesian product of `seqin` diff -r 622fcca4fe00 -r fdb796435d7b test/unittest_rqlrewrite.py --- a/test/unittest_rqlrewrite.py Thu Mar 29 14:20:41 2012 +0200 +++ b/test/unittest_rqlrewrite.py Tue Apr 10 17:03:19 2012 +0200 @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. diff -r 622fcca4fe00 -r fdb796435d7b test/unittest_schema.py --- a/test/unittest_schema.py Thu Mar 29 14:20:41 2012 +0200 +++ b/test/unittest_schema.py Tue Apr 10 17:03:19 2012 +0200 @@ -348,6 +348,10 @@ self.assertEqual(cstr.repo_check(self.session, 1, self.session.user.eid), None) # no validation error, constraint checked +class WorkflowShemaTC(CubicWebTC): + def test_trinfo_default_format(self): + tr = self.session.user.cw_adapt_to('IWorkflowable').fire_transition('deactivate') + self.assertEqual(tr.comment_format, 'text/plain') if __name__ == '__main__': unittest_main() diff -r 622fcca4fe00 -r fdb796435d7b web/data/cubicweb.ajax.js --- a/web/data/cubicweb.ajax.js Thu Mar 29 14:20:41 2012 +0200 +++ b/web/data/cubicweb.ajax.js Tue Apr 10 17:03:19 2012 +0200 @@ -372,7 +372,7 @@ /** * .. function:: loadRemote(url, form, reqtype='GET', sync=false) * - * Asynchronously (unless `async` argument is set to false) load an url or path + * Asynchronously (unless `sync` argument is set to true) load an url or path * and return a deferred whose callbacks args are decoded according to the * Content-Type response header. `form` should be additional form params * dictionary, `reqtype` the HTTP request type (get 'GET' or 'POST'). diff -r 622fcca4fe00 -r fdb796435d7b web/data/cubicweb.css --- a/web/data/cubicweb.css Thu Mar 29 14:20:41 2012 +0200 +++ b/web/data/cubicweb.css Tue Apr 10 17:03:19 2012 +0200 @@ -39,6 +39,12 @@ padding: %(h3Padding)s; } + +h4 { + font-size: %(h4FontSize)s; +} + + div.tabbedprimary + h1, h1.plain { border-bottom: none; diff -r 622fcca4fe00 -r fdb796435d7b web/data/cubicweb.edition.js --- a/web/data/cubicweb.edition.js Thu Mar 29 14:20:41 2012 +0200 +++ b/web/data/cubicweb.edition.js Tue Apr 10 17:03:19 2012 +0200 @@ -435,11 +435,15 @@ } } if (globalerrors.length) { - if (globalerrors.length == 1) { - var innernode = SPAN(null, globalerrors[0]); - } else { - var innernode = UL(null, $.map(globalerrors, partial(LI, null))); - } + if (globalerrors.length == 1) { + var innernode = SPAN(null, globalerrors[0]); + } else { + var linodes =[]; + for(var i=0; i