web/views/actions.py
branchtls-sprint
changeset 631 99f5852f8604
parent 554 f412343c89ad
child 660 5233a9457f6b
--- a/web/views/actions.py	Mon Feb 16 16:24:24 2009 +0100
+++ b/web/views/actions.py	Mon Feb 16 18:26:13 2009 +0100
@@ -6,70 +6,86 @@
 """
 __docformat__ = "restructuredtext en"
 
-from cubicweb.common.selectors import (searchstate_accept, match_user_group, yes,
-                                       one_line_rset, two_lines_rset, one_etype_rset,
-                                       authenticated_user,
-                                       match_search_state, chainfirst, chainall)
+from cubicweb.common.selectors import (
+    yes, one_line_rset, two_lines_rset, one_etype_rset, relation_possible,
+    non_final_entity,
+    authenticated_user, match_user_groups, match_search_state,
+    has_editable_relation, has_permission, has_add_permission,
+    )
 
-from cubicweb.web.action import Action, EntityAction,  LinkToEntityAction
-from cubicweb.web.views import linksearch_select_url, linksearch_match
+from cubicweb.web.action import Action
+from cubicweb.web.views import linksearch_select_url
 from cubicweb.web.views.baseviews import vid_from_rset
 
 _ = unicode
 
+def match_searched_etype(cls, req, rset, row=None, col=None, **kwargs):
+    return req.match_search_state(rset)
+
+def view_is_not_default_view(cls, req, rset, row, col, **kwargs):
+    # interesting if it propose another view than the current one
+    vid = req.form.get('vid')
+    if vid and vid != vid_from_rset(req, rset, cls.schema):
+        return 1
+    return 0
+
+def addable_etype_empty_rset(cls, req, rset, **kwargs):
+    if rset is not None and not rset.rowcount:
+        rqlst = rset.syntax_tree()
+        if len(rqlst.children) > 1:
+            return 0
+        select = rqlst.children[0]
+        if len(select.defined_vars) == 1 and len(select.solutions) == 1:
+            rset._searched_etype = select.solutions[0].itervalues().next()
+            eschema = cls.schema.eschema(rset._searched_etype)
+            if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
+                   and eschema.has_perm(req, 'add'):
+                return 1
+    return 0
+
 # generic primary actions #####################################################
 
-class SelectAction(EntityAction):
+class SelectAction(Action):
     """base class for link search actions. By default apply on
     any size entity result search it the current state is 'linksearch'
     if accept match.
     """
-    category = 'mainactions'    
-    __selectors__ = (searchstate_accept,)
-    search_states = ('linksearch',)
-    order = 0
+    id = 'select'
+    __selectors__ = (match_search_state('linksearch'),
+                     match_searched_etype)
     
-    id = 'select'
     title = _('select')
-    
-    @classmethod
-    def accept_rset(cls, req, rset, row, col):
-        return linksearch_match(req, rset)
+    category = 'mainactions'    
+    order = 0
     
     def url(self):
         return linksearch_select_url(self.req, self.rset)
 
 
 class CancelSelectAction(Action):
+    id = 'cancel'
+    __selectors__ = (match_search_state('linksearch'),)
+    
+    title = _('cancel select')
     category = 'mainactions'
-    search_states = ('linksearch',)
     order = 10
     
-    id = 'cancel'
-    title = _('cancel select')
-    
     def url(self):
-        target, link_eid, r_type, searched_type = self.req.search_state[1]
-        return self.build_url(rql="Any X WHERE X eid %s" % link_eid,
+        target, eid, r_type, searched_type = self.req.search_state[1]
+        return self.build_url(str(eid),
                               vid='edition', __mode='normal')
 
 
 class ViewAction(Action):
-    category = 'mainactions'    
-    __selectors__ = (match_user_group, searchstate_accept)
-    require_groups = ('users', 'managers')
-    order = 0
-    
     id = 'view'
-    title = _('view')
+    __selectors__ = (match_search_state('normal'),
+                     match_user_groups('users', 'managers'),
+                     view_is_not_default_view,
+                     non_final_entity())
     
-    @classmethod
-    def accept_rset(cls, req, rset, row, col):
-        # interesting if it propose another view than the current one
-        vid = req.form.get('vid')
-        if vid and vid != vid_from_rset(req, rset, cls.schema):
-            return 1
-        return 0
+    title = _('view')
+    category = 'mainactions'    
+    order = 0
     
     def url(self):
         params = self.req.form.copy()
@@ -79,76 +95,60 @@
                               **params)
 
 
-class ModifyAction(EntityAction):
-    category = 'mainactions'
-    __selectors__ = (one_line_rset, searchstate_accept)
-    #__selectors__ = searchstate_accept,
-    schema_action = 'update'
-    order = 10
-    
+class ModifyAction(Action):
     id = 'edit'
-    title = _('modify')
+    __selectors__ = (match_search_state('normal'),
+                     one_line_rset, 
+                     has_permission('update') | has_editable_relation('add'))
     
-    @classmethod
-    def has_permission(cls, entity, action):
-        if entity.has_perm(action):
-            return True
-        # if user has no update right but it can modify some relation,
-        # display action anyway
-        for dummy in entity.srelations_by_category(('generic', 'metadata'),
-                                                   'add'):
-            return True
-        for rschema, targetschemas, role in entity.relations_by_category(
-            ('primary', 'secondary'), 'add'):
-            if not rschema.is_final():
-                return True
-        return False
+    title = _('modify')
+    category = 'mainactions'
+    order = 10
 
     def url(self):
         entity = self.rset.get_entity(self.row or 0, self.col or 0)
         return entity.absolute_url(vid='edition')
         
 
-class MultipleEditAction(EntityAction):
+class MultipleEditAction(Action):
+    id = 'muledit' # XXX get strange conflicts if id='edit'
+    __selectors__ = (match_search_state('normal'),
+                     two_lines_rset, one_etype_rset,
+                     has_permission('update'))
+
+    title = _('modify')
     category = 'mainactions'
-    __selectors__ = (two_lines_rset, one_etype_rset,
-                     searchstate_accept)
-    schema_action = 'update'
     order = 10
     
-    id = 'muledit' # XXX get strange conflicts if id='edit'
-    title = _('modify')
-    
     def url(self):
         return self.build_url('view', rql=self.rset.rql, vid='muledit')
 
 
 # generic secondary actions ###################################################
 
-class ManagePermissions(LinkToEntityAction):
-    accepts = ('Any',)
-    category = 'moreactions'
+class ManagePermissions(Action):
     id = 'addpermission'
+    __selectors__ = (
+        (match_user_groups('managers') 
+         | relation_possible('require_permission', 'subject', 'EPermission')),
+                   )
+
     title = _('manage permissions')
+    category = 'moreactions'
     order = 100
-
-    etype = 'EPermission'
-    rtype = 'require_permission'
-    target = 'object'
     
     def url(self):
         return self.rset.get_entity(0, 0).absolute_url(vid='security')
 
     
-class DeleteAction(EntityAction):
+class DeleteAction(Action):
+    id = 'delete'
+    __selectors__ = (has_permission('delete'),)
+    
+    title = _('delete')
     category = 'moreactions' 
-    __selectors__ = (searchstate_accept,)
-    schema_action = 'delete'
     order = 20
     
-    id = 'delete'
-    title = _('delete')
-    
     def url(self):
         if len(self.rset) == 1:
             entity = self.rset.get_entity(0, 0)
@@ -156,14 +156,14 @@
         return self.build_url(rql=self.rset.printable_rql(), vid='deleteconf')
     
         
-class CopyAction(EntityAction):
+class CopyAction(Action):
+    id = 'copy'
+    __selectors__ = (has_permission('add'),)
+    
+    title = _('copy')
     category = 'moreactions'
-    schema_action = 'add'
     order = 30
     
-    id = 'copy'
-    title = _('copy')
-    
     def url(self):
         entity = self.rset.get_entity(self.row or 0, self.col or 0)
         return entity.absolute_url(vid='copy')
@@ -173,35 +173,16 @@
     """when we're seeing more than one entity with the same type, propose to
     add a new one
     """
+    id = 'addentity'
+    __selectors__ = (match_search_state('normal'),
+                     (addable_etype_empty_rset
+                      # XXX has_add_permission in the middle so '&' is available
+                      | (two_lines_rset & has_add_permission() & one_etype_rset ))
+                     )
+
     category = 'moreactions'
-    id = 'addentity'
     order = 40
     
-    def etype_rset_selector(cls, req, rset, **kwargs):
-        if rset is not None and not rset.rowcount:
-            rqlst = rset.syntax_tree()
-            if len(rqlst.children) > 1:
-                return 0
-            select = rqlst.children[0]
-            if len(select.defined_vars) == 1 and len(select.solutions) == 1:
-                rset._searched_etype = select.solutions[0].itervalues().next()
-                eschema = cls.schema.eschema(rset._searched_etype)
-                if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
-                       and eschema.has_perm(req, 'add'):
-                    return 1
-        return 0
-
-    def has_add_perm_selector(cls, req, rset, **kwargs):
-        eschema = cls.schema.eschema(rset.description[0][0])
-        if not (eschema.is_final() or eschema.is_subobject(strict=True)) \
-               and eschema.has_perm(req, 'add'):
-            return 1
-        return 0
-    __selectors__ = (match_search_state,
-                     chainfirst(etype_rset_selector,
-                                chainall(two_lines_rset, one_etype_rset,
-                                         has_add_perm_selector)))
-
     @property
     def rsettype(self):
         if self.rset:
@@ -219,36 +200,36 @@
 # logged user actions #########################################################
 
 class UserPreferencesAction(Action):
+    id = 'myprefs'
+    __selectors__ = (authenticated_user,)
+    
+    title = _('user preferences')
     category = 'useractions'
-    __selectors__ = authenticated_user,
     order = 10
-    
-    id = 'myprefs'
-    title = _('user preferences')
 
     def url(self):
         return self.build_url(self.id)
 
 
 class UserInfoAction(Action):
+    id = 'myinfos'
+    __selectors__ = (authenticated_user,)
+    
+    title = _('personnal informations')
     category = 'useractions'
-    __selectors__ = authenticated_user,
     order = 20
-    
-    id = 'myinfos'
-    title = _('personnal informations')
 
     def url(self):
         return self.build_url('euser/%s'%self.req.user.login, vid='edition')
 
 
 class LogoutAction(Action):
+    id = 'logout'
+    __selectors__ = (authenticated_user,)
+    
+    title = _('logout')
     category = 'useractions'
-    __selectors__ = authenticated_user,
     order = 30
-    
-    id = 'logout'
-    title = _('logout')
 
     def url(self):
         return self.build_url(self.id)
@@ -257,60 +238,35 @@
 # site actions ################################################################
 
 class ManagersAction(Action):
+    __abstract__ = True
+    __selectors__ = (match_user_groups('managers'),)
+
     category = 'siteactions'
-    __abstract__ = True
-    __selectors__ = match_user_group,
-    require_groups = ('managers',)
 
     def url(self):
         return self.build_url(self.id)
 
     
 class SiteConfigurationAction(ManagersAction):
-    order = 10
     id = 'siteconfig'
     title = _('site configuration')
+    order = 10
 
     
 class ManageAction(ManagersAction):
-    order = 20
     id = 'manage'
     title = _('manage')
+    order = 20
 
 
 class ViewSchemaAction(Action):
+    id = 'schema'
+    __selectors__ = (yes,)
+    
+    title = _("site schema")
     category = 'siteactions'
-    id = 'schema'
-    title = _("site schema")
-    __selectors__ = yes,
     order = 30
     
     def url(self):
         return self.build_url(self.id)
 
-
-# content type specific actions ###############################################
-
-class FollowAction(EntityAction):
-    category = 'mainactions'
-    accepts = ('Bookmark',)
-    
-    id = 'follow'
-    title = _('follow')
-    
-    def url(self):
-        return self.rset.get_entity(self.row or 0, self.col or 0).actual_url()
-
-class UserPreferencesEntityAction(EntityAction):
-    __selectors__ = EntityAction.__selectors__ + (one_line_rset, match_user_group,)
-    require_groups = ('owners', 'managers')
-    category = 'mainactions'
-    accepts = ('EUser',)
-    
-    id = 'prefs'
-    title = _('preferences')
-    
-    def url(self):
-        login = self.rset.get_entity(self.row or 0, self.col or 0).login
-        return self.build_url('euser/%s'%login, vid='epropertiesform')
-