##// END OF EJS Templates
events: cleanup code, pep8, better logging.
marcink -
r2920:c35ca856 default
parent child Browse files
Show More
@@ -1,43 +1,44 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2018 RhodeCode GmbH
3 # Copyright (C) 2016-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from rhodecode import events
23 from rhodecode import events
24 from rhodecode.lib import rc_cache
24 from rhodecode.lib import rc_cache
25
25
26 log = logging.getLogger(__name__)
26 log = logging.getLogger(__name__)
27
27
28
28
29 def trigger_user_permission_flush(event):
29 def trigger_user_permission_flush(event):
30 """
30 """
31 Subscriber to the `UserPermissionsChange`. This triggers the
31 Subscriber to the `UserPermissionsChange`. This triggers the
32 automatic flush of permission caches, so the users affected receive new permissions
32 automatic flush of permission caches, so the users affected receive new permissions
33 Right Away
33 Right Away
34 """
34 """
35
35 affected_user_ids = set(event.user_ids)
36 affected_user_ids = set(event.user_ids)
36 for user_id in affected_user_ids:
37 for user_id in affected_user_ids:
37 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
38 cache_namespace_uid = 'cache_user_auth.{}'.format(user_id)
38 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
39 del_keys = rc_cache.clear_cache_namespace('cache_perms', cache_namespace_uid)
39 log.debug('Deleted %s cache keys for user_id: %s', del_keys, user_id)
40 log.debug('Deleted %s cache keys for user_id: %s', del_keys, user_id)
40
41
41
42
42 def includeme(config):
43 def includeme(config):
43 config.add_subscriber(trigger_user_permission_flush, events.UserPermissionsChange)
44 config.add_subscriber(trigger_user_permission_flush, events.UserPermissionsChange)
@@ -1,84 +1,84 b''
1 # Copyright (C) 2016-2018 RhodeCode GmbH
1 # Copyright (C) 2016-2018 RhodeCode GmbH
2 #
2 #
3 # This program is free software: you can redistribute it and/or modify
3 # This program is free software: you can redistribute it and/or modify
4 # it under the terms of the GNU Affero General Public License, version 3
4 # it under the terms of the GNU Affero General Public License, version 3
5 # (only), as published by the Free Software Foundation.
5 # (only), as published by the Free Software Foundation.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU Affero General Public License
12 # You should have received a copy of the GNU Affero General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 #
14 #
15 # This program is dual-licensed. If you wish to learn more about the
15 # This program is dual-licensed. If you wish to learn more about the
16 # RhodeCode Enterprise Edition, including its added features, Support services,
16 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
17 # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 import logging
19 import logging
20 from pyramid.threadlocal import get_current_registry
20 from pyramid.threadlocal import get_current_registry
21 from rhodecode.events.base import RhodecodeEvent
21 from rhodecode.events.base import RhodecodeEvent
22
22
23
23
24 log = logging.getLogger(__name__)
24 log = logging.getLogger(__name__)
25
25
26
26
27 def trigger(event, registry=None):
27 def trigger(event, registry=None):
28 """
28 """
29 Helper method to send an event. This wraps the pyramid logic to send an
29 Helper method to send an event. This wraps the pyramid logic to send an
30 event.
30 event.
31 """
31 """
32 # For the first step we are using pyramids thread locals here. If the
32 # For the first step we are using pyramids thread locals here. If the
33 # event mechanism works out as a good solution we should think about
33 # event mechanism works out as a good solution we should think about
34 # passing the registry as an argument to get rid of it.
34 # passing the registry as an argument to get rid of it.
35 registry = registry or get_current_registry()
35 registry = registry or get_current_registry()
36 registry.notify(event)
36 registry.notify(event)
37 log.debug('event %s triggered using registry %s', event, registry)
37 log.debug('event %s triggered using registry %s', event.__class__, registry)
38
38
39 # Until we can work around the problem that VCS operations do not have a
39 # Until we can work around the problem that VCS operations do not have a
40 # pyramid context to work with, we send the events to integrations directly
40 # pyramid context to work with, we send the events to integrations directly
41
41
42 # Later it will be possible to use regular pyramid subscribers ie:
42 # Later it will be possible to use regular pyramid subscribers ie:
43 # config.add_subscriber(
43 # config.add_subscriber(
44 # 'rhodecode.integrations.integrations_event_handler',
44 # 'rhodecode.integrations.integrations_event_handler',
45 # 'rhodecode.events.RhodecodeEvent')
45 # 'rhodecode.events.RhodecodeEvent')
46 # trigger(event, request.registry)
46 # trigger(event, request.registry)
47
47
48 from rhodecode.integrations import integrations_event_handler
48 from rhodecode.integrations import integrations_event_handler
49 if isinstance(event, RhodecodeEvent):
49 if isinstance(event, RhodecodeEvent):
50 integrations_event_handler(event)
50 integrations_event_handler(event)
51
51
52
52
53 from rhodecode.events.user import ( # noqa
53 from rhodecode.events.user import ( # noqa
54 UserPreCreate,
54 UserPreCreate,
55 UserPostCreate,
55 UserPostCreate,
56 UserPreUpdate,
56 UserPreUpdate,
57 UserRegistered,
57 UserRegistered,
58 UserPermissionsChange,
58 UserPermissionsChange,
59 )
59 )
60
60
61 from rhodecode.events.repo import ( # noqa
61 from rhodecode.events.repo import ( # noqa
62 RepoEvent,
62 RepoEvent,
63 RepoPreCreateEvent, RepoCreateEvent,
63 RepoPreCreateEvent, RepoCreateEvent,
64 RepoPreDeleteEvent, RepoDeleteEvent,
64 RepoPreDeleteEvent, RepoDeleteEvent,
65 RepoPrePushEvent, RepoPushEvent,
65 RepoPrePushEvent, RepoPushEvent,
66 RepoPrePullEvent, RepoPullEvent,
66 RepoPrePullEvent, RepoPullEvent,
67 )
67 )
68
68
69 from rhodecode.events.repo_group import ( # noqa
69 from rhodecode.events.repo_group import ( # noqa
70 RepoGroupEvent,
70 RepoGroupEvent,
71 RepoGroupCreateEvent,
71 RepoGroupCreateEvent,
72 RepoGroupUpdateEvent,
72 RepoGroupUpdateEvent,
73 RepoGroupDeleteEvent,
73 RepoGroupDeleteEvent,
74 )
74 )
75
75
76 from rhodecode.events.pullrequest import ( # noqa
76 from rhodecode.events.pullrequest import ( # noqa
77 PullRequestEvent,
77 PullRequestEvent,
78 PullRequestCreateEvent,
78 PullRequestCreateEvent,
79 PullRequestUpdateEvent,
79 PullRequestUpdateEvent,
80 PullRequestCommentEvent,
80 PullRequestCommentEvent,
81 PullRequestReviewEvent,
81 PullRequestReviewEvent,
82 PullRequestMergeEvent,
82 PullRequestMergeEvent,
83 PullRequestCloseEvent,
83 PullRequestCloseEvent,
84 )
84 )
@@ -1,222 +1,221 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2018 RhodeCode GmbH
3 # Copyright (C) 2011-2018 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 """
22 """
23 Model for integrations
23 Model for integrations
24 """
24 """
25
25
26
26
27 import logging
27 import logging
28
28
29 from sqlalchemy import or_, and_
29 from sqlalchemy import or_, and_
30
30
31 import rhodecode
31 import rhodecode
32 from rhodecode import events
32 from rhodecode import events
33 from rhodecode.integrations.types.base import EEIntegration
33 from rhodecode.integrations.types.base import EEIntegration
34 from rhodecode.lib.caching_query import FromCache
34 from rhodecode.lib.caching_query import FromCache
35 from rhodecode.model import BaseModel
35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import Integration, Repository, RepoGroup
36 from rhodecode.model.db import Integration, Repository, RepoGroup, true, false
37 from rhodecode.integrations import integration_type_registry
37 from rhodecode.integrations import integration_type_registry
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41
41
42 class IntegrationModel(BaseModel):
42 class IntegrationModel(BaseModel):
43
43
44 cls = Integration
44 cls = Integration
45
45
46 def __get_integration(self, integration):
46 def __get_integration(self, integration):
47 if isinstance(integration, Integration):
47 if isinstance(integration, Integration):
48 return integration
48 return integration
49 elif isinstance(integration, (int, long)):
49 elif isinstance(integration, (int, long)):
50 return self.sa.query(Integration).get(integration)
50 return self.sa.query(Integration).get(integration)
51 else:
51 else:
52 if integration:
52 if integration:
53 raise Exception('integration must be int, long or Instance'
53 raise Exception('integration must be int, long or Instance'
54 ' of Integration got %s' % type(integration))
54 ' of Integration got %s' % type(integration))
55
55
56 def create(self, IntegrationType, name, enabled, repo, repo_group,
56 def create(self, IntegrationType, name, enabled, repo, repo_group,
57 child_repos_only, settings):
57 child_repos_only, settings):
58 """ Create an IntegrationType integration """
58 """ Create an IntegrationType integration """
59 integration = Integration()
59 integration = Integration()
60 integration.integration_type = IntegrationType.key
60 integration.integration_type = IntegrationType.key
61 self.sa.add(integration)
61 self.sa.add(integration)
62 self.update_integration(integration, name, enabled, repo, repo_group,
62 self.update_integration(integration, name, enabled, repo, repo_group,
63 child_repos_only, settings)
63 child_repos_only, settings)
64 self.sa.commit()
64 self.sa.commit()
65 return integration
65 return integration
66
66
67 def update_integration(self, integration, name, enabled, repo, repo_group,
67 def update_integration(self, integration, name, enabled, repo, repo_group,
68 child_repos_only, settings):
68 child_repos_only, settings):
69 integration = self.__get_integration(integration)
69 integration = self.__get_integration(integration)
70
70
71 integration.repo = repo
71 integration.repo = repo
72 integration.repo_group = repo_group
72 integration.repo_group = repo_group
73 integration.child_repos_only = child_repos_only
73 integration.child_repos_only = child_repos_only
74 integration.name = name
74 integration.name = name
75 integration.enabled = enabled
75 integration.enabled = enabled
76 integration.settings = settings
76 integration.settings = settings
77
77
78 return integration
78 return integration
79
79
80 def delete(self, integration):
80 def delete(self, integration):
81 integration = self.__get_integration(integration)
81 integration = self.__get_integration(integration)
82 if integration:
82 if integration:
83 self.sa.delete(integration)
83 self.sa.delete(integration)
84 return True
84 return True
85 return False
85 return False
86
86
87 def get_integration_handler(self, integration):
87 def get_integration_handler(self, integration):
88 TypeClass = integration_type_registry.get(integration.integration_type)
88 TypeClass = integration_type_registry.get(integration.integration_type)
89 if not TypeClass:
89 if not TypeClass:
90 log.error('No class could be found for integration type: {}'.format(
90 log.error('No class could be found for integration type: {}'.format(
91 integration.integration_type))
91 integration.integration_type))
92 return None
92 return None
93 elif isinstance(TypeClass, EEIntegration) or issubclass(TypeClass, EEIntegration):
93 elif isinstance(TypeClass, EEIntegration) or issubclass(TypeClass, EEIntegration):
94 log.error('EE integration cannot be '
94 log.error('EE integration cannot be '
95 'executed for integration type: {}'.format(
95 'executed for integration type: {}'.format(
96 integration.integration_type))
96 integration.integration_type))
97 return None
97 return None
98
98
99 return TypeClass(integration.settings)
99 return TypeClass(integration.settings)
100
100
101 def send_event(self, integration, event):
101 def send_event(self, integration, event):
102 """ Send an event to an integration """
102 """ Send an event to an integration """
103 handler = self.get_integration_handler(integration)
103 handler = self.get_integration_handler(integration)
104 if handler:
104 if handler:
105 log.debug(
105 log.debug(
106 'events: sending event %s on integration %s using handler %s',
106 'events: sending event %s on integration %s using handler %s',
107 event, integration, handler)
107 event, integration, handler)
108 handler.send_event(event)
108 handler.send_event(event)
109
109
110 def get_integrations(self, scope, IntegrationType=None):
110 def get_integrations(self, scope, IntegrationType=None):
111 """
111 """
112 Return integrations for a scope, which must be one of:
112 Return integrations for a scope, which must be one of:
113
113
114 'all' - every integration, global/repogroup/repo
114 'all' - every integration, global/repogroup/repo
115 'global' - global integrations only
115 'global' - global integrations only
116 <Repository> instance - integrations for this repo only
116 <Repository> instance - integrations for this repo only
117 <RepoGroup> instance - integrations for this repogroup only
117 <RepoGroup> instance - integrations for this repogroup only
118 """
118 """
119
119
120 if isinstance(scope, Repository):
120 if isinstance(scope, Repository):
121 query = self.sa.query(Integration).filter(
121 query = self.sa.query(Integration).filter(
122 Integration.repo==scope)
122 Integration.repo == scope)
123 elif isinstance(scope, RepoGroup):
123 elif isinstance(scope, RepoGroup):
124 query = self.sa.query(Integration).filter(
124 query = self.sa.query(Integration).filter(
125 Integration.repo_group==scope)
125 Integration.repo_group == scope)
126 elif scope == 'global':
126 elif scope == 'global':
127 # global integrations
127 # global integrations
128 query = self.sa.query(Integration).filter(
128 query = self.sa.query(Integration).filter(
129 and_(Integration.repo_id==None, Integration.repo_group_id==None)
129 and_(Integration.repo_id == None, Integration.repo_group_id == None)
130 )
130 )
131 elif scope == 'root-repos':
131 elif scope == 'root-repos':
132 query = self.sa.query(Integration).filter(
132 query = self.sa.query(Integration).filter(
133 and_(Integration.repo_id==None,
133 and_(Integration.repo_id == None,
134 Integration.repo_group_id==None,
134 Integration.repo_group_id == None,
135 Integration.child_repos_only==True)
135 Integration.child_repos_only == true())
136 )
136 )
137 elif scope == 'all':
137 elif scope == 'all':
138 query = self.sa.query(Integration)
138 query = self.sa.query(Integration)
139 else:
139 else:
140 raise Exception(
140 raise Exception(
141 "invalid `scope`, must be one of: "
141 "invalid `scope`, must be one of: "
142 "['global', 'all', <Repository>, <RepoGroup>]")
142 "['global', 'all', <Repository>, <RepoGroup>]")
143
143
144 if IntegrationType is not None:
144 if IntegrationType is not None:
145 query = query.filter(
145 query = query.filter(
146 Integration.integration_type==IntegrationType.key)
146 Integration.integration_type==IntegrationType.key)
147
147
148 result = []
148 result = []
149 for integration in query.all():
149 for integration in query.all():
150 IntType = integration_type_registry.get(integration.integration_type)
150 IntType = integration_type_registry.get(integration.integration_type)
151 result.append((IntType, integration))
151 result.append((IntType, integration))
152 return result
152 return result
153
153
154 def get_for_event(self, event, cache=False):
154 def get_for_event(self, event, cache=False):
155 """
155 """
156 Get integrations that match an event
156 Get integrations that match an event
157 """
157 """
158 query = self.sa.query(
158 query = self.sa.query(
159 Integration
159 Integration
160 ).filter(
160 ).filter(
161 Integration.enabled==True
161 Integration.enabled == true()
162 )
162 )
163
163
164 global_integrations_filter = and_(
164 global_integrations_filter = and_(
165 Integration.repo_id==None,
165 Integration.repo_id == None,
166 Integration.repo_group_id==None,
166 Integration.repo_group_id == None,
167 Integration.child_repos_only==False,
167 Integration.child_repos_only == False,
168 )
168 )
169
169
170 if isinstance(event, events.RepoEvent):
170 if isinstance(event, events.RepoEvent):
171 root_repos_integrations_filter = and_(
171 root_repos_integrations_filter = and_(
172 Integration.repo_id==None,
172 Integration.repo_id == None,
173 Integration.repo_group_id==None,
173 Integration.repo_group_id == None,
174 Integration.child_repos_only==True,
174 Integration.child_repos_only == true(),
175 )
175 )
176
176
177 clauses = [
177 clauses = [
178 global_integrations_filter,
178 global_integrations_filter,
179 ]
179 ]
180
180
181 # repo integrations
181 # repo integrations
182 if event.repo.repo_id: # pre create events dont have a repo_id yet
182 if event.repo.repo_id: # pre create events dont have a repo_id yet
183 clauses.append(
183 clauses.append(
184 Integration.repo_id==event.repo.repo_id
184 Integration.repo_id == event.repo.repo_id
185 )
185 )
186
186
187 if event.repo.group:
187 if event.repo.group:
188 clauses.append(
188 clauses.append(
189 and_(
189 and_(
190 Integration.repo_group_id==event.repo.group.group_id,
190 Integration.repo_group_id == event.repo.group.group_id,
191 Integration.child_repos_only==True
191 Integration.child_repos_only == true()
192 )
192 )
193 )
193 )
194 # repo group cascade to kids
194 # repo group cascade to kids
195 clauses.append(
195 clauses.append(
196 and_(
196 and_(
197 Integration.repo_group_id.in_(
197 Integration.repo_group_id.in_(
198 [group.group_id for group in
198 [group.group_id for group in
199 event.repo.groups_with_parents]
199 event.repo.groups_with_parents]
200 ),
200 ),
201 Integration.child_repos_only==False
201 Integration.child_repos_only == false()
202 )
202 )
203 )
203 )
204
204
205
206 if not event.repo.group: # root repo
205 if not event.repo.group: # root repo
207 clauses.append(root_repos_integrations_filter)
206 clauses.append(root_repos_integrations_filter)
208
207
209 query = query.filter(or_(*clauses))
208 query = query.filter(or_(*clauses))
210
209
211 if cache:
210 if cache:
212 cache_key = "get_enabled_repo_integrations_%i" % event.repo.repo_id
211 cache_key = "get_enabled_repo_integrations_%i" % event.repo.repo_id
213 query = query.options(
212 query = query.options(
214 FromCache("sql_cache_short", cache_key))
213 FromCache("sql_cache_short", cache_key))
215 else: # only global integrations
214 else: # only global integrations
216 query = query.filter(global_integrations_filter)
215 query = query.filter(global_integrations_filter)
217 if cache:
216 if cache:
218 query = query.options(
217 query = query.options(
219 FromCache("sql_cache_short", "get_enabled_global_integrations"))
218 FromCache("sql_cache_short", "get_enabled_global_integrations"))
220
219
221 result = query.all()
220 result = query.all()
222 return result No newline at end of file
221 return result
General Comments 0
You need to be logged in to leave comments. Login now