63 # state / transitions accessors ############################################ |
63 # state / transitions accessors ############################################ |
64 |
64 |
65 def state_by_name(self, statename): |
65 def state_by_name(self, statename): |
66 rset = self._cw.execute('Any S, SN WHERE S name SN, S name %(n)s, ' |
66 rset = self._cw.execute('Any S, SN WHERE S name SN, S name %(n)s, ' |
67 'S state_of WF, WF eid %(wf)s', |
67 'S state_of WF, WF eid %(wf)s', |
68 {'n': statename, 'wf': self.eid}, 'wf') |
68 {'n': statename, 'wf': self.eid}) |
69 if rset: |
69 if rset: |
70 return rset.get_entity(0, 0) |
70 return rset.get_entity(0, 0) |
71 return None |
71 return None |
72 |
72 |
73 def state_by_eid(self, eid): |
73 def state_by_eid(self, eid): |
74 rset = self._cw.execute('Any S, SN WHERE S name SN, S eid %(s)s, ' |
74 rset = self._cw.execute('Any S, SN WHERE S name SN, S eid %(s)s, ' |
75 'S state_of WF, WF eid %(wf)s', |
75 'S state_of WF, WF eid %(wf)s', |
76 {'s': eid, 'wf': self.eid}, ('wf', 's')) |
76 {'s': eid, 'wf': self.eid}) |
77 if rset: |
77 if rset: |
78 return rset.get_entity(0, 0) |
78 return rset.get_entity(0, 0) |
79 return None |
79 return None |
80 |
80 |
81 def transition_by_name(self, trname): |
81 def transition_by_name(self, trname): |
82 rset = self._cw.execute('Any T, TN WHERE T name TN, T name %(n)s, ' |
82 rset = self._cw.execute('Any T, TN WHERE T name TN, T name %(n)s, ' |
83 'T transition_of WF, WF eid %(wf)s', |
83 'T transition_of WF, WF eid %(wf)s', |
84 {'n': trname, 'wf': self.eid}, 'wf') |
84 {'n': trname, 'wf': self.eid}) |
85 if rset: |
85 if rset: |
86 return rset.get_entity(0, 0) |
86 return rset.get_entity(0, 0) |
87 return None |
87 return None |
88 |
88 |
89 def transition_by_eid(self, eid): |
89 def transition_by_eid(self, eid): |
90 rset = self._cw.execute('Any T, TN WHERE T name TN, T eid %(t)s, ' |
90 rset = self._cw.execute('Any T, TN WHERE T name TN, T eid %(t)s, ' |
91 'T transition_of WF, WF eid %(wf)s', |
91 'T transition_of WF, WF eid %(wf)s', |
92 {'t': eid, 'wf': self.eid}, ('wf', 't')) |
92 {'t': eid, 'wf': self.eid}) |
93 if rset: |
93 if rset: |
94 return rset.get_entity(0, 0) |
94 return rset.get_entity(0, 0) |
95 return None |
95 return None |
96 |
96 |
97 # wf construction methods ################################################## |
97 # wf construction methods ################################################## |
98 |
98 |
99 def add_state(self, name, initial=False, **kwargs): |
99 def add_state(self, name, initial=False, **kwargs): |
100 """add a state to this workflow""" |
100 """add a state to this workflow""" |
101 state = self._cw.create_entity('State', name=unicode(name), **kwargs) |
101 state = self._cw.create_entity('State', name=unicode(name), **kwargs) |
102 self._cw.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s', |
102 self._cw.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s', |
103 {'s': state.eid, 'wf': self.eid}, ('s', 'wf')) |
103 {'s': state.eid, 'wf': self.eid}) |
104 if initial: |
104 if initial: |
105 assert not self.initial, "Initial state already defined as %s" % self.initial |
105 assert not self.initial, "Initial state already defined as %s" % self.initial |
106 self._cw.execute('SET WF initial_state S ' |
106 self._cw.execute('SET WF initial_state S ' |
107 'WHERE S eid %(s)s, WF eid %(wf)s', |
107 'WHERE S eid %(s)s, WF eid %(wf)s', |
108 {'s': state.eid, 'wf': self.eid}, ('s', 'wf')) |
108 {'s': state.eid, 'wf': self.eid}) |
109 return state |
109 return state |
110 |
110 |
111 def _add_transition(self, trtype, name, fromstates, |
111 def _add_transition(self, trtype, name, fromstates, |
112 requiredgroups=(), conditions=(), **kwargs): |
112 requiredgroups=(), conditions=(), **kwargs): |
113 tr = self._cw.create_entity(trtype, name=unicode(name), **kwargs) |
113 tr = self._cw.create_entity(trtype, name=unicode(name), **kwargs) |
114 self._cw.execute('SET T transition_of WF ' |
114 self._cw.execute('SET T transition_of WF ' |
115 'WHERE T eid %(t)s, WF eid %(wf)s', |
115 'WHERE T eid %(t)s, WF eid %(wf)s', |
116 {'t': tr.eid, 'wf': self.eid}, ('t', 'wf')) |
116 {'t': tr.eid, 'wf': self.eid}) |
117 assert fromstates, fromstates |
117 assert fromstates, fromstates |
118 if not isinstance(fromstates, (tuple, list)): |
118 if not isinstance(fromstates, (tuple, list)): |
119 fromstates = (fromstates,) |
119 fromstates = (fromstates,) |
120 for state in fromstates: |
120 for state in fromstates: |
121 if hasattr(state, 'eid'): |
121 if hasattr(state, 'eid'): |
122 state = state.eid |
122 state = state.eid |
123 self._cw.execute('SET S allowed_transition T ' |
123 self._cw.execute('SET S allowed_transition T ' |
124 'WHERE S eid %(s)s, T eid %(t)s', |
124 'WHERE S eid %(s)s, T eid %(t)s', |
125 {'s': state, 't': tr.eid}, ('s', 't')) |
125 {'s': state, 't': tr.eid}) |
126 tr.set_permissions(requiredgroups, conditions, reset=False) |
126 tr.set_permissions(requiredgroups, conditions, reset=False) |
127 return tr |
127 return tr |
128 |
128 |
129 def add_transition(self, name, fromstates, tostate=None, |
129 def add_transition(self, name, fromstates, tostate=None, |
130 requiredgroups=(), conditions=(), **kwargs): |
130 requiredgroups=(), conditions=(), **kwargs): |
134 if tostate is not None: |
134 if tostate is not None: |
135 if hasattr(tostate, 'eid'): |
135 if hasattr(tostate, 'eid'): |
136 tostate = tostate.eid |
136 tostate = tostate.eid |
137 self._cw.execute('SET T destination_state S ' |
137 self._cw.execute('SET T destination_state S ' |
138 'WHERE S eid %(s)s, T eid %(t)s', |
138 'WHERE S eid %(s)s, T eid %(t)s', |
139 {'t': tr.eid, 's': tostate}, ('s', 't')) |
139 {'t': tr.eid, 's': tostate}) |
140 return tr |
140 return tr |
141 |
141 |
142 def add_wftransition(self, name, subworkflow, fromstates, exitpoints=(), |
142 def add_wftransition(self, name, subworkflow, fromstates, exitpoints=(), |
143 requiredgroups=(), conditions=(), **kwargs): |
143 requiredgroups=(), conditions=(), **kwargs): |
144 """add a workflow transition to this workflow""" |
144 """add a workflow transition to this workflow""" |
145 tr = self._add_transition('WorkflowTransition', name, fromstates, |
145 tr = self._add_transition('WorkflowTransition', name, fromstates, |
146 requiredgroups, conditions, **kwargs) |
146 requiredgroups, conditions, **kwargs) |
147 if hasattr(subworkflow, 'eid'): |
147 if hasattr(subworkflow, 'eid'): |
148 subworkflow = subworkflow.eid |
148 subworkflow = subworkflow.eid |
149 assert self._cw.execute('SET T subworkflow WF WHERE WF eid %(wf)s,T eid %(t)s', |
149 assert self._cw.execute('SET T subworkflow WF WHERE WF eid %(wf)s,T eid %(t)s', |
150 {'t': tr.eid, 'wf': subworkflow}, ('wf', 't')) |
150 {'t': tr.eid, 'wf': subworkflow}) |
151 for fromstate, tostate in exitpoints: |
151 for fromstate, tostate in exitpoints: |
152 tr.add_exit_point(fromstate, tostate) |
152 tr.add_exit_point(fromstate, tostate) |
153 return tr |
153 return tr |
154 |
154 |
155 def replace_state(self, todelstate, replacement): |
155 def replace_state(self, todelstate, replacement): |
157 if not hasattr(todelstate, 'eid'): |
157 if not hasattr(todelstate, 'eid'): |
158 todelstate = self.state_by_name(todelstate) |
158 todelstate = self.state_by_name(todelstate) |
159 if not hasattr(replacement, 'eid'): |
159 if not hasattr(replacement, 'eid'): |
160 replacement = self.state_by_name(replacement) |
160 replacement = self.state_by_name(replacement) |
161 execute = self._cw.execute |
161 execute = self._cw.execute |
162 execute('SET X in_state S WHERE S eid %(s)s', {'s': todelstate.eid}, 's') |
162 execute('SET X in_state S WHERE S eid %(s)s', {'s': todelstate.eid}) |
163 execute('SET X from_state NS WHERE X to_state OS, OS eid %(os)s, NS eid %(ns)s', |
163 execute('SET X from_state NS WHERE X to_state OS, OS eid %(os)s, NS eid %(ns)s', |
164 {'os': todelstate.eid, 'ns': replacement.eid}, 's') |
164 {'os': todelstate.eid, 'ns': replacement.eid}) |
165 execute('SET X to_state NS WHERE X to_state OS, OS eid %(os)s, NS eid %(ns)s', |
165 execute('SET X to_state NS WHERE X to_state OS, OS eid %(os)s, NS eid %(ns)s', |
166 {'os': todelstate.eid, 'ns': replacement.eid}, 's') |
166 {'os': todelstate.eid, 'ns': replacement.eid}) |
167 todelstate.delete() |
167 todelstate.delete() |
168 |
168 |
169 |
169 |
170 class BaseTransition(AnyEntity): |
170 class BaseTransition(AnyEntity): |
171 """customized class for abstract transition |
171 """customized class for abstract transition |
225 """set or add (if `reset` is False) groups and conditions for this |
225 """set or add (if `reset` is False) groups and conditions for this |
226 transition |
226 transition |
227 """ |
227 """ |
228 if reset: |
228 if reset: |
229 self._cw.execute('DELETE T require_group G WHERE T eid %(x)s', |
229 self._cw.execute('DELETE T require_group G WHERE T eid %(x)s', |
230 {'x': self.eid}, 'x') |
230 {'x': self.eid}) |
231 self._cw.execute('DELETE T condition R WHERE T eid %(x)s', |
231 self._cw.execute('DELETE T condition R WHERE T eid %(x)s', |
232 {'x': self.eid}, 'x') |
232 {'x': self.eid}) |
233 for gname in requiredgroups: |
233 for gname in requiredgroups: |
234 rset = self._cw.execute('SET T require_group G ' |
234 rset = self._cw.execute('SET T require_group G ' |
235 'WHERE T eid %(x)s, G name %(gn)s', |
235 'WHERE T eid %(x)s, G name %(gn)s', |
236 {'x': self.eid, 'gn': gname}, 'x') |
236 {'x': self.eid, 'gn': gname}) |
237 assert rset, '%s is not a known group' % gname |
237 assert rset, '%s is not a known group' % gname |
238 if isinstance(conditions, basestring): |
238 if isinstance(conditions, basestring): |
239 conditions = (conditions,) |
239 conditions = (conditions,) |
240 for expr in conditions: |
240 for expr in conditions: |
241 if isinstance(expr, basestring): |
241 if isinstance(expr, basestring): |
297 if hasattr(fromstate, 'eid'): |
297 if hasattr(fromstate, 'eid'): |
298 fromstate = fromstate.eid |
298 fromstate = fromstate.eid |
299 if tostate is None: |
299 if tostate is None: |
300 self._cw.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, ' |
300 self._cw.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, ' |
301 'X subworkflow_state FS WHERE T eid %(t)s, FS eid %(fs)s', |
301 'X subworkflow_state FS WHERE T eid %(t)s, FS eid %(fs)s', |
302 {'t': self.eid, 'fs': fromstate}, ('t', 'fs')) |
302 {'t': self.eid, 'fs': fromstate}) |
303 else: |
303 else: |
304 if hasattr(tostate, 'eid'): |
304 if hasattr(tostate, 'eid'): |
305 tostate = tostate.eid |
305 tostate = tostate.eid |
306 self._cw.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, ' |
306 self._cw.execute('INSERT SubWorkflowExitPoint X: T subworkflow_exit X, ' |
307 'X subworkflow_state FS, X destination_state TS ' |
307 'X subworkflow_state FS, X destination_state TS ' |
308 'WHERE T eid %(t)s, FS eid %(fs)s, TS eid %(ts)s', |
308 'WHERE T eid %(t)s, FS eid %(fs)s, TS eid %(ts)s', |
309 {'t': self.eid, 'fs': fromstate, 'ts': tostate}, |
309 {'t': self.eid, 'fs': fromstate, 'ts': tostate}) |
310 ('t', 'fs', 'ts')) |
|
311 |
310 |
312 def get_exit_point(self, entity, stateeid): |
311 def get_exit_point(self, entity, stateeid): |
313 """if state is an exit point, return its associated destination state""" |
312 """if state is an exit point, return its associated destination state""" |
314 if hasattr(stateeid, 'eid'): |
313 if hasattr(stateeid, 'eid'): |
315 stateeid = stateeid.eid |
314 stateeid = stateeid.eid |