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 |