# HG changeset patch # User Julien Cristau # Date 1390313476 -3600 # Node ID 6880674c1a2669e3635abd688755116dda72e65e # Parent 549c999d06d27cbcbe8a4e2df0f8e4365886c2e7# Parent 1910d86afcbcb1a82d825688fd2c43dec168cff1 merge 3.17.12 into 3.18 branch diff -r 549c999d06d2 -r 6880674c1a26 .hgtags --- a/.hgtags Wed Sep 11 18:04:05 2013 +0200 +++ b/.hgtags Tue Jan 21 15:11:16 2014 +0100 @@ -320,6 +320,9 @@ 7f67db7c848ec20152daf489d9e11f0fc8402e9b cubicweb-version-3.17.11 7f67db7c848ec20152daf489d9e11f0fc8402e9b cubicweb-debian-version-3.17.11-1 b02e2912cad5d80395e488c55b548495e8320198 cubicweb-debian-version-3.17.11-2 +838d58a30f7efc6a8f83ac27ae8de7d79b84b2bb cubicweb-version-3.17.12 +838d58a30f7efc6a8f83ac27ae8de7d79b84b2bb cubicweb-debian-version-3.17.12-1 +838d58a30f7efc6a8f83ac27ae8de7d79b84b2bb cubicweb-centos-version-3.17.12-1 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-version-3.18.0 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-debian-version-3.18.0-1 db37bf35a1474843ded0a537f9cb4838f4a78cda cubicweb-centos-version-3.18.0-1 diff -r 549c999d06d2 -r 6880674c1a26 __pkginfo__.py --- a/__pkginfo__.py Wed Sep 11 18:04:05 2013 +0200 +++ b/__pkginfo__.py Tue Jan 21 15:11:16 2014 +0100 @@ -1,5 +1,5 @@ # pylint: disable=W0622,C0103 -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. diff -r 549c999d06d2 -r 6880674c1a26 cubicweb.spec diff -r 549c999d06d2 -r 6880674c1a26 dataimport.py --- a/dataimport.py Wed Sep 11 18:04:05 2013 +0200 +++ b/dataimport.py Tue Jan 21 15:11:16 2014 +0100 @@ -1064,7 +1064,7 @@ if subjtype is None: # Try to infer it targets = [t.type for t in - self.schema.rschema(rtype).targets()] + self.schema.rschema(rtype).subjects()] if len(targets) == 1: subjtype = targets[0] else: diff -r 549c999d06d2 -r 6880674c1a26 debian/changelog --- a/debian/changelog Wed Sep 11 18:04:05 2013 +0200 +++ b/debian/changelog Tue Jan 21 15:11:16 2014 +0100 @@ -16,6 +16,12 @@ -- Julien Cristau Fri, 10 Jan 2014 17:14:18 +0100 +cubicweb (3.17.12-1) unstable; urgency=low + + * new upstream release + + -- Aurelien Campeas Tue, 21 Jan 2014 13:10:22 +0100 + cubicweb (3.17.11-2) unstable; urgency=low * Override lintian false-positive about debian/rules.tmpl in the cube diff -r 549c999d06d2 -r 6880674c1a26 debian/control --- a/debian/control Wed Sep 11 18:04:05 2013 +0200 +++ b/debian/control Tue Jan 21 15:11:16 2014 +0100 @@ -43,7 +43,8 @@ Package: cubicweb-server Architecture: all -Conflicts: cubicweb-multisources +Conflicts: + cubicweb-multisources Replaces: cubicweb-multisources Provides: cubicweb-multisources Depends: diff -r 549c999d06d2 -r 6880674c1a26 devtools/fake.py --- a/devtools/fake.py Wed Sep 11 18:04:05 2013 +0200 +++ b/devtools/fake.py Tue Jan 21 15:11:16 2014 +0100 @@ -71,10 +71,6 @@ self._headers_in.setHeader('Cookie', cookie) ## Implement request abstract API - def header_accept_language(self): - """returns an ordered list of preferred languages""" - return ('en',) - def http_method(self): return self._http_method diff -r 549c999d06d2 -r 6880674c1a26 devtools/testlib.py --- a/devtools/testlib.py Wed Sep 11 18:04:05 2013 +0200 +++ b/devtools/testlib.py Tue Jan 21 15:11:16 2014 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -85,6 +85,28 @@ def parse_string(self, data): return json.loads(data) +@contextmanager +def real_error_handling(app): + """By default, CubicWebTC `app` attribute (ie the publisher) is monkey + patched so that unexpected error are raised rather than going through the + `error_handler` method. + + By using this context manager you disable this monkey-patching temporarily. + Hence when publishihng a request no error will be raised, you'll get + req.status_out set to an HTTP error status code and the generated page will + usually hold a traceback as HTML. + + >>> with real_error_handling(app): + >>> page = app.handle_request(req) + """ + # remove the monkey patched error handler + fake_error_handler = app.error_handler + del app.error_handler + # return the app + yield app + # restore + app.error_handler = fake_error_handler + # email handling, to test emails sent by an application ######################## MAILBOX = [] @@ -520,9 +542,9 @@ it2 = set(getattr(x, 'eid', x) for x in it2) super(CubicWebTC, self).assertItemsEqual(it1, it2, *args, **kwargs) - def assertMessageEqual(self, req, params, msg): + def assertMessageEqual(self, req, params, expected_msg): msg = req.session.data[params['_cwmsgid']] - self.assertEqual(msg, msg) + self.assertEqual(expected_msg, msg) # workflow utilities ####################################################### @@ -702,17 +724,14 @@ return self.ctrl_publish(req, ctrlid, rset) def http_publish(self, url, data=None): - """like `url_publish`, except this returns a http response, even in case of errors""" + """like `url_publish`, except this returns a http response, even in case + of errors. You may give form parameters using the `data` argument. + """ req = self.req_from_url(url) if data is not None: req.form.update(data) - # remove the monkey patched error handler - fake_error_handler = self.app.error_handler - del self.app.error_handler - try: + with real_error_handling(self.app): result = self.app_handle_request(req, req.relative_path(False)) - finally: - self.app.error_handler = fake_error_handler return result, req @staticmethod diff -r 549c999d06d2 -r 6880674c1a26 doc/book/en/admin/setup.rst --- a/doc/book/en/admin/setup.rst Wed Sep 11 18:04:05 2013 +0200 +++ b/doc/book/en/admin/setup.rst Tue Jan 21 15:11:16 2014 +0100 @@ -51,9 +51,9 @@ Depending on the distribution you are using, add the appropriate line to your `list of sources` (for example by editing ``/etc/apt/sources.list``). -For Debian 6.0 Squeeze (stable):: +For Debian 7.0 Wheezy (stable):: - deb http://download.logilab.org/production/ squeeze/ + deb http://download.logilab.org/production/ wheezy/ For Debian Sid (unstable):: diff -r 549c999d06d2 -r 6880674c1a26 doc/book/en/devweb/edition/examples.rst --- a/doc/book/en/devweb/edition/examples.rst Wed Sep 11 18:04:05 2013 +0200 +++ b/doc/book/en/devweb/edition/examples.rst Tue Jan 21 15:11:16 2014 +0100 @@ -55,7 +55,7 @@ .. sourcecode:: python - def sender_value(form): + def sender_value(form, field): return '%s <%s>' % (form._cw.user.dc_title(), form._cw.user.get_email()) def recipient_choices(form, field): @@ -63,7 +63,7 @@ for e in form.cw_rset.entities() if e.get_email()] - def recipient_value(form): + def recipient_value(form, field): return [e.eid for e in form.cw_rset.entities() if e.get_email()] diff -r 549c999d06d2 -r 6880674c1a26 entities/adapters.py --- a/entities/adapters.py Wed Sep 11 18:04:05 2013 +0200 +++ b/entities/adapters.py Tue Jan 21 15:11:16 2014 +0100 @@ -102,17 +102,16 @@ _done.add(entity.eid) containers = tuple(entity.e_schema.fulltext_containers()) if containers: - for rschema, target in containers: - if target == 'object': + for rschema, role in containers: + if role == 'object': targets = getattr(entity, rschema.type) else: targets = getattr(entity, 'reverse_%s' % rschema) - for entity in targets: - if entity.eid in _done: + for target in targets: + if target.eid in _done: continue - for container in entity.cw_adapt_to('IFTIndexable').fti_containers(_done): + for container in target.cw_adapt_to('IFTIndexable').fti_containers(_done): yield container - yielded = True else: yield entity diff -r 549c999d06d2 -r 6880674c1a26 entities/test/data/schema.py --- a/entities/test/data/schema.py Wed Sep 11 18:04:05 2013 +0200 +++ b/entities/test/data/schema.py Tue Jan 21 15:11:16 2014 +0100 @@ -24,6 +24,7 @@ class Company(EntityType): name = String() + description = RichString() class Division(Company): __specializes_schema__ = True diff -r 549c999d06d2 -r 6880674c1a26 entities/test/unittest_base.py --- a/entities/test/unittest_base.py Wed Sep 11 18:04:05 2013 +0200 +++ b/entities/test/unittest_base.py Tue Jan 21 15:11:16 2014 +0100 @@ -133,6 +133,27 @@ self.request().create_entity('CWGroup', name=u'logilab', reverse_in_group=e) +class HTMLtransformTC(BaseEntityTC): + + def test_sanitized_html(self): + r = self.request() + c = r.create_entity('Company', name=u'Babar', + description=u""" +Title +===== + +Elephant management best practices. + +.. raw:: html + + +""", description_format=u'text/rest') + self.commit() + c.cw_clear_all_caches() + self.assertIn('alert', c.printable_value('description', format='text/plain')) + self.assertNotIn('alert', c.printable_value('description', format='text/html')) + + class SpecializedEntityClassesTC(CubicWebTC): def select_eclass(self, etype): diff -r 549c999d06d2 -r 6880674c1a26 entity.py --- a/entity.py Wed Sep 11 18:04:05 2013 +0200 +++ b/entity.py Tue Jan 21 15:11:16 2014 +0100 @@ -764,7 +764,7 @@ _engine=ENGINE): trdata = TransformData(data, format, encoding, appobject=self) data = _engine.convert(trdata, target_format).decode() - if format == 'text/html': + if target_format == 'text/html': data = soup2xhtml(data, self._cw.encoding) return data diff -r 549c999d06d2 -r 6880674c1a26 i18n/fr.po --- a/i18n/fr.po Wed Sep 11 18:04:05 2013 +0200 +++ b/i18n/fr.po Tue Jan 21 15:11:16 2014 +0100 @@ -942,7 +942,7 @@ "box, or edit file content online with the widget below." msgstr "" "Vous pouvez soit soumettre un nouveau fichier en utilisant le bouton\n" -"\"parcourir\" ci-dessus, soit suprrimer le fichier déjà présent en\n" +"\"parcourir\" ci-dessus, soit supprimer le fichier déjà présent en\n" "cochant la case \"détacher fichier attaché\", soit éditer le contenu\n" "du fichier en ligne avec le champ ci-dessous." @@ -951,7 +951,7 @@ "content online with the widget below." msgstr "" "Vous pouvez soit soumettre un nouveau fichier en utilisant le bouton\n" -"\"parcourir\" ci-dessu, soit éditer le contenu du fichier en ligne\n" +"\"parcourir\" ci-dessus, soit éditer le contenu du fichier en ligne\n" "avec le champ ci-dessous." msgid "You can't change this relation" diff -r 549c999d06d2 -r 6880674c1a26 test/unittest_entity.py --- a/test/unittest_entity.py Wed Sep 11 18:04:05 2013 +0200 +++ b/test/unittest_entity.py Tue Jan 21 15:11:16 2014 +0100 @@ -551,7 +551,7 @@ e = self.request().create_entity('Card', title=u'rest test', content=u'du :eid:`1:*ReST*`', content_format=u'text/rest') self.assertEqual(e.printable_value('content'), - '

du *ReST*

\n') + '

du *ReST*

') e.cw_attr_cache['content'] = 'du html users' e.cw_attr_cache['content_format'] = 'text/html' self.assertEqual(e.printable_value('content'), @@ -559,7 +559,7 @@ e.cw_attr_cache['content'] = 'du *texte*' e.cw_attr_cache['content_format'] = 'text/plain' self.assertEqual(e.printable_value('content'), - '

\ndu *texte*
\n

') + '

\ndu *texte*

') e.cw_attr_cache['title'] = 'zou' e.cw_attr_cache['content'] = '''\ a title @@ -590,24 +590,21 @@ if tuple(int(i) for i in pygments.__version__.split('.')[:2]) >= (1, 3): self.assertEqual(e.printable_value('data'), '''
lambda x: 1
-
-''') +''') else: self.assertEqual(e.printable_value('data'), '''
lambda x: 1
-
-''') +''') else: self.assertEqual(e.printable_value('data'), '''
 lambda x: 1
-
-''') +''') e = req.create_entity('File', data=Binary('*héhéhé*'), data_format=u'text/rest', data_encoding=u'utf-8', data_name=u'toto.txt') self.assertEqual(e.printable_value('data'), - u'

héhéhé

\n') + u'

héhéhé

') def test_printable_value_bad_html(self): """make sure we don't crash if we try to render invalid XHTML strings""" diff -r 549c999d06d2 -r 6880674c1a26 web/application.py --- a/web/application.py Wed Sep 11 18:04:05 2013 +0200 +++ b/web/application.py Tue Jan 21 15:11:16 2014 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -39,7 +39,7 @@ from cubicweb.web import LOGGER, component from cubicweb.web import ( StatusResponse, DirectResponse, Redirect, NotFound, LogOut, - RemoteCallFailed, InvalidSession, RequestError) + RemoteCallFailed, InvalidSession, RequestError, PublishException) from cubicweb.web.request import CubicWebRequestBase @@ -567,7 +567,7 @@ content = self.vreg['views'].main_template(req, template, view=errview) except Exception: content = self.vreg['views'].main_template(req, 'error-template') - if getattr(ex, 'status', None) is not None: + if isinstance(ex, PublishException) and ex.status is not None: req.status_out = ex.status return content @@ -580,11 +580,11 @@ def ajax_error_handler(self, req, ex): req.set_header('content-type', 'application/json') - status = ex.status - if status is None: - status = httplib.INTERNAL_SERVER_ERROR + status = httplib.INTERNAL_SERVER_ERROR + if isinstance(ex, PublishException) and ex.status is not None: + status = ex.status + req.status_out = status json_dumper = getattr(ex, 'dumps', lambda : unicode(ex)) - req.status_out = status return json_dumper() # special case handling diff -r 549c999d06d2 -r 6880674c1a26 web/http_headers.py --- a/web/http_headers.py Wed Sep 11 18:04:05 2013 +0200 +++ b/web/http_headers.py Tue Jan 21 15:11:16 2014 +0100 @@ -1307,7 +1307,7 @@ return self._toRaw(name) def getHeader(self, name, default=None): - """Ret9urns the parsed representation of the given header. + """Returns the parsed representation of the given header. The exact form of the return value depends on the header in question. If no parser for the header exists, raise ValueError. diff -r 549c999d06d2 -r 6880674c1a26 web/test/unittest_application.py --- a/web/test/unittest_application.py Wed Sep 11 18:04:05 2013 +0200 +++ b/web/test/unittest_application.py Tue Jan 21 15:11:16 2014 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -19,13 +19,15 @@ import base64, Cookie import sys +import httplib from urllib import unquote from logilab.common.testlib import TestCase, unittest_main from logilab.common.decorators import clear_cache, classproperty from cubicweb import AuthenticationError, Unauthorized -from cubicweb.devtools.testlib import CubicWebTC +from cubicweb import view +from cubicweb.devtools.testlib import CubicWebTC, real_error_handling from cubicweb.devtools.fake import FakeRequest from cubicweb.web import LogOut, Redirect, INTERNAL_FIELD_VALUE from cubicweb.web.views.basecontrollers import ViewController @@ -264,6 +266,18 @@ {'login-subject': u'the value "admin" is already used, use another one'}) self.assertEqual(forminfo['values'], req.form) + def test_ajax_view_raise_arbitrary_error(self): + class ErrorAjaxView(view.View): + __regid__ = 'test.ajax.error' + def call(self): + raise Exception('whatever') + with self.temporary_appobjects(ErrorAjaxView): + with real_error_handling(self.app) as app: + req = self.request(vid='test.ajax.error') + req.ajax_request = True + page = app.handle_request(req, '') + self.assertEqual(httplib.INTERNAL_SERVER_ERROR, + req.status_out) def _test_cleaned(self, kwargs, injected, cleaned): req = self.request(**kwargs) @@ -433,5 +447,6 @@ req.form['rql'] = 'rql:Any OV1, X WHERE X custom_workflow OV1?' self.app_handle_request(req) + if __name__ == '__main__': unittest_main() diff -r 549c999d06d2 -r 6880674c1a26 web/uicfg.py --- a/web/uicfg.py Wed Sep 11 18:04:05 2013 +0200 +++ b/web/uicfg.py Tue Jan 21 15:11:16 2014 +0100 @@ -16,7 +16,7 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """ -This module is now deprecated, see web.views.uicfg. +This module has been moved to web.views.uicfg. """ __docformat__ = "restructuredtext en" diff -r 549c999d06d2 -r 6880674c1a26 web/views/workflow.py --- a/web/views/workflow.py Wed Sep 11 18:04:05 2013 +0200 +++ b/web/views/workflow.py Tue Jan 21 15:11:16 2014 +0100 @@ -445,6 +445,13 @@ binary = True def cell_call(self, row=0, col=0): - tmpfile = self._cw.session.data[self._cw.form['tmpfile']] + key = self._cw.form['tmpfile'] + if key not in self._cw.session.data: + # the temp file is gone and there's nothing + # we can do about it + # we should probably write it to some well + # behaved place and serve it + return + tmpfile = self._cw.session.data.pop(key) self.w(open(tmpfile, 'rb').read()) os.unlink(tmpfile)