7 """ |
7 """ |
8 __docformat__ = "restructuredtext en" |
8 __docformat__ = "restructuredtext en" |
9 |
9 |
10 from cubicweb import UnknownProperty, ValidationError, BadConnectionId |
10 from cubicweb import UnknownProperty, ValidationError, BadConnectionId |
11 from cubicweb.selectors import entity_implements |
11 from cubicweb.selectors import entity_implements |
12 from cubicweb.server.hook import Hook, match_rtype |
12 from cubicweb.server import hook |
13 from cubicweb.server.pool import Operation |
13 |
14 from cubicweb.server.hookhelper import get_user_sessions |
14 |
|
15 def get_user_sessions(repo, ueid): |
|
16 for session in repo._sessions.values(): |
|
17 if ueid == session.user.eid: |
|
18 yield session |
|
19 |
|
20 |
|
21 class SyncSessionHook(hook.Hook): |
|
22 __abstract__ = True |
|
23 category = 'syncsession' |
15 |
24 |
16 |
25 |
17 # user/groups synchronisation ################################################# |
26 # user/groups synchronisation ################################################# |
18 |
27 |
19 class _GroupOperation(Operation): |
28 class _GroupOperation(hook.Operation): |
20 """base class for group operation""" |
29 """base class for group operation""" |
21 geid = None |
30 geid = None |
22 def __init__(self, session, *args, **kwargs): |
31 def __init__(self, session, *args, **kwargs): |
23 """override to get the group name before actual groups manipulation: |
32 """override to get the group name before actual groups manipulation: |
24 |
33 |
25 we may temporarily loose right access during a commit event, so |
34 we may temporarily loose right access during a commit event, so |
26 no query should be emitted while comitting |
35 no query should be emitted while comitting |
27 """ |
36 """ |
28 rql = 'Any N WHERE G eid %(x)s, G name N' |
37 rql = 'Any N WHERE G eid %(x)s, G name N' |
29 result = session.execute(rql, {'x': kwargs['geid']}, 'x', build_descr=False) |
38 result = session.execute(rql, {'x': kwargs['geid']}, 'x', build_descr=False) |
30 Operation.__init__(self, session, *args, **kwargs) |
39 hook.Operation.__init__(self, session, *args, **kwargs) |
31 self.group = result[0][0] |
40 self.group = result[0][0] |
32 |
41 |
33 |
42 |
34 class _DeleteGroupOp(_GroupOperation): |
43 class _DeleteGroupOp(_GroupOperation): |
35 """synchronize user when a in_group relation has been deleted""" |
44 """synchronize user when a in_group relation has been deleted""" |
53 self.group) |
62 self.group) |
54 return |
63 return |
55 groups.add(self.group) |
64 groups.add(self.group) |
56 |
65 |
57 |
66 |
58 class SyncInGroupHook(Hook): |
67 class SyncInGroupHook(SyncSessionHook): |
59 __id__ = 'syncingroup' |
68 __id__ = 'syncingroup' |
60 __select__ = Hook.__select__ & match_rtype('in_group') |
69 __select__ = SyncSessionHook.__select__ & hook.match_rtype('in_group') |
61 events = ('after_delete_relation', 'after_add_relation') |
70 events = ('after_delete_relation', 'after_add_relation') |
62 category = 'syncsession' |
|
63 |
71 |
64 def __call__(self): |
72 def __call__(self): |
65 if self.event == 'after_delete_relation': |
73 if self.event == 'after_delete_relation': |
66 opcls = _DeleteGroupOp |
74 opcls = _DeleteGroupOp |
67 else: |
75 else: |
68 opcls = _AddGroupOp |
76 opcls = _AddGroupOp |
69 for session in get_user_sessions(self.cw_req.repo, self.eidfrom): |
77 for session in get_user_sessions(self.cw_req.repo, self.eidfrom): |
70 opcls(self.cw_req, cnxuser=session.user, geid=self.eidto) |
78 opcls(self.cw_req, cnxuser=session.user, geid=self.eidto) |
71 |
79 |
72 |
80 |
73 class _DelUserOp(Operation): |
81 class _DelUserOp(hook.Operation): |
74 """close associated user's session when it is deleted""" |
82 """close associated user's session when it is deleted""" |
75 def __init__(self, session, cnxid): |
83 def __init__(self, session, cnxid): |
76 self.cnxid = cnxid |
84 self.cnxid = cnxid |
77 Operation.__init__(self, session) |
85 hook.Operation.__init__(self, session) |
78 |
86 |
79 def commit_event(self): |
87 def commit_event(self): |
80 """the observed connections pool has been commited""" |
88 """the observed connections pool has been commited""" |
81 try: |
89 try: |
82 self.repo.close(self.cnxid) |
90 self.repo.close(self.cnxid) |
83 except BadConnectionId: |
91 except BadConnectionId: |
84 pass # already closed |
92 pass # already closed |
85 |
93 |
86 |
94 |
87 class CloseDeletedUserSessionsHook(Hook): |
95 class CloseDeletedUserSessionsHook(SyncSessionHook): |
88 __id__ = 'closession' |
96 __id__ = 'closession' |
89 __select__ = Hook.__select__ & entity_implements('CWUser') |
97 __select__ = SyncSessionHook.__select__ & entity_implements('CWUser') |
90 events = ('after_delete_entity',) |
98 events = ('after_delete_entity',) |
91 category = 'syncsession' |
|
92 |
99 |
93 def __call__(self): |
100 def __call__(self): |
94 """modify user permission, need to update users""" |
101 """modify user permission, need to update users""" |
95 for session in get_user_sessions(self.cw_req.repo, self.entity.eid): |
102 for session in get_user_sessions(self.cw_req.repo, self.entity.eid): |
96 _DelUserOp(self.cw_req, session.id) |
103 _DelUserOp(self.cw_req, session.id) |
97 |
104 |
98 |
105 |
99 # CWProperty hooks ############################################################# |
106 # CWProperty hooks ############################################################# |
100 |
107 |
101 |
108 |
102 class _DelCWPropertyOp(Operation): |
109 class _DelCWPropertyOp(hook.Operation): |
103 """a user's custom properties has been deleted""" |
110 """a user's custom properties has been deleted""" |
104 |
111 |
105 def commit_event(self): |
112 def commit_event(self): |
106 """the observed connections pool has been commited""" |
113 """the observed connections pool has been commited""" |
107 try: |
114 try: |
108 del self.epropdict[self.key] |
115 del self.epropdict[self.key] |
109 except KeyError: |
116 except KeyError: |
110 self.error('%s has no associated value', self.key) |
117 self.error('%s has no associated value', self.key) |
111 |
118 |
112 |
119 |
113 class _ChangeCWPropertyOp(Operation): |
120 class _ChangeCWPropertyOp(hook.Operation): |
114 """a user's custom properties has been added/changed""" |
121 """a user's custom properties has been added/changed""" |
115 |
122 |
116 def commit_event(self): |
123 def commit_event(self): |
117 """the observed connections pool has been commited""" |
124 """the observed connections pool has been commited""" |
118 self.epropdict[self.key] = self.value |
125 self.epropdict[self.key] = self.value |
119 |
126 |
120 |
127 |
121 class _AddCWPropertyOp(Operation): |
128 class _AddCWPropertyOp(hook.Operation): |
122 """a user's custom properties has been added/changed""" |
129 """a user's custom properties has been added/changed""" |
123 |
130 |
124 def commit_event(self): |
131 def commit_event(self): |
125 """the observed connections pool has been commited""" |
132 """the observed connections pool has been commited""" |
126 eprop = self.eprop |
133 eprop = self.eprop |
127 if not eprop.for_user: |
134 if not eprop.for_user: |
128 self.repo.vreg.eprop_values[eprop.pkey] = eprop.value |
135 self.repo.vreg.eprop_values[eprop.pkey] = eprop.value |
129 # if for_user is set, update is handled by a ChangeCWPropertyOp operation |
136 # if for_user is set, update is handled by a ChangeCWPropertyOp operation |
130 |
137 |
131 |
138 |
132 class AddCWPropertyHook(Hook): |
139 class AddCWPropertyHook(SyncSessionHook): |
133 __id__ = 'addcwprop' |
140 __id__ = 'addcwprop' |
134 __select__ = Hook.__select__ & entity_implements('CWProperty') |
141 __select__ = SyncSessionHook.__select__ & entity_implements('CWProperty') |
135 category = 'syncsession' |
|
136 events = ('after_add_entity',) |
142 events = ('after_add_entity',) |
137 |
143 |
138 def __call__(self): |
144 def __call__(self): |
139 key, value = self.entity.pkey, self.entity.value |
145 key, value = self.entity.pkey, self.entity.value |
140 session = self.cw_req |
146 session = self.cw_req |