--- 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
--- 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.
--- 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:
--- 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 <julien.cristau@logilab.fr> Fri, 10 Jan 2014 17:14:18 +0100
+cubicweb (3.17.12-1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Aurelien Campeas <aurelien.campeas@logilab.fr> 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
--- 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:
--- 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
--- 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
--- 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)::
--- 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()]
--- 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
--- 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
--- 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
+
+ <script>alert("coucou")</script>
+""", 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):
--- 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
--- 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"
--- 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'),
- '<p>du <a class="reference" href="http://testing.fr/cubicweb/cwsource/system">*ReST*</a></p>\n')
+ '<p>du <a class="reference" href="http://testing.fr/cubicweb/cwsource/system">*ReST*</a></p>')
e.cw_attr_cache['content'] = 'du <em>html</em> <ref rql="CWUser X">users</ref>'
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'),
- '<p>\ndu *texte*<br/>\n</p>')
+ '<p>\ndu *texte*<br/></p>')
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'),
'''<div class="highlight"><pre><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="mi">1</span>
-</pre></div>
-''')
+</pre></div>''')
else:
self.assertEqual(e.printable_value('data'),
'''<div class="highlight"><pre><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="mf">1</span>
-</pre></div>
-''')
+</pre></div>''')
else:
self.assertEqual(e.printable_value('data'),
'''<pre class="python">
<span style="color: #C00000;">lambda</span> <span style="color: #000000;">x</span><span style="color: #0000C0;">:</span> <span style="color: #0080C0;">1</span>
-</pre>
-''')
+</pre>''')
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'<p><em>héhéhé</em></p>\n')
+ u'<p><em>héhéhé</em></p>')
def test_printable_value_bad_html(self):
"""make sure we don't crash if we try to render invalid XHTML strings"""
--- 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
--- 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.
--- 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()
--- 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 <http://www.gnu.org/licenses/>.
"""
-This module is now deprecated, see web.views.uicfg.
+This module has been moved to web.views.uicfg.
"""
__docformat__ = "restructuredtext en"
--- 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)