diff -r 66ff0b2f7d03 -r 99f5852f8604 web/action.py --- 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,