web/action.py
branchtls-sprint
changeset 631 99f5852f8604
parent 254 b1eda3dd844a
child 640 8e64f12be69c
--- a/web/action.py	Mon Feb 16 16:24:24 2009 +0100
+++ b/web/action.py	Mon Feb 16 18:26:13 2009 +0100
@@ -1,14 +1,15 @@
 """abstract action classes for CubicWeb web client
 
 :organization: Logilab
-:copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 __docformat__ = "restructuredtext en"
 
+from cubicweb import target
 from cubicweb.common.appobject import AppRsetObject
 from cubicweb.common.registerers import action_registerer
-from cubicweb.common.selectors import add_etype_selector, \
+from cubicweb.common.selectors import user_can_add_etype, \
      match_search_state, searchstate_accept_one, \
      searchstate_accept_one_but_etype
     
@@ -21,9 +22,7 @@
     """
     __registry__ = 'actions'
     __registerer__ = action_registerer
-    __selectors__ = (match_search_state,)
-    # by default actions don't appear in link search mode
-    search_states = ('normal',) 
+
     property_defs = {
         'visible':  dict(type='Boolean', default=True,
                          help=_('display the action or not')),
@@ -37,53 +36,6 @@
     site_wide = True # don't want user to configuration actions eproperties
     category = 'moreactions'
     
-    @classmethod
-    def accept_rset(cls, req, rset, row, col):
-        user = req.user
-        action = cls.schema_action
-        if row is None:
-            score = 0
-            need_local_check = [] 
-            geteschema = cls.schema.eschema
-            for etype in rset.column_types(0):
-                accepted = cls.accept(user, etype)
-                if not accepted:
-                    return 0
-                if action:
-                    eschema = geteschema(etype)
-                    if not user.matching_groups(eschema.get_groups(action)):
-                        if eschema.has_local_role(action):
-                            # have to ckeck local roles
-                            need_local_check.append(eschema)
-                            continue
-                        else:
-                            # even a local role won't be enough
-                            return 0
-                score += accepted
-            if need_local_check:
-                # check local role for entities of necessary types
-                for i, row in enumerate(rset):
-                    if not rset.description[i][0] in need_local_check:
-                        continue
-                    if not cls.has_permission(rset.get_entity(i, 0), action):
-                        return 0
-                    score += 1
-            return score
-        col = col or 0
-        etype = rset.description[row][col]
-        score = cls.accept(user, etype)
-        if score and action:
-            if not cls.has_permission(rset.get_entity(row, col), action):
-                return 0
-        return score
-    
-    @classmethod
-    def has_permission(cls, entity, action):
-        """defined in a separated method to ease overriding (see ModifyAction
-        for instance)
-        """
-        return entity.has_perm(action)
-    
     def url(self):
         """return the url associated with this action"""
         raise NotImplementedError
@@ -94,6 +46,7 @@
         if self.category:
             return 'box' + self.category.capitalize()
 
+
 class UnregisteredAction(Action):
     """non registered action used to build boxes. Unless you set them
     explicitly, .vreg and .schema attributes at least are None.
@@ -115,7 +68,7 @@
     """link to the entity creation form. Concrete class must set .etype and
     may override .vid
     """
-    __selectors__ = (add_etype_selector, match_search_state)
+    __selectors__ = (user_can_add_etype,)
     vid = 'creation'
     etype = None
     
@@ -127,21 +80,9 @@
     """an action for an entity. By default entity actions are only
     displayable on single entity result if accept match.
     """
-    __selectors__ = (searchstate_accept_one,)
-    schema_action = None
-    condition = None
+    # XXX deprecate
     
-    @classmethod
-    def accept(cls, user, etype):
-        score = super(EntityAction, cls).accept(user, etype)
-        if not score:
-            return 0
-        # check if this type of entity has the necessary relation
-        if hasattr(cls, 'rtype') and not cls.relation_possible(etype):
-            return 0
-        return score
 
-    
 class LinkToEntityAction(EntityAction):
     """base class for actions consisting to create a new object
     with an initial relation set to an entity.
@@ -149,64 +90,19 @@
     using .etype, .rtype and .target attributes to check if the
     action apply and if the logged user has access to it
     """
-    etype = None
-    rtype = None
-    target = None
+    def my_selector(cls, req, rset, row=None, col=0, **kwargs):
+        return chainall(match_search_state('normal'),
+                        one_line_rset, accept,
+                        relation_possible(cls.rtype, role(cls), cls.etype,
+                                          permission='add'),
+                        may_add_relation(cls.rtype, role(cls)))
+    __selectors__ = my_selector,
+    
     category = 'addrelated'
-
-    @classmethod
-    def accept_rset(cls, req, rset, row, col):
-        entity = rset.get_entity(row or 0, col or 0)
-        # check if this type of entity has the necessary relation
-        if hasattr(cls, 'rtype') and not cls.relation_possible(entity.e_schema):
-            return 0
-        score = cls.accept(req.user, entity.e_schema)
-        if not score:
-            return 0
-        if not cls.check_perms(req, entity):
-            return 0
-        return score
-
-    @classmethod
-    def check_perms(cls, req, entity):
-        if not cls.check_rtype_perm(req, entity):
-            return False
-        # XXX document this:
-        # if user can create the relation, suppose it can create the entity
-        # this is because we usually can't check "add" permission before the
-        # entity has actually been created, and schema security should be
-        # defined considering this
-        #if not cls.check_etype_perm(req, entity):
-        #    return False
-        return True
-        
-    @classmethod
-    def check_etype_perm(cls, req, entity):
-        eschema = cls.schema.eschema(cls.etype)
-        if not eschema.has_perm(req, 'add'):
-            #print req.user.login, 'has no add perm on etype', cls.etype
-            return False
-        #print 'etype perm ok', cls
-        return True
-
-    @classmethod
-    def check_rtype_perm(cls, req, entity):
-        rschema = cls.schema.rschema(cls.rtype)
-        # cls.target is telling us if we want to add the subject or object of
-        # the relation
-        if cls.target == 'subject':
-            if not rschema.has_perm(req, 'add', toeid=entity.eid):
-                #print req.user.login, 'has no add perm on subject rel', cls.rtype, 'with', entity
-                return False
-        elif not rschema.has_perm(req, 'add', fromeid=entity.eid):
-            #print req.user.login, 'has no add perm on object rel', cls.rtype, 'with', entity
-            return False
-        #print 'rtype perm ok', cls
-        return True
-            
+                
     def url(self):
         current_entity = self.rset.get_entity(self.row or 0, self.col or 0)
-        linkto = '%s:%s:%s' % (self.rtype, current_entity.eid, self.target)
+        linkto = '%s:%s:%s' % (self.rtype, current_entity.eid, target(self))
         return self.build_url(vid='creation', etype=self.etype,
                               __linkto=linkto,
                               __redirectpath=current_entity.rest_path(), # should not be url quoted!
@@ -217,5 +113,10 @@
     """LinkToEntity action where the action is not usable on the same
     entity's type as the one refered by the .etype attribute
     """
-    __selectors__ = (searchstate_accept_one_but_etype,)
+    def my_selector(cls, req, rset, row=None, col=0, **kwargs):
+        return chainall(match_search_state('normal'),
+                        but_etype, one_line_rset, accept,
+                        relation_possible(cls.rtype, role(cls), cls.etype),
+                        may_add_relation(cls.rtype, role(cls)))
+    __selectors__ = my_selector,