backport stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Thu, 08 Sep 2011 18:09:36 +0200
changeset 7776 aa547cf3bf0d
parent 7769 8af09eeee130 (diff)
parent 7775 72699a8e739d (current diff)
child 7784 7f5c455ec7d1
backport stable
web/webconfig.py
--- a/entity.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/entity.py	Thu Sep 08 18:09:36 2011 +0200
@@ -96,11 +96,12 @@
                     If None is specified, the first non-meta attribute will
                     be used
 
-    :type skip_copy_for: list
-    :cvar skip_copy_for: a list of relations that should be skipped when copying
-                         this kind of entity. Note that some relations such
-                         as composite relations or relations that have '?1' as object
-                         cardinality are always skipped.
+    :type cw_skip_copy_for: list
+    :cvar cw_skip_copy_for: a list of couples (rtype, role) for each relation
+                            that should be skipped when copying
+                            this kind of entity. Note that some relations such
+                            as composite relations or relations that have '?1' as object
+                            cardinality are always skipped.
     """
     __registry__ = 'etypes'
     __select__ = yes()
@@ -108,7 +109,8 @@
     # class attributes that must be set in class definition
     rest_attr = None
     fetch_attrs = None
-    skip_copy_for = ('in_state',) # XXX turn into a set
+    skip_copy_for = () # bw compat (< 3.14), use cw_skip_copy_for instead
+    cw_skip_copy_for = [('in_state', 'subject')]
     # class attributes set automatically at registration time
     e_schema = None
 
@@ -542,13 +544,22 @@
         """
         assert self.has_eid()
         execute = self._cw.execute
+        skip_copy_for = {'subject': set(), 'object': set()}
+        for rtype in self.skip_copy_for:
+            skip_copy_for['subject'].add(rtype)
+            warn('[3.14] skip_copy_for on entity classes (%s) is deprecated, '
+                 'use cw_skip_for instead with list of couples (rtype, role)' % self.__regid__,
+                 DeprecationWarning)
+        for rtype, role in self.cw_skip_copy_for:
+            assert role in ('subject', 'object'), role
+            skip_copy_for[role].add(rtype)
         for rschema in self.e_schema.subject_relations():
             if rschema.final or rschema.meta:
                 continue
             # skip already defined relations
             if getattr(self, rschema.type):
                 continue
-            if rschema.type in self.skip_copy_for:
+            if rschema.type in skip_copy_for['subject']:
                 continue
             # skip composite relation
             rdef = self.e_schema.rdef(rschema)
@@ -568,6 +579,8 @@
             # skip already defined relations
             if self.related(rschema.type, 'object'):
                 continue
+            if rschema.type in skip_copy_for['object']:
+                continue
             rdef = self.e_schema.rdef(rschema, 'object')
             # skip composite relation
             if rdef.composite:
--- a/server/session.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/server/session.py	Thu Sep 08 18:09:36 2011 +0200
@@ -28,6 +28,7 @@
 from warnings import warn
 
 from logilab.common.deprecation import deprecated
+from logilab.common.textutils import unormalize
 from rql import CoercionError
 from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj
 from yams import BASE_TYPES
@@ -232,7 +233,7 @@
 
     def __init__(self, user, repo, cnxprops=None, _id=None):
         super(Session, self).__init__(repo.vreg)
-        self.id = _id or make_uid(user.login.encode('UTF8'))
+        self.id = _id or make_uid(unormalize(user.login).encode('UTF8'))
         cnxprops = cnxprops or ConnectionProperties('inmemory')
         self.user = user
         self.repo = repo
--- a/test/unittest_utils.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/test/unittest_utils.py	Thu Sep 08 18:09:36 2011 +0200
@@ -159,9 +159,17 @@
         self.assertEqual(self.encode(TestCase), 'null')
 
 class HTMLHeadTC(CubicWebTC):
+
+    def htmlhead(self, datadir_url):
+        req = self.request()
+        base_url = u'http://test.fr/data/'
+        req.datadir_url = base_url
+        head = HTMLHead(req)
+        return head
+
     def test_concat_urls(self):
         base_url = u'http://test.fr/data/'
-        head = HTMLHead(base_url)
+        head = self.htmlhead(base_url)
         urls = [base_url + u'bob1.js',
                 base_url + u'bob2.js',
                 base_url + u'bob3.js']
@@ -171,7 +179,7 @@
 
     def test_group_urls(self):
         base_url = u'http://test.fr/data/'
-        head = HTMLHead(base_url)
+        head = self.htmlhead(base_url)
         urls_spec = [(base_url + u'bob0.js', None),
                      (base_url + u'bob1.js', None),
                      (u'http://ext.com/bob2.js', None),
@@ -196,7 +204,7 @@
 
     def test_getvalue_with_concat(self):
         base_url = u'http://test.fr/data/'
-        head = HTMLHead(base_url)
+        head = self.htmlhead(base_url)
         head.add_js(base_url + u'bob0.js')
         head.add_js(base_url + u'bob1.js')
         head.add_js(u'http://ext.com/bob2.js')
@@ -224,20 +232,22 @@
         self.assertEqual(result, expected)
 
     def test_getvalue_without_concat(self):
-        base_url = u'http://test.fr/data/'
-        head = HTMLHead()
-        head.add_js(base_url + u'bob0.js')
-        head.add_js(base_url + u'bob1.js')
-        head.add_js(u'http://ext.com/bob2.js')
-        head.add_js(u'http://ext.com/bob3.js')
-        head.add_css(base_url + u'bob4.css')
-        head.add_css(base_url + u'bob5.css')
-        head.add_css(base_url + u'bob6.css', 'print')
-        head.add_css(base_url + u'bob7.css', 'print')
-        head.add_ie_css(base_url + u'bob8.css')
-        head.add_ie_css(base_url + u'bob9.css', 'print', u'[if lt IE 7]')
-        result = head.getvalue()
-        expected = u"""<head>
+        self.config.global_set_option('concat-resources', False)
+        try:
+            base_url = u'http://test.fr/data/'
+            head = self.htmlhead(base_url)
+            head.add_js(base_url + u'bob0.js')
+            head.add_js(base_url + u'bob1.js')
+            head.add_js(u'http://ext.com/bob2.js')
+            head.add_js(u'http://ext.com/bob3.js')
+            head.add_css(base_url + u'bob4.css')
+            head.add_css(base_url + u'bob5.css')
+            head.add_css(base_url + u'bob6.css', 'print')
+            head.add_css(base_url + u'bob7.css', 'print')
+            head.add_ie_css(base_url + u'bob8.css')
+            head.add_ie_css(base_url + u'bob9.css', 'print', u'[if lt IE 7]')
+            result = head.getvalue()
+            expected = u"""<head>
 <link rel="stylesheet" type="text/css" media="all" href="http://test.fr/data/bob4.css"/>
 <link rel="stylesheet" type="text/css" media="all" href="http://test.fr/data/bob5.css"/>
 <link rel="stylesheet" type="text/css" media="print" href="http://test.fr/data/bob6.css"/>
@@ -253,7 +263,9 @@
 <script type="text/javascript" src="http://ext.com/bob3.js"></script>
 </head>
 """
-        self.assertEqual(result, expected)
+            self.assertEqual(result, expected)
+        finally:
+            self.config.global_set_option('concat-resources', True)
 
 class DocTest(DocTest):
     from cubicweb import utils as module
--- a/utils.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/utils.py	Thu Sep 08 18:09:36 2011 +0200
@@ -227,7 +227,7 @@
     xhtml_safe_script_opening = u'<script type="text/javascript"><!--//--><![CDATA[//><!--\n'
     xhtml_safe_script_closing = u'\n//--><!]]></script>'
 
-    def __init__(self, datadir_url=None):
+    def __init__(self, req):
         super(HTMLHead, self).__init__()
         self.jsvars = []
         self.jsfiles = []
@@ -235,8 +235,8 @@
         self.ie_cssfiles = []
         self.post_inlined_scripts = []
         self.pagedata_unload = False
-        self.datadir_url = datadir_url
-
+        self._cw = req
+        self.datadir_url = req.datadir_url
 
     def add_raw(self, rawheader):
         self.write(rawheader)
@@ -348,20 +348,26 @@
                 w(vardecl + u'\n')
             w(self.xhtml_safe_script_closing)
         # 2/ css files
-        for cssfile, media in (self.group_urls(self.cssfiles) if self.datadir_url else self.cssfiles):
+        ie_cssfiles = ((x, (y, z)) for x, y, z in self.ie_cssfiles)
+        if self.datadir_url and self._cw.vreg.config['concat-resources']:
+            cssfiles = self.group_urls(self.cssfiles)
+            ie_cssfiles = self.group_urls(ie_cssfiles)
+            jsfiles = (x for x, _ in self.group_urls((x, None) for x in self.jsfiles))
+        else:
+            cssfiles = self.cssfiles
+            jsfiles = self.jsfiles
+        for cssfile, media in cssfiles:
             w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
               (media, xml_escape(cssfile)))
         # 3/ ie css if necessary
-        if self.ie_cssfiles:
-            ie_cssfiles = ((x, (y, z)) for x, y, z in self.ie_cssfiles)
-            for cssfile, (media, iespec) in (self.group_urls(ie_cssfiles) if self.datadir_url else ie_cssfiles):
+        if self.ie_cssfiles: # use self.ie_cssfiles because `ie_cssfiles` is a genexp
+            for cssfile, (media, iespec) in ie_cssfiles:
                 w(u'<!--%s>\n' % iespec)
                 w(u'<link rel="stylesheet" type="text/css" media="%s" href="%s"/>\n' %
                   (media, xml_escape(cssfile)))
             w(u'<![endif]--> \n')
         # 4/ js files
-        jsfiles = ((x, None) for x in self.jsfiles)
-        for jsfile, media in self.group_urls(jsfiles) if self.datadir_url else jsfiles:
+        for jsfile in jsfiles:
             if skiphead:
                 # Don't insert <script> tags directly as they would be
                 # interpreted directly by some browsers (e.g. IE).
--- a/web/request.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/web/request.py	Thu Sep 08 18:09:36 2011 +0200
@@ -92,7 +92,7 @@
             self.uiprops = vreg.config.uiprops
             self.datadir_url = vreg.config.datadir_url
         # raw html headers that can be added from any view
-        self.html_headers = HTMLHead(self.datadir_url)
+        self.html_headers = HTMLHead(self)
         # form parameters
         self.setup_params(form)
         # dictionnary that may be used to store request data that has to be
@@ -262,7 +262,7 @@
         """used by AutomaticWebTest to clear html headers between tests on
         the same resultset
         """
-        self.html_headers = HTMLHead(self.datadir_url)
+        self.html_headers = HTMLHead(self)
         return self
 
     # web state helpers #######################################################
--- a/web/test/unittest_views_basecontrollers.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/web/test/unittest_views_basecontrollers.py	Thu Sep 08 18:09:36 2011 +0200
@@ -365,6 +365,43 @@
         self.assertEqual(path, 'view')
         self.assertIn('_cwmsgid', params)
 
+    def test_simple_copy(self):
+        req = self.request()
+        blog = req.create_entity('Blog', title=u'my-blog')
+        blogentry = req.create_entity('BlogEntry', title=u'entry1',
+                                      content=u'content1', entry_of=blog)
+        req = self.request()
+        req.form = {'__maineid' : 'X', 'eid': 'X',
+                    '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
+                    '_cw_entity_fields:X': 'title-subject,content-subject',
+                    'title-subject:X': u'entry1-copy',
+                    'content-subject:X': u'content1',
+                    }
+        self.expect_redirect_publish(req, 'edit')
+        blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
+        self.assertEqual(blogentry2.entry_of[0].eid, blog.eid)
+
+    def test_skip_copy_for(self):
+        req = self.request()
+        blog = req.create_entity('Blog', title=u'my-blog')
+        blogentry = req.create_entity('BlogEntry', title=u'entry1',
+                                      content=u'content1', entry_of=blog)
+        blogentry.__class__.cw_skip_copy_for = [('entry_of', 'subject')]
+        try:
+            req = self.request()
+            req.form = {'__maineid' : 'X', 'eid': 'X',
+                        '__cloned_eid:X': blogentry.eid, '__type:X': 'BlogEntry',
+                        '_cw_entity_fields:X': 'title-subject,content-subject',
+                        'title-subject:X': u'entry1-copy',
+                        'content-subject:X': u'content1',
+                        }
+            self.expect_redirect_publish(req, 'edit')
+            blogentry2 = req.find_one_entity('BlogEntry', title=u'entry1-copy')
+            # entry_of should not be copied
+            self.assertEqual(len(blogentry2.entry_of), 0)
+        finally:
+            blogentry.__class__.cw_skip_copy_for = []
+
     def test_nonregr_eetype_etype_editing(self):
         """non-regression test checking that a manager user can edit a CWEType entity
         """
--- a/web/webconfig.py	Thu Sep 08 18:04:50 2011 +0200
+++ b/web/webconfig.py	Thu Sep 08 18:09:36 2011 +0200
@@ -203,6 +203,12 @@
           'help': 'use cubicweb.old.css instead of 3.9 cubicweb.css',
           'group': 'web', 'level': 2,
           }),
+        ('concat-resources',
+         {'type' : 'yn',
+          'default': True,
+          'help': 'use modconcat-like URLS to concat and serve JS / CSS files',
+          'group': 'web', 'level': 2,
+          }),
         ))
 
     def fckeditor_installed(self):