|
1 """workflow definition and history related entities |
|
2 |
|
3 :organization: Logilab |
|
4 :copyright: 2001-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. |
|
5 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|
6 """ |
|
7 __docformat__ = "restructuredtext en" |
|
8 |
|
9 from cubicweb.entities import AnyEntity, fetch_config |
|
10 |
|
11 |
|
12 class Transition(AnyEntity): |
|
13 """customized class for Transition entities |
|
14 |
|
15 provides a specific may_be_passed method to check if the relation may be |
|
16 passed by the logged user |
|
17 """ |
|
18 id = 'Transition' |
|
19 fetch_attrs, fetch_order = fetch_config(['name']) |
|
20 __rtags__ = {('destination_state', '*', 'subject'): 'create', |
|
21 ('allowed_transition', '*', 'object') : 'create', |
|
22 } |
|
23 |
|
24 def may_be_passed(self, eid, stateeid): |
|
25 """return true if the logged user may pass this transition |
|
26 |
|
27 `eid` is the eid of the object on which we may pass the transition |
|
28 `stateeid` is the eid of the current object'state XXX unused |
|
29 """ |
|
30 user = self.req.user |
|
31 # check user is at least in one of the required groups if any |
|
32 groups = frozenset(g.name for g in self.require_group) |
|
33 if groups: |
|
34 matches = user.matching_groups(groups) |
|
35 if matches: |
|
36 return matches |
|
37 if 'owners' in groups and user.owns(eid): |
|
38 return True |
|
39 # check one of the rql expression conditions matches if any |
|
40 if self.condition: |
|
41 for rqlexpr in self.condition: |
|
42 if rqlexpr.check_expression(self.req, eid): |
|
43 return True |
|
44 if self.condition or groups: |
|
45 return False |
|
46 return True |
|
47 |
|
48 def destination(self): |
|
49 return self.destination_state[0] |
|
50 |
|
51 def after_deletion_path(self): |
|
52 """return (path, parameters) which should be used as redirect |
|
53 information when this entity is being deleted |
|
54 """ |
|
55 if self.transition_of: |
|
56 return self.transition_of[0].rest_path(), {'vid': 'workflow'} |
|
57 return super(Transition, self).after_deletion_path() |
|
58 |
|
59 |
|
60 class State(AnyEntity): |
|
61 """customized class for State entities |
|
62 |
|
63 provides a specific transitions method returning transitions that may be |
|
64 passed by the current user for the given entity |
|
65 """ |
|
66 id = 'State' |
|
67 fetch_attrs, fetch_order = fetch_config(['name']) |
|
68 rest_attr = 'eid' |
|
69 |
|
70 __rtags__ = {'destination_state' : 'create', |
|
71 'allowed_transition' : 'create' |
|
72 } |
|
73 |
|
74 def transitions(self, entity, desteid=None): |
|
75 rql = ('Any T,N,DS where S allowed_transition T, S eid %(x)s, ' |
|
76 'T name N, T destination_state DS, ' |
|
77 'T transition_of ET, ET name %(et)s') |
|
78 if desteid is not None: |
|
79 rql += ', DS eid %(ds)s' |
|
80 rset = self.req.execute(rql, {'x': self.eid, 'et': str(entity.e_schema), |
|
81 'ds': desteid}, 'x') |
|
82 for tr in rset.entities(): |
|
83 if tr.may_be_passed(entity.eid, self.eid): |
|
84 yield tr |
|
85 |
|
86 def after_deletion_path(self): |
|
87 """return (path, parameters) which should be used as redirect |
|
88 information when this entity is being deleted |
|
89 """ |
|
90 if self.state_of: |
|
91 return self.state_of[0].rest_path(), {'vid': 'workflow'} |
|
92 return super(State, self).after_deletion_path() |
|
93 |
|
94 |
|
95 class TrInfo(AnyEntity): |
|
96 """customized class for Transition information entities |
|
97 """ |
|
98 id = 'TrInfo' |
|
99 fetch_attrs, fetch_order = fetch_config(['creation_date', 'comment'], |
|
100 pclass=None) # don't want modification_date |
|
101 @property |
|
102 def for_entity(self): |
|
103 return self.wf_info_for and self.wf_info_for[0] |
|
104 @property |
|
105 def previous_state(self): |
|
106 return self.from_state and self.from_state[0] |
|
107 |
|
108 @property |
|
109 def new_state(self): |
|
110 return self.to_state[0] |
|
111 |
|
112 def after_deletion_path(self): |
|
113 """return (path, parameters) which should be used as redirect |
|
114 information when this entity is being deleted |
|
115 """ |
|
116 if self.for_entity: |
|
117 return self.for_entity.rest_path(), {} |
|
118 return 'view', {} |