common/mixins.py
branch3.5
changeset 2920 64322aa83a1d
parent 2748 d2fcf19bfb34
child 2968 0e3460341023
child 3002 a9d7eaa07475
equal deleted inserted replaced
2919:662f35236d1c 2920:64322aa83a1d
    11 from logilab.common.deprecation import deprecated
    11 from logilab.common.deprecation import deprecated
    12 from logilab.common.decorators import cached
    12 from logilab.common.decorators import cached
    13 
    13 
    14 from cubicweb import typed_eid
    14 from cubicweb import typed_eid
    15 from cubicweb.selectors import implements
    15 from cubicweb.selectors import implements
    16 from cubicweb.interfaces import IWorkflowable, IEmailable, ITree
    16 from cubicweb.interfaces import IEmailable, ITree
    17 
    17 
    18 
    18 
    19 class TreeMixIn(object):
    19 class TreeMixIn(object):
    20     """base tree-mixin providing the tree interface
    20     """base tree-mixin providing the tree interface
    21 
    21 
   156     def root(self):
   156     def root(self):
   157         """return the root object"""
   157         """return the root object"""
   158         return self.req.entity_from_eid(self.path()[0])
   158         return self.req.entity_from_eid(self.path()[0])
   159 
   159 
   160 
   160 
   161 class WorkflowableMixIn(object):
       
   162     """base mixin providing workflow helper methods for workflowable entities.
       
   163     This mixin will be automatically set on class supporting the 'in_state'
       
   164     relation (which implies supporting 'wf_info_for' as well)
       
   165     """
       
   166     __implements__ = (IWorkflowable,)
       
   167 
       
   168     @property
       
   169     def state(self):
       
   170         try:
       
   171             return self.in_state[0].name
       
   172         except IndexError:
       
   173             self.warning('entity %s has no state', self)
       
   174             return None
       
   175 
       
   176     @property
       
   177     def displayable_state(self):
       
   178         return self.req._(self.state)
       
   179 
       
   180     def wf_state(self, statename):
       
   181         rset = self.req.execute('Any S, SN WHERE S name SN, S name %(n)s, S state_of E, E name %(e)s',
       
   182                                 {'n': statename, 'e': str(self.e_schema)})
       
   183         if rset:
       
   184             return rset.get_entity(0, 0)
       
   185         return None
       
   186 
       
   187     def wf_transition(self, trname):
       
   188         rset = self.req.execute('Any T, TN WHERE T name TN, T name %(n)s, T transition_of E, E name %(e)s',
       
   189                                 {'n': trname, 'e': str(self.e_schema)})
       
   190         if rset:
       
   191             return rset.get_entity(0, 0)
       
   192         return None
       
   193 
       
   194     def change_state(self, state, trcomment=None, trcommentformat=None):
       
   195         """change the entity's state according to a state defined in given
       
   196         parameters
       
   197         """
       
   198         if isinstance(state, basestring):
       
   199             state = self.wf_state(state)
       
   200             assert state is not None, 'not a %s state: %s' % (self.id, state)
       
   201         if hasattr(state, 'eid'):
       
   202             stateeid = state.eid
       
   203         else:
       
   204             stateeid = state
       
   205         stateeid = typed_eid(stateeid)
       
   206         if trcomment:
       
   207             self.req.set_shared_data('trcomment', trcomment)
       
   208         if trcommentformat:
       
   209             self.req.set_shared_data('trcommentformat', trcommentformat)
       
   210         self.req.execute('SET X in_state S WHERE X eid %(x)s, S eid %(s)s',
       
   211                          {'x': self.eid, 's': stateeid}, 'x')
       
   212 
       
   213     def can_pass_transition(self, trname):
       
   214         """return the Transition instance if the current user can pass the
       
   215         transition with the given name, else None
       
   216         """
       
   217         stateeid = self.in_state[0].eid
       
   218         rset = self.req.execute('Any T,N,DS WHERE S allowed_transition T,'
       
   219                                 'S eid %(x)s,T name %(trname)s,ET name %(et)s,'
       
   220                                 'T name N,T destination_state DS,T transition_of ET',
       
   221                                 {'x': stateeid, 'et': str(self.e_schema),
       
   222                                  'trname': trname}, 'x')
       
   223         for tr in rset.entities():
       
   224             if tr.may_be_passed(self.eid, stateeid):
       
   225                 return tr
       
   226 
       
   227     def latest_trinfo(self):
       
   228         """return the latest transition information for this entity"""
       
   229         return self.reverse_wf_info_for[-1]
       
   230 
       
   231     # __method methods ########################################################
       
   232 
       
   233     def set_state(self, params=None):
       
   234         """change the entity's state according to a state defined in given
       
   235         parameters, used to be called using __method controler facility
       
   236         """
       
   237         params = params or self.req.form
       
   238         self.change_state(typed_eid(params.pop('state')),
       
   239                           params.get('trcomment'),
       
   240                           params.get('trcomment_format'))
       
   241         self.req.set_message(self.req._('__msg state changed'))
       
   242 
       
   243     # specific vocabulary methods #############################################
       
   244 
       
   245     @deprecated('use EntityFieldsForm.subject_in_state_vocabulary')
       
   246     def subject_in_state_vocabulary(self, rschema, limit=None):
       
   247         form = self.vreg.select('forms', 'edition', self.req, entity=self)
       
   248         return form.subject_in_state_vocabulary(rschema, limit)
       
   249 
       
   250 
       
   251 
       
   252 class EmailableMixIn(object):
   161 class EmailableMixIn(object):
   253     """base mixin providing the default get_email() method used by
   162     """base mixin providing the default get_email() method used by
   254     the massmailing view
   163     the massmailing view
   255 
   164 
   256     NOTE: The default implementation is based on the
   165     NOTE: The default implementation is based on the
   286         return dict( (attr, getattr(self, attr)) for attr in self.allowed_massmail_keys() )
   195         return dict( (attr, getattr(self, attr)) for attr in self.allowed_massmail_keys() )
   287 
   196 
   288 
   197 
   289 
   198 
   290 MI_REL_TRIGGERS = {
   199 MI_REL_TRIGGERS = {
   291     ('in_state',    'subject'): WorkflowableMixIn,
       
   292     ('primary_email',   'subject'): EmailableMixIn,
   200     ('primary_email',   'subject'): EmailableMixIn,
   293     ('use_email',   'subject'): EmailableMixIn,
   201     ('use_email',   'subject'): EmailableMixIn,
   294     }
   202     }
   295 
   203 
   296 
   204