merge stable
authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
Mon, 07 Sep 2009 20:23:40 +0200
branchstable
changeset 3108 aa43c0c22b98
parent 3105 b788903e77d5 (diff)
parent 3107 0829808e93c1 (current diff)
child 3109 e7e1bb06b716
merge
--- a/server/migractions.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/server/migractions.py	Mon Sep 07 20:23:40 2009 +0200
@@ -166,14 +166,20 @@
                                            % (self.config.appid, backupfile)):
             return
         # unpack backup
-        bkup = tarfile.open(backupfile, 'r|gz')
-        for name in bkup.getnames():
-            if name[0] in '/.':
-                raise Exception('Security check failed, path starts with "/" or "."')
-        bkup.close() # XXX seek error if not close+open !?!
-        bkup = tarfile.open(backupfile, 'r|gz')
         tmpdir = tempfile.mkdtemp()
-        bkup.extractall(path=tmpdir)
+        try:
+            bkup = tarfile.open(backupfile, 'r|gz')
+        except tarfile.ReadError:
+            # assume restoring old backup
+            shutil.copy(backupfile, osp.join(tmpdir, 'system'))  
+        else:
+            for name in bkup.getnames():
+                if name[0] in '/.':
+                    raise Exception('Security check failed, path starts with "/" or "."')
+            bkup.close() # XXX seek error if not close+open !?!
+            bkup = tarfile.open(backupfile, 'r|gz')
+            bkup.extractall(path=tmpdir)
+            bkup.close()
 
         self.config.open_connections_pools = False
         repo = self.repo_connect()
@@ -186,7 +192,6 @@
                 print '-> error trying to restore [%s]' % exc
                 if not self.confirm('Continue anyway?', default='n'):
                     raise SystemExit(1)
-        bkup.close()
         shutil.rmtree(tmpdir)
         # call hooks
         repo.open_connections_pools()
--- a/server/session.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/server/session.py	Mon Sep 07 20:23:40 2009 +0200
@@ -129,8 +129,11 @@
                 if row[0] == targeteid:
                     break
             else:
-                raise Exception('cache inconsistency for %s %s %s %s' %
-                                (eid, rtype, role, targeteid))
+                # this may occurs if the cache has been filed by a hook
+                # after the database update
+                self.debug('cache inconsistency for %s %s %s %s', eid, rtype,
+                           role, targeteid)
+                return
             del rset.rows[idx]
             if isinstance(rset.description, list): # else description not set
                 del rset.description[idx]
--- a/sobjects/notification.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/sobjects/notification.py	Mon Sep 07 20:23:40 2009 +0200
@@ -21,7 +21,7 @@
 from cubicweb.server.hookhelper import SendMailOp
 from cubicweb.server.hooksmanager import Hook
 
-parse_message_id = deprecated('parse_message_id is now defined in cubicweb.common.mail')
+parse_message_id = deprecated('parse_message_id is now defined in cubicweb.common.mail')(parse_message_id)
 
 
 class RecipientsFinder(Component):
--- a/utils.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/utils.py	Mon Sep 07 20:23:40 2009 +0200
@@ -7,6 +7,8 @@
 """
 __docformat__ = "restructuredtext en"
 
+from logilab.mtconverter import xml_escape
+
 import locale
 from md5 import md5
 from datetime import datetime, timedelta, date
@@ -262,17 +264,18 @@
         # 2/ css files
         for cssfile, media in self.cssfiles:
             w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
-              (media, cssfile))
+              (media, xml_escape(cssfile)))
         # 3/ ie css if necessary
         if self.ie_cssfiles:
             w(u'<!--[if lt IE 8]>\n')
             for cssfile, media in self.ie_cssfiles:
                 w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
-                  (media, cssfile))
+                  (media, xml_escape(cssfile)))
             w(u'<![endif]--> \n')
         # 4/ js files
         for jsfile in self.jsfiles:
-            w(u'<script type="text/javascript" src="%s"></script>\n' % jsfile)
+            w(u'<script type="text/javascript" src="%s"></script>\n' %
+              xml_escape(jsfile))
         # 5/ post inlined scripts (i.e. scripts depending on other JS files)
         if self.post_inlined_scripts:
             w(u'<script type="text/javascript">\n')
@@ -305,7 +308,8 @@
         self.htmltag = u'<html xmlns="http://www.w3.org/1999/xhtml" ' \
                        'xmlns:cubicweb="http://www.logilab.org/2008/cubicweb" ' \
                        'xml:lang="%s" lang="%s">' % (req.lang, req.lang)
-
+        # keep main_stream's reference on req for easier text/html demoting
+        req.main_stream = self
 
     def write(self, data):
         """StringIO interface: this method will be assigned to self.w
--- a/web/data/cubicweb.ajax.js	Mon Sep 07 13:53:12 2009 +0200
+++ b/web/data/cubicweb.ajax.js	Mon Sep 07 20:23:40 2009 +0200
@@ -387,24 +387,30 @@
     return stripped;
 }
 
-/* convenience function that returns a DOM node based on req's result. */
+/* convenience function that returns a DOM node based on req's result.
+ * XXX clarify the need to clone
+ * */
 function getDomFromResponse(response) {
     if (typeof(response) == 'string') {
-	return html2dom(response);
+	var doc = html2dom(response);
+    } else {
+        var doc = response.documentElement;
     }
-    var doc = response.documentElement;
     var children = doc.childNodes;
     if (!children.length) {
 	// no child (error cases) => return the whole document
-	return doc.cloneNode(true);
+	return jQuery(doc).clone().context;
     }
     children = stripEmptyTextNodes(children);
     if (children.length == 1) {
 	// only one child => return it
-	return children[0].cloneNode(true);
+	return jQuery(children[0]).clone().context;
     }
     // several children => wrap them in a single node and return the wrap
-    return DIV(null, map(methodcaller('cloneNode', true), children));
+    return DIV(null, map(function(node) {
+                           return jQuery(node).clone().context;
+                         },
+                         children));
 }
 
 function postJSON(url, data, callback) {
--- a/web/request.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/web/request.py	Mon Sep 07 20:23:40 2009 +0200
@@ -26,7 +26,7 @@
 from cubicweb.common.mail import header
 from cubicweb.common.uilib import remove_html_tags
 from cubicweb.utils import SizeConstrainedList, HTMLHead
-from cubicweb.view import STRICT_DOCTYPE
+from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE_NOEXT
 from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit,
                           RequestError, StatusResponse)
 
@@ -663,6 +663,16 @@
         """
         raise NotImplementedError()
 
+    def demote_to_html(self):
+        """helper method to dynamically set request content type to text/html
+
+        The global doctype and xmldec must also be changed otherwise the browser
+        will display '<[' at the beginning of the page
+        """
+        self.set_content_type('text/html')
+        self.main_stream.doctype = TRANSITIONAL_DOCTYPE_NOEXT
+        self.main_stream.xmldecl = u''
+
     # page data management ####################################################
 
     def get_page_data(self, key, default=None):
--- a/web/views/editcontroller.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/web/views/editcontroller.py	Mon Sep 07 20:23:40 2009 +0200
@@ -191,7 +191,22 @@
             return
         attrtype = rschema.objects(entity.e_schema)[0].type
         # on checkbox or selection, the field may not be in params
-        if attrtype == 'Boolean':
+        # NOTE: raising ValidationError here is not a good solution because
+        #       we can't gather all errors at once. Hopefully, the new 3.6.x
+        #       form handling will fix that
+        if attrtype == 'Int':
+            try:
+                value = int(value)
+            except ValueError:
+                raise ValidationError(entity.eid,
+                                      {attr: self.req._("invalid integer value")})
+        elif attrtype == 'Float':
+            try:
+                value = float(value)
+            except ValueError:
+                raise ValidationError(entity.eid,
+                                      {attr: self.req._("invalid float value")})
+        elif attrtype == 'Boolean':
             value = bool(value)
         elif attrtype == 'Decimal':
             value = Decimal(value)
--- a/web/views/editforms.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/web/views/editforms.py	Mon Sep 07 20:23:40 2009 +0200
@@ -20,7 +20,8 @@
 from cubicweb.utils import make_uid
 from cubicweb.view import EntityView
 from cubicweb.common import tags
-from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, eid_param, uicfg
+from cubicweb.web import INTERNAL_FIELD_VALUE, RequestError, stdmsgs, eid_param
+from cubicweb.web import uicfg
 from cubicweb.web.form import FormViewMixIn, FieldNotFound
 from cubicweb.web.formfields import guess_field
 from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton
@@ -327,13 +328,13 @@
         """creation view for an entity"""
         etype = kwargs.pop('etype', self.req.form.get('etype'))
         try:
-            entity = self.vreg['etypes'].etype_class(etype)(self.req)
-        except:
-            self.w(self.req._('no such entity type %s') % etype)
-        else:
-            self.initialize_varmaker()
-            entity.eid = self.varmaker.next()
-            self.render_form(entity)
+            etype = self.vreg.case_insensitive_etypes[etype.lower()]
+        except KeyError:
+            raise RequestError(self.req._('no such entity type %s') % etype)
+        entity = self.vreg['etypes'].etype_class(etype)(self.req)
+        self.initialize_varmaker()
+        entity.eid = self.varmaker.next()
+        self.render_form(entity)
 
     def form_title(self, entity):
         """the form view title"""
--- a/web/views/igeocodable.py	Mon Sep 07 13:53:12 2009 +0200
+++ b/web/views/igeocodable.py	Mon Sep 07 20:23:40 2009 +0200
@@ -74,6 +74,7 @@
     need_navigation = False
 
     def call(self, gmap_key, width=400, height=400, uselabel=True, urlparams=None):
+        self.req.demote_to_html()
         # remove entities that don't define latitude and longitude
         self.rset = self.rset.filtered_rset(lambda e: e.latitude and e.longitude)
         self.req.add_js('http://maps.google.com/maps?sensor=false&file=api&amp;v=2&amp;key=%s' % gmap_key,