merge with 3.20.10
authorRémi Cardona <remi.cardona@logilab.fr>
Fri, 09 Oct 2015 17:52:14 +0200
changeset 10646 45671fb330f5
parent 10645 57c60a96de70 (current diff)
parent 10642 7312eb6c8b59 (diff)
child 10647 012ea658883b
merge with 3.20.10
.hgtags
__pkginfo__.py
cubicweb.spec
debian/changelog
devtools/test/unittest_testlib.py
devtools/testlib.py
hooks/syncschema.py
predicates.py
server/migractions.py
server/sources/native.py
server/test/data-migractions/migratedapp/schema.py
server/test/data/schema.py
server/test/unittest_migractions.py
web/test/unittest_views_editforms.py
web/views/autoform.py
--- a/.hgtags	Tue Sep 29 12:09:04 2015 +0200
+++ b/.hgtags	Fri Oct 09 17:52:14 2015 +0200
@@ -469,6 +469,9 @@
 5932de3d50bf023544c8f54b47898e4db35eac7c 3.19.12
 5932de3d50bf023544c8f54b47898e4db35eac7c debian/3.19.12-1
 5932de3d50bf023544c8f54b47898e4db35eac7c centos/3.19.12-1
+f933a38d7ab5fc6f2ad593fe1cf9985ce9d7e873 3.19.13
+f933a38d7ab5fc6f2ad593fe1cf9985ce9d7e873 debian/3.19.13-1
+f933a38d7ab5fc6f2ad593fe1cf9985ce9d7e873 centos/3.19.13-1
 7e6b7739afe6128589ad51b0318decb767cbae36 3.20.0
 7e6b7739afe6128589ad51b0318decb767cbae36 debian/3.20.0-1
 7e6b7739afe6128589ad51b0318decb767cbae36 centos/3.20.0-1
@@ -499,6 +502,9 @@
 d477e64475821c21632878062bf68d142252ffc2 3.20.9
 d477e64475821c21632878062bf68d142252ffc2 debian/3.20.9-1
 d477e64475821c21632878062bf68d142252ffc2 centos/3.20.9-1
+8f82e95239625d153a9f1de6e79820d96d9efe8a 3.20.10
+8f82e95239625d153a9f1de6e79820d96d9efe8a debian/3.20.10-1
+8f82e95239625d153a9f1de6e79820d96d9efe8a centos/3.20.10-1
 887c6eef807781560adcd4ecd2dea9011f5a6681 3.21.0
 887c6eef807781560adcd4ecd2dea9011f5a6681 debian/3.21.0-1
 887c6eef807781560adcd4ecd2dea9011f5a6681 centos/3.21.0-1
--- a/debian/changelog	Tue Sep 29 12:09:04 2015 +0200
+++ b/debian/changelog	Fri Oct 09 17:52:14 2015 +0200
@@ -10,6 +10,12 @@
 
  -- Julien Cristau <julien.cristau@logilab.fr>  Fri, 10 Jul 2015 17:04:11 +0200
 
+cubicweb (3.20.10-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Rémi Cardona <remi.cardona@logilab.fr>  Thu, 08 Oct 2015 18:47:24 +0200
+
 cubicweb (3.20.9-1) unstable; urgency=low
 
   * New upstream release.
@@ -76,6 +82,12 @@
 
  -- Julien Cristau <julien.cristau@logilab.fr>  Tue, 06 Jan 2015 18:11:03 +0100
 
+cubicweb (3.19.13-1) unstable; urgency=medium
+
+  * New upstream release.
+
+ -- Rémi Cardona <remi.cardona@logilab.fr>  Tue, 06 Oct 2015 18:31:33 +0200
+
 cubicweb (3.19.12-1) unstable; urgency=low
 
   * New upstream release
--- a/devtools/test/unittest_testlib.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/devtools/test/unittest_testlib.py	Fri Oct 09 17:52:14 2015 +0200
@@ -196,6 +196,18 @@
             self.assertTrue(rdef.permissions['add'])
         self.assertTrue(rdef.permissions['read'], ())
 
+    def test_temporary_permissions_rdef_with_exception(self):
+        rdef = self.schema['CWUser'].rdef('in_group')
+        try:
+            with self.temporary_permissions((rdef, {'read': ()})):
+                self.assertEqual(rdef.permissions['read'], ())
+                self.assertTrue(rdef.permissions['add'])
+                raise ValueError('goto')
+        except ValueError:
+            self.assertTrue(rdef.permissions['read'], ())
+        else:
+            self.fail('exception was caught unexpectedly')
+
     def test_temporary_appobjects_registered(self):
 
         class AnAppobject(object):
--- a/devtools/testlib.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/devtools/testlib.py	Fri Oct 09 17:52:14 2015 +0200
@@ -526,16 +526,18 @@
                 origperms = erschema.permissions[action]
                 erschema.set_action_permissions(action, actionperms)
                 torestore.append([erschema, action, origperms])
-        yield
-        for erschema, action, permissions in torestore:
-            if action is None:
-                erschema.permissions = permissions
-            else:
-                erschema.set_action_permissions(action, permissions)
+        try:
+            yield
+        finally:
+            for erschema, action, permissions in torestore:
+                if action is None:
+                    erschema.permissions = permissions
+                else:
+                    erschema.set_action_permissions(action, permissions)
 
     def assertModificationDateGreater(self, entity, olddate):
         entity.cw_attr_cache.pop('modification_date', None)
-        self.assertTrue(entity.modification_date > olddate)
+        self.assertGreater(entity.modification_date, olddate)
 
     def assertMessageEqual(self, req, params, expected_msg):
         msg = req.session.data[params['_cwmsgid']]
--- a/hooks/security.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/hooks/security.py	Fri Oct 09 17:52:14 2015 +0200
@@ -143,10 +143,13 @@
     """
     assert rschema.inlined
     try:
-        entity = cnx.transaction_data['ecache'][eid]
+        entity = cnx.entity_cache(eid)
     except KeyError:
         return False
-    return rschema.type in entity.cw_edited.skip_security
+    edited = getattr(entity, 'cw_edited', None)
+    if edited is None:
+        return False
+    return rschema.type in edited.skip_security
 
 
 class BeforeAddRelationSecurityHook(SecurityHook):
--- a/hooks/syncschema.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/hooks/syncschema.py	Fri Oct 09 17:52:14 2015 +0200
@@ -701,6 +701,16 @@
         syssource = cnx.repo.system_source
         cstrtype = self.oldcstr.type()
         if cstrtype == 'SizeConstraint':
+            # if the size constraint is being replaced with a new max size, we'll
+            # call update_rdef_column in CWConstraintAddOp, skip it here
+            for cstr in cnx.transaction_data.get('newsizecstr', ()):
+                rdefentity = cstr.reverse_constrained_by[0]
+                cstrrdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid)
+                if cstrrdef == rdef:
+                    return
+
+            # we found that the size constraint for this rdef is really gone,
+            # not just replaced by another
             syssource.update_rdef_column(cnx, rdef)
             self.size_cstr_changed = True
         elif cstrtype == 'UniqueConstraint':
@@ -794,6 +804,13 @@
     entity = cstrname = None # for pylint
     cols = () # for pylint
 
+    def insert_index(self):
+        # We need to run before CWConstraintDelOp: if a size constraint is
+        # removed and the column is part of a unique_together constraint, we
+        # remove the unique_together index before changing the column's type.
+        # SQL Server does not support unique indices on unlimited text columns.
+        return 0
+
     def precommit_event(self):
         cnx = self.cnx
         prefix = SQL_PREFIX
@@ -1224,6 +1241,11 @@
     events = ('after_add_entity', 'after_update_entity')
 
     def __call__(self):
+        if self.entity.cstrtype[0].name == 'SizeConstraint':
+            txdata = self._cw.transaction_data
+            if 'newsizecstr' not in txdata:
+                txdata['newsizecstr'] = set()
+            txdata['newsizecstr'].add(self.entity)
         CWConstraintAddOp(self._cw, entity=self.entity)
 
 
--- a/predicates.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/predicates.py	Fri Oct 09 17:52:14 2015 +0200
@@ -1369,7 +1369,7 @@
         score = self.score_class(req.vreg['etypes'].etype_class(etype), req)
         if score:
             eschema = req.vreg.schema.eschema(etype)
-            if eschema.has_local_role('add') or eschema.has_perm(req, 'add'):
+            if eschema.may_have_permission('add', req):
                 return score
         return 0
 
--- a/server/migractions.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/migractions.py	Fri Oct 09 17:52:14 2015 +0200
@@ -452,7 +452,8 @@
         rtype = str(rtype)
         if rtype in self._synchronized:
             return
-        self._synchronized.add(rtype)
+        if syncrdefs and syncperms and syncprops:
+            self._synchronized.add(rtype)
         rschema = self.fs_schema.rschema(rtype)
         reporschema = self.repo.schema.rschema(rtype)
         if syncprops:
@@ -483,7 +484,8 @@
         etype = str(etype)
         if etype in self._synchronized:
             return
-        self._synchronized.add(etype)
+        if syncrdefs and syncperms and syncprops:
+            self._synchronized.add(etype)
         repoeschema = self.repo.schema.eschema(etype)
         try:
             eschema = self.fs_schema.eschema(etype)
@@ -581,9 +583,10 @@
         reporschema = self.repo.schema.rschema(rschema)
         if (subjtype, rschema, objtype) in self._synchronized:
             return
-        self._synchronized.add((subjtype, rschema, objtype))
-        if rschema.symmetric:
-            self._synchronized.add((objtype, rschema, subjtype))
+        if syncperms and syncprops:
+            self._synchronized.add((subjtype, rschema, objtype))
+            if rschema.symmetric:
+                self._synchronized.add((objtype, rschema, subjtype))
         rdef = rschema.rdef(subjtype, objtype)
         if rdef.infered:
             return # don't try to synchronize infered relation defs
@@ -1079,8 +1082,9 @@
                                 default='n'):
                 return
         self.cmd_add_relation_type(newname, commit=True)
-        self.rqlexec('SET X %s Y WHERE X %s Y' % (newname, oldname),
-                     ask_confirm=self.verbosity>=2)
+        if not self.repo.schema[oldname].rule:
+            self.rqlexec('SET X %s Y WHERE X %s Y' % (newname, oldname),
+                         ask_confirm=self.verbosity>=2)
         self.cmd_drop_relation_type(oldname, commit=commit)
 
     def cmd_add_relation_definition(self, subjtype, rtype, objtype, commit=True):
--- a/server/sources/native.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/sources/native.py	Fri Oct 09 17:52:14 2015 +0200
@@ -932,12 +932,12 @@
             self._handle_is_relation_sql(cnx, 'INSERT INTO cw_source_relation(eid_from,eid_to) VALUES (%s,%s)',
                                          (entity.eid, source.eid))
         # now we can update the full text index
-        if self.do_fti and self.need_fti_indexation(entity.cw_etype):
+        if self.need_fti_indexation(entity.cw_etype):
             self.index_entity(cnx, entity=entity)
 
     def update_info(self, cnx, entity, need_fti_update):
         """mark entity as being modified, fulltext reindex if needed"""
-        if self.do_fti and need_fti_update:
+        if need_fti_update:
             # reindex the entity only if this query is updating at least
             # one indexable attribute
             self.index_entity(cnx, entity=entity)
@@ -1333,7 +1333,8 @@
         """create an operation to [re]index textual content of the given entity
         on commit
         """
-        FTIndexEntityOp.get_instance(cnx).add_data(entity.eid)
+        if self.do_fti:
+            FTIndexEntityOp.get_instance(cnx).add_data(entity.eid)
 
     def fti_unindex_entities(self, cnx, entities):
         """remove text content for entities from the full text index
@@ -1723,7 +1724,7 @@
             self.logger.info('restoring sequence %s', seq)
             self.read_sequence(archive, seq)
         for numrange in numranges:
-            self.logger.info('restoring numrange %s', seq)
+            self.logger.info('restoring numrange %s', numrange)
             self.read_numrange(archive, numrange)
         for table in tables:
             self.logger.info('restoring table %s', table)
--- a/server/test/data-migractions/migratedapp/schema.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/test/data-migractions/migratedapp/schema.py	Fri Oct 09 17:52:14 2015 +0200
@@ -108,6 +108,12 @@
 
 
 class Personne(EntityType):
+    __permissions__ = {
+        'read':   ('managers', 'users'), # 'guests' was removed
+        'add':    ('managers', 'users'),
+        'update': ('managers', 'owners'),
+        'delete': ('managers', 'owners')
+    }
     __unique_together__ = [('nom', 'prenom', 'datenaiss')]
     nom    = String(fulltextindexed=True, required=True, maxsize=64)
     prenom = String(fulltextindexed=True, maxsize=64)
--- a/server/test/data/schema.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/test/data/schema.py	Fri Oct 09 17:52:14 2015 +0200
@@ -128,6 +128,12 @@
 
 
 class Personne(EntityType):
+    __permissions__ = {
+        'read':   ('managers', 'users', 'guests'), # 'guests' will be removed
+        'add':    ('managers', 'users'),
+        'update': ('managers', 'owners'),
+        'delete': ('managers', 'owners')
+    }
     __unique_together__ = [('nom', 'prenom', 'inline2')]
     nom    = String(fulltextindexed=True, required=True, maxsize=64)
     prenom = String(fulltextindexed=True, maxsize=64)
--- a/server/test/datacomputed/migratedapp/schema.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/test/datacomputed/migratedapp/schema.py	Fri Oct 09 17:52:14 2015 +0200
@@ -55,3 +55,7 @@
 
 class whatever(ComputedRelation):
     rule = 'S employees E, O associates E'
+
+
+class renamed(ComputedRelation):
+    rule = 'S employees E, O concerns E'
--- a/server/test/datacomputed/schema.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/test/datacomputed/schema.py	Fri Oct 09 17:52:14 2015 +0200
@@ -36,11 +36,13 @@
 class Company(EntityType):
     score100 = Float(formula='Any AVG(NN) WHERE X employees E, N concerns E, N note100 NN')
 
+
 class Note(EntityType):
     note = Int()
     note20 = Int(formula='Any N*20 WHERE X note N')
     note100 = Int(formula='Any N*20 WHERE X note N')
 
+
 class concerns(RelationDefinition):
     subject = 'Note'
     object = 'Employee'
@@ -52,3 +54,7 @@
 
 class whatever(ComputedRelation):
     rule = 'S employees E, O concerns E'
+
+
+class to_be_renamed(ComputedRelation):
+    rule = 'S employees E, O concerns E'
--- a/server/test/unittest_migractions.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/server/test/unittest_migractions.py	Fri Oct 09 17:52:14 2015 +0200
@@ -452,6 +452,9 @@
             delete_concerne_rqlexpr = self._rrqlexpr_rset(cnx, 'delete', 'concerne')
             add_concerne_rqlexpr = self._rrqlexpr_rset(cnx, 'add', 'concerne')
 
+            # make sure properties (e.g. etype descriptions) are synced by the
+            # second call to sync_schema
+            mh.cmd_sync_schema_props_perms(syncprops=False, commit=False)
             mh.cmd_sync_schema_props_perms(commit=False)
 
             self.assertEqual(cnx.execute('Any D WHERE X name "Personne", X description D')[0][0],
@@ -732,8 +735,7 @@
         self.assertNotIn('works_for', self.schema)
         with self.mh() as (cnx, mh):
             with self.assertRaises(ExecutionError) as exc:
-                mh.cmd_add_relation_definition('Employee', 'works_for',
-                                                    'Company')
+                mh.cmd_add_relation_definition('Employee', 'works_for', 'Company')
         self.assertEqual(str(exc.exception),
                          'Cannot add a relation definition for a computed '
                          'relation (works_for)')
@@ -792,6 +794,12 @@
                          'Cannot synchronize a relation definition for a computed '
                          'relation (whatever)')
 
+    def test_computed_relation_rename_relation_type(self):
+        with self.mh() as (cnx, mh):
+            mh.cmd_rename_relation_type('to_be_renamed', 'renamed')
+        self.assertIn('renamed', self.schema)
+        self.assertNotIn('to_be_renamed', self.schema)
+
     # computed attributes migration ############################################
 
     def setup_add_score(self):
@@ -799,9 +807,9 @@
             assert not cnx.execute('Company X')
             c = cnx.create_entity('Company')
             e1 = cnx.create_entity('Employee', reverse_employees=c)
-            n1 = cnx.create_entity('Note', note=2, concerns=e1)
+            cnx.create_entity('Note', note=2, concerns=e1)
             e2 = cnx.create_entity('Employee', reverse_employees=c)
-            n2 = cnx.create_entity('Note', note=4, concerns=e2)
+            cnx.create_entity('Note', note=4, concerns=e2)
             cnx.commit()
 
     def assert_score_initialized(self, mh):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/unittest_sources_native.py	Fri Oct 09 17:52:14 2015 +0200
@@ -0,0 +1,38 @@
+# copyright 2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# 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.
+#
+# 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 CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
+
+from logilab.common import tempattr
+
+from cubicweb.devtools.testlib import CubicWebTC
+from cubicweb.server.sources.native import FTIndexEntityOp
+
+class NativeSourceTC(CubicWebTC):
+
+    def test_index_entity_consider_do_fti(self):
+        source = self.repo.system_source
+        with tempattr(source, 'do_fti', False):
+            with self.admin_access.repo_cnx() as cnx:
+                # when do_fti is set to false, call to index_entity (as may be done from hooks)
+                # should have no effect
+                source.index_entity(cnx, cnx.user)
+                self.assertNotIn(cnx.user.eid, FTIndexEntityOp.get_instance(cnx).get_data())
+
+
+if __name__ == '__main__':
+    from logilab.common.testlib import unittest_main
+    unittest_main()
--- a/web/test/unittest_views_actions.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/web/test/unittest_views_actions.py	Fri Oct 09 17:52:14 2015 +0200
@@ -21,6 +21,7 @@
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.web.views import actions, uicfg
 
+
 class ActionsTC(CubicWebTC):
     def test_view_action(self):
         with self.admin_access.web_request(vid='rss', rql='CWUser X') as req:
@@ -33,12 +34,31 @@
         """ensure has_editable_relation predicate used by ModifyAction
         return positive score if there is only some inlined forms
         """
+        # The schema only allows the anonymous user to modify his/her own
+        # EmailAddress if it is set, not to create one. Since the 'anon' CWUser
+        # entity is created without any associated EmailAddress entities, there
+        # are no attributes nor relations that can be edited: the "modify"
+        # action should not appear.
+        with self.new_access('anon').web_request() as req:
+            predicate = actions.has_editable_relation()
+            self.assertEqual(predicate(None, req, rset=req.user.as_rset()),
+                             0)
+        # being allowed to 'add' the relation is not enough
         use_email = self.schema['use_email'].rdefs['CWUser', 'EmailAddress']
         with self.temporary_permissions((use_email, {'add': ('guests',)})):
             with self.new_access('anon').web_request() as req:
                 predicate = actions.has_editable_relation()
                 self.assertEqual(predicate(None, req, rset=req.user.as_rset()),
+                                 0)
+        # if we also allow creating the target etype, then the "modify" action
+        # should appear
+        with self.temporary_permissions((use_email, {'add': ('guests',)}),
+                                        EmailAddress={'add': ('guests',)}):
+            with self.new_access('anon').web_request() as req:
+                predicate = actions.has_editable_relation()
+                self.assertEqual(predicate(None, req, rset=req.user.as_rset()),
                                  1)
 
+
 if __name__ == '__main__':
     unittest_main()
--- a/web/test/unittest_views_editforms.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/web/test/unittest_views_editforms.py	Fri Oct 09 17:52:14 2015 +0200
@@ -20,6 +20,8 @@
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.web.views import uicfg
 from cubicweb.web.formwidgets import AutoCompletionWidget
+from cubicweb.schema import RRQLExpression
+
 
 AFFK = uicfg.autoform_field_kwargs
 AFS = uicfg.autoform_section
@@ -173,6 +175,35 @@
                              [rschema.type
                               for rschema, _ in mform.editable_attributes()])
 
+    def test_inlined_relations(self):
+        with self.admin_access.web_request() as req:
+            with self.temporary_permissions(EmailAddress={'add': ()}):
+                autoform = self.vreg['forms'].select('edition', req, entity=req.user)
+                self.assertEqual(list(autoform.inlined_form_views()), [])
+
+    def test_check_inlined_rdef_permissions(self):
+        # try to check permissions when creating an entity ('user' below is a
+        # fresh entity without an eid)
+        with self.admin_access.web_request() as req:
+            ttype = 'EmailAddress'
+            rschema = self.schema['use_email']
+            rdef =  rschema.rdefs[('CWUser', ttype)]
+            tschema = self.schema[ttype]
+            role = 'subject'
+            with self.temporary_permissions((rdef, {'add': ()})):
+                user = self.vreg['etypes'].etype_class('CWUser')(req)
+                autoform = self.vreg['forms'].select('edition', req, entity=user)
+                self.assertFalse(autoform.check_inlined_rdef_permissions(rschema, role,
+                                                                         tschema, ttype))
+            # we actually don't care about the actual expression,
+            # may_have_permission only checks the presence of such expressions
+            expr = RRQLExpression('S use_email O')
+            with self.temporary_permissions((rdef, {'add': (expr,)})):
+                user = self.vreg['etypes'].etype_class('CWUser')(req)
+                autoform = self.vreg['forms'].select('edition', req, entity=user)
+                self.assertTrue(autoform.check_inlined_rdef_permissions(rschema, role,
+                                                                        tschema, ttype))
+
 
 class FormViewsTC(CubicWebTC):
 
--- a/web/views/actions.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/web/views/actions.py	Fri Oct 09 17:52:14 2015 +0200
@@ -50,7 +50,7 @@
                                                entity=entity, mainform=False)
         for dummy in form.editable_relations():
             return 1
-        for dummy in form.inlined_relations():
+        for dummy in form.inlined_form_views():
             return 1
         for dummy in form.editable_attributes(strict=True):
             return 1
--- a/web/views/autoform.py	Tue Sep 29 12:09:04 2015 +0200
+++ b/web/views/autoform.py	Fri Oct 09 17:52:14 2015 +0200
@@ -126,6 +126,7 @@
 from logilab.mtconverter import xml_escape
 from logilab.common.decorators import iclassmethod, cached
 from logilab.common.deprecation import deprecated
+from logilab.common.registry import NoSelectableObject
 
 from cubicweb import neg_role, uilib
 from cubicweb.schema import display_name
@@ -942,6 +943,8 @@
     def check_inlined_rdef_permissions(self, rschema, role, tschema, ttype):
         """return true if permissions are granted on the inlined object and
         relation"""
+        if not tschema.has_perm(self._cw, 'add'):
+            return False
         entity = self.edited_entity
         rdef = entity.e_schema.rdef(rschema, role, ttype)
         if entity.has_eid():
@@ -949,10 +952,8 @@
                 rdefkwargs = {'fromeid': entity.eid}
             else:
                 rdefkwargs = {'toeid': entity.eid}
-        else:
-            rdefkwargs = {}
-        return (tschema.has_perm(self._cw, 'add')
-                and rdef.has_perm(self._cw, 'add', **rdefkwargs))
+            return rdef.has_perm(self._cw, 'add', **rdefkwargs)
+        return rdef.may_have_permission('add', self._cw)
 
 
     def should_hide_add_new_relation_link(self, rschema, card):
@@ -983,11 +984,16 @@
         """yield inline form views to a newly related (hence created) entity
         through the given relation
         """
-        yield self._cw.vreg['views'].select('inline-creation', self._cw,
-                                            etype=ttype, rtype=rschema, role=role,
-                                            peid=self.edited_entity.eid,
-                                            petype=self.edited_entity.e_schema,
-                                            pform=self)
+        try:
+            yield self._cw.vreg['views'].select('inline-creation', self._cw,
+                                                etype=ttype, rtype=rschema, role=role,
+                                                peid=self.edited_entity.eid,
+                                                petype=self.edited_entity.e_schema,
+                                                pform=self)
+        except NoSelectableObject:
+            # may be raised if user doesn't have the permission to add ttype entities (no checked
+            # earlier) or if there is some custom selector on the view
+            pass
 
 
 ## default form ui configuration ##############################################