##// END OF EJS Templates
integrations: fixed flash message queue.
marcink -
r424:918fa151 default
parent child Browse files
Show More
@@ -1,257 +1,258 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2016 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 colander
21 import colander
22 import logging
22 import logging
23 import pylons
23 import pylons
24
24
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
25 from pyramid.httpexceptions import HTTPFound, HTTPForbidden
26 from pyramid.renderers import render
26 from pyramid.renderers import render
27 from pyramid.response import Response
27 from pyramid.response import Response
28
28
29 from rhodecode.lib import auth
29 from rhodecode.lib import auth
30 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
30 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
31 from rhodecode.model.db import Repository, Session, Integration
31 from rhodecode.model.db import Repository, Session, Integration
32 from rhodecode.model.scm import ScmModel
32 from rhodecode.model.scm import ScmModel
33 from rhodecode.model.integration import IntegrationModel
33 from rhodecode.model.integration import IntegrationModel
34 from rhodecode.admin.navigation import navigation_list
34 from rhodecode.admin.navigation import navigation_list
35 from rhodecode.translation import _
35 from rhodecode.translation import _
36 from rhodecode.integrations import integration_type_registry
36 from rhodecode.integrations import integration_type_registry
37
37
38 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
39
39
40
40
41 class IntegrationSettingsViewBase(object):
41 class IntegrationSettingsViewBase(object):
42 """ Base Integration settings view used by both repo / global settings """
42 """ Base Integration settings view used by both repo / global settings """
43
43
44 def __init__(self, context, request):
44 def __init__(self, context, request):
45 self.context = context
45 self.context = context
46 self.request = request
46 self.request = request
47 self._load_general_context()
47 self._load_general_context()
48
48
49 if not self.perm_check(request.user):
49 if not self.perm_check(request.user):
50 raise HTTPForbidden()
50 raise HTTPForbidden()
51
51
52 def _load_general_context(self):
52 def _load_general_context(self):
53 """
53 """
54 This avoids boilerplate for repo/global+list/edit+views/templates
54 This avoids boilerplate for repo/global+list/edit+views/templates
55 by doing all possible contexts at the same time however it should
55 by doing all possible contexts at the same time however it should
56 be split up into separate functions once more "contexts" exist
56 be split up into separate functions once more "contexts" exist
57 """
57 """
58
58
59 self.IntegrationType = None
59 self.IntegrationType = None
60 self.repo = None
60 self.repo = None
61 self.integration = None
61 self.integration = None
62 self.integrations = {}
62 self.integrations = {}
63
63
64 request = self.request
64 request = self.request
65
65
66 if 'repo_name' in request.matchdict: # we're in a repo context
66 if 'repo_name' in request.matchdict: # we're in a repo context
67 repo_name = request.matchdict['repo_name']
67 repo_name = request.matchdict['repo_name']
68 self.repo = Repository.get_by_repo_name(repo_name)
68 self.repo = Repository.get_by_repo_name(repo_name)
69
69
70 if 'integration' in request.matchdict: # we're in integration context
70 if 'integration' in request.matchdict: # we're in integration context
71 integration_type = request.matchdict['integration']
71 integration_type = request.matchdict['integration']
72 self.IntegrationType = integration_type_registry[integration_type]
72 self.IntegrationType = integration_type_registry[integration_type]
73
73
74 if 'integration_id' in request.matchdict: # single integration context
74 if 'integration_id' in request.matchdict: # single integration context
75 integration_id = request.matchdict['integration_id']
75 integration_id = request.matchdict['integration_id']
76 self.integration = Integration.get(integration_id)
76 self.integration = Integration.get(integration_id)
77 else: # list integrations context
77 else: # list integrations context
78 for integration in IntegrationModel().get_integrations(self.repo):
78 for integration in IntegrationModel().get_integrations(self.repo):
79 self.integrations.setdefault(integration.integration_type, []
79 self.integrations.setdefault(integration.integration_type, []
80 ).append(integration)
80 ).append(integration)
81
81
82 self.settings = self.integration and self.integration.settings or {}
82 self.settings = self.integration and self.integration.settings or {}
83
83
84 def _template_c_context(self):
84 def _template_c_context(self):
85 # TODO: dan: this is a stopgap in order to inherit from current pylons
85 # TODO: dan: this is a stopgap in order to inherit from current pylons
86 # based admin/repo settings templates - this should be removed entirely
86 # based admin/repo settings templates - this should be removed entirely
87 # after port to pyramid
87 # after port to pyramid
88
88
89 c = pylons.tmpl_context
89 c = pylons.tmpl_context
90 c.active = 'integrations'
90 c.active = 'integrations'
91 c.rhodecode_user = self.request.user
91 c.rhodecode_user = self.request.user
92 c.repo = self.repo
92 c.repo = self.repo
93 c.repo_name = self.repo and self.repo.repo_name or None
93 c.repo_name = self.repo and self.repo.repo_name or None
94 if self.repo:
94 if self.repo:
95 c.repo_info = self.repo
95 c.repo_info = self.repo
96 c.rhodecode_db_repo = self.repo
96 c.rhodecode_db_repo = self.repo
97 c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
97 c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
98 else:
98 else:
99 c.navlist = navigation_list(self.request)
99 c.navlist = navigation_list(self.request)
100
100
101 return c
101 return c
102
102
103 def _form_schema(self):
103 def _form_schema(self):
104 return self.IntegrationType.settings_schema()
104 return self.IntegrationType.settings_schema()
105
105
106 def settings_get(self, defaults=None, errors=None):
106 def settings_get(self, defaults=None, errors=None):
107 """
107 """
108 View that displays the plugin settings as a form.
108 View that displays the plugin settings as a form.
109 """
109 """
110 defaults = defaults or {}
110 defaults = defaults or {}
111 errors = errors or {}
111 errors = errors or {}
112
112
113 schema = self._form_schema()
113 schema = self._form_schema()
114
114
115 if not defaults:
115 if not defaults:
116 if self.integration:
116 if self.integration:
117 defaults['enabled'] = self.integration.enabled
117 defaults['enabled'] = self.integration.enabled
118 defaults['name'] = self.integration.name
118 defaults['name'] = self.integration.name
119 else:
119 else:
120 if self.repo:
120 if self.repo:
121 scope = self.repo.repo_name
121 scope = self.repo.repo_name
122 else:
122 else:
123 scope = _('Global')
123 scope = _('Global')
124
124
125 defaults['name'] = '{} {} integration'.format(scope,
125 defaults['name'] = '{} {} integration'.format(scope,
126 self.IntegrationType.display_name)
126 self.IntegrationType.display_name)
127 defaults['enabled'] = True
127 defaults['enabled'] = True
128
128
129 for node in schema:
129 for node in schema:
130 setting = self.settings.get(node.name)
130 setting = self.settings.get(node.name)
131 if setting is not None:
131 if setting is not None:
132 defaults.setdefault(node.name, setting)
132 defaults.setdefault(node.name, setting)
133 else:
133 else:
134 if node.default:
134 if node.default:
135 defaults.setdefault(node.name, node.default)
135 defaults.setdefault(node.name, node.default)
136
136
137 template_context = {
137 template_context = {
138 'defaults': defaults,
138 'defaults': defaults,
139 'errors': errors,
139 'errors': errors,
140 'schema': schema,
140 'schema': schema,
141 'current_IntegrationType': self.IntegrationType,
141 'current_IntegrationType': self.IntegrationType,
142 'integration': self.integration,
142 'integration': self.integration,
143 'settings': self.settings,
143 'settings': self.settings,
144 'resource': self.context,
144 'resource': self.context,
145 'c': self._template_c_context(),
145 'c': self._template_c_context(),
146 }
146 }
147
147
148 return template_context
148 return template_context
149
149
150 @auth.CSRFRequired()
150 @auth.CSRFRequired()
151 def settings_post(self):
151 def settings_post(self):
152 """
152 """
153 View that validates and stores the plugin settings.
153 View that validates and stores the plugin settings.
154 """
154 """
155 if self.request.params.get('delete'):
155 if self.request.params.get('delete'):
156 Session().delete(self.integration)
156 Session().delete(self.integration)
157 Session().commit()
157 Session().commit()
158 self.request.session.flash(
158 self.request.session.flash(
159 _('Integration {integration_name} deleted successfully.').format(
159 _('Integration {integration_name} deleted successfully.').format(
160 integration_name=self.integration.name),
160 integration_name=self.integration.name),
161 queue='success')
161 queue='success')
162 if self.repo:
162 if self.repo:
163 redirect_to = self.request.route_url(
163 redirect_to = self.request.route_url(
164 'repo_integrations_home', repo_name=self.repo.repo_name)
164 'repo_integrations_home', repo_name=self.repo.repo_name)
165 else:
165 else:
166 redirect_to = self.request.route_url('global_integrations_home')
166 redirect_to = self.request.route_url('global_integrations_home')
167 raise HTTPFound(redirect_to)
167 raise HTTPFound(redirect_to)
168
168
169 schema = self._form_schema()
169 schema = self._form_schema()
170
170
171 params = {}
171 params = {}
172 for node in schema.children:
172 for node in schema.children:
173 if type(node.typ) in (colander.Set, colander.List):
173 if type(node.typ) in (colander.Set, colander.List):
174 val = self.request.params.getall(node.name)
174 val = self.request.params.getall(node.name)
175 else:
175 else:
176 val = self.request.params.get(node.name)
176 val = self.request.params.get(node.name)
177 if val:
177 if val:
178 params[node.name] = val
178 params[node.name] = val
179
179
180 try:
180 try:
181 valid_data = schema.deserialize(params)
181 valid_data = schema.deserialize(params)
182 except colander.Invalid, e:
182 except colander.Invalid, e:
183 # Display error message and display form again.
183 # Display error message and display form again.
184 self.request.session.flash(
184 self.request.session.flash(
185 _('Errors exist when saving plugin settings. '
185 _('Errors exist when saving plugin settings. '
186 'Please check the form inputs.'),
186 'Please check the form inputs.'),
187 queue='error')
187 queue='error')
188 return self.settings_get(errors=e.asdict(), defaults=params)
188 return self.settings_get(errors=e.asdict(), defaults=params)
189
189
190 if not self.integration:
190 if not self.integration:
191 self.integration = Integration(
191 self.integration = Integration(
192 integration_type=self.IntegrationType.key)
192 integration_type=self.IntegrationType.key)
193 if self.repo:
193 if self.repo:
194 self.integration.repo = self.repo
194 self.integration.repo = self.repo
195 Session.add(self.integration)
195 Session.add(self.integration)
196
196
197 self.integration.enabled = valid_data.pop('enabled', False)
197 self.integration.enabled = valid_data.pop('enabled', False)
198 self.integration.name = valid_data.pop('name')
198 self.integration.name = valid_data.pop('name')
199 self.integration.settings = valid_data
199 self.integration.settings = valid_data
200
200
201 Session.commit()
201 Session.commit()
202
202
203 # Display success message and redirect.
203 # Display success message and redirect.
204 self.request.session.flash(
204 self.request.session.flash(
205 _('Integration {integration_name} updated successfully.').format(
205 _('Integration {integration_name} updated successfully.').format(
206 integration_name=self.IntegrationType.display_name,
206 integration_name=self.IntegrationType.display_name),
207 queue='success'))
207 queue='success')
208
208 if self.repo:
209 if self.repo:
209 redirect_to = self.request.route_url(
210 redirect_to = self.request.route_url(
210 'repo_integrations_edit', repo_name=self.repo.repo_name,
211 'repo_integrations_edit', repo_name=self.repo.repo_name,
211 integration=self.integration.integration_type,
212 integration=self.integration.integration_type,
212 integration_id=self.integration.integration_id)
213 integration_id=self.integration.integration_id)
213 else:
214 else:
214 redirect_to = self.request.route_url(
215 redirect_to = self.request.route_url(
215 'global_integrations_edit',
216 'global_integrations_edit',
216 integration=self.integration.integration_type,
217 integration=self.integration.integration_type,
217 integration_id=self.integration.integration_id)
218 integration_id=self.integration.integration_id)
218
219
219 return HTTPFound(redirect_to)
220 return HTTPFound(redirect_to)
220
221
221 def index(self):
222 def index(self):
222 current_integrations = self.integrations
223 current_integrations = self.integrations
223 if self.IntegrationType:
224 if self.IntegrationType:
224 current_integrations = {
225 current_integrations = {
225 self.IntegrationType.key: self.integrations.get(
226 self.IntegrationType.key: self.integrations.get(
226 self.IntegrationType.key, [])
227 self.IntegrationType.key, [])
227 }
228 }
228
229
229 template_context = {
230 template_context = {
230 'current_IntegrationType': self.IntegrationType,
231 'current_IntegrationType': self.IntegrationType,
231 'current_integrations': current_integrations,
232 'current_integrations': current_integrations,
232 'current_integration': 'none',
233 'current_integration': 'none',
233 'available_integrations': integration_type_registry,
234 'available_integrations': integration_type_registry,
234 'c': self._template_c_context()
235 'c': self._template_c_context()
235 }
236 }
236
237
237 if self.repo:
238 if self.repo:
238 html = render('rhodecode:templates/admin/integrations/list.html',
239 html = render('rhodecode:templates/admin/integrations/list.html',
239 template_context,
240 template_context,
240 request=self.request)
241 request=self.request)
241 else:
242 else:
242 html = render('rhodecode:templates/admin/integrations/list.html',
243 html = render('rhodecode:templates/admin/integrations/list.html',
243 template_context,
244 template_context,
244 request=self.request)
245 request=self.request)
245
246
246 return Response(html)
247 return Response(html)
247
248
248
249
249 class GlobalIntegrationsView(IntegrationSettingsViewBase):
250 class GlobalIntegrationsView(IntegrationSettingsViewBase):
250 def perm_check(self, user):
251 def perm_check(self, user):
251 return auth.HasPermissionAll('hg.admin').check_permissions(user=user)
252 return auth.HasPermissionAll('hg.admin').check_permissions(user=user)
252
253
253
254
254 class RepoIntegrationsView(IntegrationSettingsViewBase):
255 class RepoIntegrationsView(IntegrationSettingsViewBase):
255 def perm_check(self, user):
256 def perm_check(self, user):
256 return auth.HasRepoPermissionAll('repository.admin'
257 return auth.HasRepoPermissionAll('repository.admin'
257 )(repo_name=self.repo.repo_name, user=user)
258 )(repo_name=self.repo.repo_name, user=user)
General Comments 0
You need to be logged in to leave comments. Login now