##// END OF EJS Templates
integrations: fixed missing template variable for fork reference checks.
marcink -
r3611:37100ede stable
parent child Browse files
Show More
@@ -1,316 +1,310 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 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 pyramid.view import view_config
23 from pyramid.view import view_config
24 from pyramid.httpexceptions import HTTPFound
24 from pyramid.httpexceptions import HTTPFound
25
25
26 from rhodecode import events
26 from rhodecode import events
27 from rhodecode.apps._base import RepoAppView
27 from rhodecode.apps._base import RepoAppView
28 from rhodecode.lib import helpers as h
28 from rhodecode.lib import helpers as h
29 from rhodecode.lib import audit_logger
29 from rhodecode.lib import audit_logger
30 from rhodecode.lib.auth import (
30 from rhodecode.lib.auth import (
31 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired,
31 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired,
32 HasRepoPermissionAny)
32 HasRepoPermissionAny)
33 from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
33 from rhodecode.lib.exceptions import AttachedForksError, AttachedPullRequestsError
34 from rhodecode.lib.utils2 import safe_int
34 from rhodecode.lib.utils2 import safe_int
35 from rhodecode.lib.vcs import RepositoryError
35 from rhodecode.lib.vcs import RepositoryError
36 from rhodecode.model.db import Session, UserFollowing, User, Repository
36 from rhodecode.model.db import Session, UserFollowing, User, Repository
37 from rhodecode.model.repo import RepoModel
37 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.scm import ScmModel
38 from rhodecode.model.scm import ScmModel
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42
42
43 class RepoSettingsView(RepoAppView):
43 class RepoSettingsView(RepoAppView):
44
44
45 def load_default_context(self):
45 def load_default_context(self):
46 c = self._get_local_tmpl_context()
46 c = self._get_local_tmpl_context()
47 return c
47 return c
48
48
49 def _get_users_with_permissions(self):
49 def _get_users_with_permissions(self):
50 user_permissions = {}
50 user_permissions = {}
51 for perm in self.db_repo.permissions():
51 for perm in self.db_repo.permissions():
52 user_permissions[perm.user_id] = perm
52 user_permissions[perm.user_id] = perm
53
53
54 return user_permissions
54 return user_permissions
55
55
56 @LoginRequired()
56 @LoginRequired()
57 @HasRepoPermissionAnyDecorator('repository.admin')
57 @HasRepoPermissionAnyDecorator('repository.admin')
58 @view_config(
58 @view_config(
59 route_name='edit_repo_advanced', request_method='GET',
59 route_name='edit_repo_advanced', request_method='GET',
60 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
60 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
61 def edit_advanced(self):
61 def edit_advanced(self):
62 c = self.load_default_context()
62 c = self.load_default_context()
63 c.active = 'advanced'
63 c.active = 'advanced'
64
64
65 c.default_user_id = User.get_default_user().user_id
65 c.default_user_id = User.get_default_user().user_id
66 c.in_public_journal = UserFollowing.query() \
66 c.in_public_journal = UserFollowing.query() \
67 .filter(UserFollowing.user_id == c.default_user_id) \
67 .filter(UserFollowing.user_id == c.default_user_id) \
68 .filter(UserFollowing.follows_repository == self.db_repo).scalar()
68 .filter(UserFollowing.follows_repository == self.db_repo).scalar()
69
69
70 c.has_origin_repo_read_perm = False
71 if self.db_repo.fork:
72 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
73 'repository.write', 'repository.read', 'repository.admin')(
74 self.db_repo.fork.repo_name, 'repo set as fork page')
75
76 c.ver_info_dict = self.rhodecode_vcs_repo.get_hooks_info()
70 c.ver_info_dict = self.rhodecode_vcs_repo.get_hooks_info()
77
71
78 return self._get_template_context(c)
72 return self._get_template_context(c)
79
73
80 @LoginRequired()
74 @LoginRequired()
81 @HasRepoPermissionAnyDecorator('repository.admin')
75 @HasRepoPermissionAnyDecorator('repository.admin')
82 @CSRFRequired()
76 @CSRFRequired()
83 @view_config(
77 @view_config(
84 route_name='edit_repo_advanced_archive', request_method='POST',
78 route_name='edit_repo_advanced_archive', request_method='POST',
85 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
79 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
86 def edit_advanced_archive(self):
80 def edit_advanced_archive(self):
87 """
81 """
88 Archives the repository. It will become read-only, and not visible in search
82 Archives the repository. It will become read-only, and not visible in search
89 or other queries. But still visible for super-admins.
83 or other queries. But still visible for super-admins.
90 """
84 """
91
85
92 _ = self.request.translate
86 _ = self.request.translate
93
87
94 try:
88 try:
95 old_data = self.db_repo.get_api_data()
89 old_data = self.db_repo.get_api_data()
96 RepoModel().archive(self.db_repo)
90 RepoModel().archive(self.db_repo)
97
91
98 repo = audit_logger.RepoWrap(repo_id=None, repo_name=self.db_repo.repo_name)
92 repo = audit_logger.RepoWrap(repo_id=None, repo_name=self.db_repo.repo_name)
99 audit_logger.store_web(
93 audit_logger.store_web(
100 'repo.archive', action_data={'old_data': old_data},
94 'repo.archive', action_data={'old_data': old_data},
101 user=self._rhodecode_user, repo=repo)
95 user=self._rhodecode_user, repo=repo)
102
96
103 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
97 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
104 h.flash(
98 h.flash(
105 _('Archived repository `%s`') % self.db_repo_name,
99 _('Archived repository `%s`') % self.db_repo_name,
106 category='success')
100 category='success')
107 Session().commit()
101 Session().commit()
108 except Exception:
102 except Exception:
109 log.exception("Exception during archiving of repository")
103 log.exception("Exception during archiving of repository")
110 h.flash(_('An error occurred during archiving of `%s`')
104 h.flash(_('An error occurred during archiving of `%s`')
111 % self.db_repo_name, category='error')
105 % self.db_repo_name, category='error')
112 # redirect to advanced for more deletion options
106 # redirect to advanced for more deletion options
113 raise HTTPFound(
107 raise HTTPFound(
114 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name,
108 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name,
115 _anchor='advanced-archive'))
109 _anchor='advanced-archive'))
116
110
117 # flush permissions for all users defined in permissions
111 # flush permissions for all users defined in permissions
118 affected_user_ids = self._get_users_with_permissions().keys()
112 affected_user_ids = self._get_users_with_permissions().keys()
119 events.trigger(events.UserPermissionsChange(affected_user_ids))
113 events.trigger(events.UserPermissionsChange(affected_user_ids))
120
114
121 raise HTTPFound(h.route_path('home'))
115 raise HTTPFound(h.route_path('home'))
122
116
123 @LoginRequired()
117 @LoginRequired()
124 @HasRepoPermissionAnyDecorator('repository.admin')
118 @HasRepoPermissionAnyDecorator('repository.admin')
125 @CSRFRequired()
119 @CSRFRequired()
126 @view_config(
120 @view_config(
127 route_name='edit_repo_advanced_delete', request_method='POST',
121 route_name='edit_repo_advanced_delete', request_method='POST',
128 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
122 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
129 def edit_advanced_delete(self):
123 def edit_advanced_delete(self):
130 """
124 """
131 Deletes the repository, or shows warnings if deletion is not possible
125 Deletes the repository, or shows warnings if deletion is not possible
132 because of attached forks or other errors.
126 because of attached forks or other errors.
133 """
127 """
134 _ = self.request.translate
128 _ = self.request.translate
135 handle_forks = self.request.POST.get('forks', None)
129 handle_forks = self.request.POST.get('forks', None)
136 if handle_forks == 'detach_forks':
130 if handle_forks == 'detach_forks':
137 handle_forks = 'detach'
131 handle_forks = 'detach'
138 elif handle_forks == 'delete_forks':
132 elif handle_forks == 'delete_forks':
139 handle_forks = 'delete'
133 handle_forks = 'delete'
140
134
141 try:
135 try:
142 old_data = self.db_repo.get_api_data()
136 old_data = self.db_repo.get_api_data()
143 RepoModel().delete(self.db_repo, forks=handle_forks)
137 RepoModel().delete(self.db_repo, forks=handle_forks)
144
138
145 _forks = self.db_repo.forks.count()
139 _forks = self.db_repo.forks.count()
146 if _forks and handle_forks:
140 if _forks and handle_forks:
147 if handle_forks == 'detach_forks':
141 if handle_forks == 'detach_forks':
148 h.flash(_('Detached %s forks') % _forks, category='success')
142 h.flash(_('Detached %s forks') % _forks, category='success')
149 elif handle_forks == 'delete_forks':
143 elif handle_forks == 'delete_forks':
150 h.flash(_('Deleted %s forks') % _forks, category='success')
144 h.flash(_('Deleted %s forks') % _forks, category='success')
151
145
152 repo = audit_logger.RepoWrap(repo_id=None, repo_name=self.db_repo.repo_name)
146 repo = audit_logger.RepoWrap(repo_id=None, repo_name=self.db_repo.repo_name)
153 audit_logger.store_web(
147 audit_logger.store_web(
154 'repo.delete', action_data={'old_data': old_data},
148 'repo.delete', action_data={'old_data': old_data},
155 user=self._rhodecode_user, repo=repo)
149 user=self._rhodecode_user, repo=repo)
156
150
157 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
151 ScmModel().mark_for_invalidation(self.db_repo_name, delete=True)
158 h.flash(
152 h.flash(
159 _('Deleted repository `%s`') % self.db_repo_name,
153 _('Deleted repository `%s`') % self.db_repo_name,
160 category='success')
154 category='success')
161 Session().commit()
155 Session().commit()
162 except AttachedForksError:
156 except AttachedForksError:
163 repo_advanced_url = h.route_path(
157 repo_advanced_url = h.route_path(
164 'edit_repo_advanced', repo_name=self.db_repo_name,
158 'edit_repo_advanced', repo_name=self.db_repo_name,
165 _anchor='advanced-delete')
159 _anchor='advanced-delete')
166 delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
160 delete_anchor = h.link_to(_('detach or delete'), repo_advanced_url)
167 h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
161 h.flash(_('Cannot delete `{repo}` it still contains attached forks. '
168 'Try using {delete_or_detach} option.')
162 'Try using {delete_or_detach} option.')
169 .format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
163 .format(repo=self.db_repo_name, delete_or_detach=delete_anchor),
170 category='warning')
164 category='warning')
171
165
172 # redirect to advanced for forks handle action ?
166 # redirect to advanced for forks handle action ?
173 raise HTTPFound(repo_advanced_url)
167 raise HTTPFound(repo_advanced_url)
174
168
175 except AttachedPullRequestsError:
169 except AttachedPullRequestsError:
176 repo_advanced_url = h.route_path(
170 repo_advanced_url = h.route_path(
177 'edit_repo_advanced', repo_name=self.db_repo_name,
171 'edit_repo_advanced', repo_name=self.db_repo_name,
178 _anchor='advanced-delete')
172 _anchor='advanced-delete')
179 attached_prs = len(self.db_repo.pull_requests_source +
173 attached_prs = len(self.db_repo.pull_requests_source +
180 self.db_repo.pull_requests_target)
174 self.db_repo.pull_requests_target)
181 h.flash(
175 h.flash(
182 _('Cannot delete `{repo}` it still contains {num} attached pull requests. '
176 _('Cannot delete `{repo}` it still contains {num} attached pull requests. '
183 'Consider archiving the repository instead.').format(
177 'Consider archiving the repository instead.').format(
184 repo=self.db_repo_name, num=attached_prs), category='warning')
178 repo=self.db_repo_name, num=attached_prs), category='warning')
185
179
186 # redirect to advanced for forks handle action ?
180 # redirect to advanced for forks handle action ?
187 raise HTTPFound(repo_advanced_url)
181 raise HTTPFound(repo_advanced_url)
188
182
189 except Exception:
183 except Exception:
190 log.exception("Exception during deletion of repository")
184 log.exception("Exception during deletion of repository")
191 h.flash(_('An error occurred during deletion of `%s`')
185 h.flash(_('An error occurred during deletion of `%s`')
192 % self.db_repo_name, category='error')
186 % self.db_repo_name, category='error')
193 # redirect to advanced for more deletion options
187 # redirect to advanced for more deletion options
194 raise HTTPFound(
188 raise HTTPFound(
195 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name,
189 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name,
196 _anchor='advanced-delete'))
190 _anchor='advanced-delete'))
197
191
198 raise HTTPFound(h.route_path('home'))
192 raise HTTPFound(h.route_path('home'))
199
193
200 @LoginRequired()
194 @LoginRequired()
201 @HasRepoPermissionAnyDecorator('repository.admin')
195 @HasRepoPermissionAnyDecorator('repository.admin')
202 @CSRFRequired()
196 @CSRFRequired()
203 @view_config(
197 @view_config(
204 route_name='edit_repo_advanced_journal', request_method='POST',
198 route_name='edit_repo_advanced_journal', request_method='POST',
205 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
199 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
206 def edit_advanced_journal(self):
200 def edit_advanced_journal(self):
207 """
201 """
208 Set's this repository to be visible in public journal,
202 Set's this repository to be visible in public journal,
209 in other words making default user to follow this repo
203 in other words making default user to follow this repo
210 """
204 """
211 _ = self.request.translate
205 _ = self.request.translate
212
206
213 try:
207 try:
214 user_id = User.get_default_user().user_id
208 user_id = User.get_default_user().user_id
215 ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
209 ScmModel().toggle_following_repo(self.db_repo.repo_id, user_id)
216 h.flash(_('Updated repository visibility in public journal'),
210 h.flash(_('Updated repository visibility in public journal'),
217 category='success')
211 category='success')
218 Session().commit()
212 Session().commit()
219 except Exception:
213 except Exception:
220 h.flash(_('An error occurred during setting this '
214 h.flash(_('An error occurred during setting this '
221 'repository in public journal'),
215 'repository in public journal'),
222 category='error')
216 category='error')
223
217
224 raise HTTPFound(
218 raise HTTPFound(
225 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
219 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
226
220
227 @LoginRequired()
221 @LoginRequired()
228 @HasRepoPermissionAnyDecorator('repository.admin')
222 @HasRepoPermissionAnyDecorator('repository.admin')
229 @CSRFRequired()
223 @CSRFRequired()
230 @view_config(
224 @view_config(
231 route_name='edit_repo_advanced_fork', request_method='POST',
225 route_name='edit_repo_advanced_fork', request_method='POST',
232 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
226 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
233 def edit_advanced_fork(self):
227 def edit_advanced_fork(self):
234 """
228 """
235 Mark given repository as a fork of another
229 Mark given repository as a fork of another
236 """
230 """
237 _ = self.request.translate
231 _ = self.request.translate
238
232
239 new_fork_id = safe_int(self.request.POST.get('id_fork_of'))
233 new_fork_id = safe_int(self.request.POST.get('id_fork_of'))
240
234
241 # valid repo, re-check permissions
235 # valid repo, re-check permissions
242 if new_fork_id:
236 if new_fork_id:
243 repo = Repository.get(new_fork_id)
237 repo = Repository.get(new_fork_id)
244 # ensure we have at least read access to the repo we mark
238 # ensure we have at least read access to the repo we mark
245 perm_check = HasRepoPermissionAny(
239 perm_check = HasRepoPermissionAny(
246 'repository.read', 'repository.write', 'repository.admin')
240 'repository.read', 'repository.write', 'repository.admin')
247
241
248 if repo and perm_check(repo_name=repo.repo_name):
242 if repo and perm_check(repo_name=repo.repo_name):
249 new_fork_id = repo.repo_id
243 new_fork_id = repo.repo_id
250 else:
244 else:
251 new_fork_id = None
245 new_fork_id = None
252
246
253 try:
247 try:
254 repo = ScmModel().mark_as_fork(
248 repo = ScmModel().mark_as_fork(
255 self.db_repo_name, new_fork_id, self._rhodecode_user.user_id)
249 self.db_repo_name, new_fork_id, self._rhodecode_user.user_id)
256 fork = repo.fork.repo_name if repo.fork else _('Nothing')
250 fork = repo.fork.repo_name if repo.fork else _('Nothing')
257 Session().commit()
251 Session().commit()
258 h.flash(
252 h.flash(
259 _('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
253 _('Marked repo %s as fork of %s') % (self.db_repo_name, fork),
260 category='success')
254 category='success')
261 except RepositoryError as e:
255 except RepositoryError as e:
262 log.exception("Repository Error occurred")
256 log.exception("Repository Error occurred")
263 h.flash(str(e), category='error')
257 h.flash(str(e), category='error')
264 except Exception:
258 except Exception:
265 log.exception("Exception while editing fork")
259 log.exception("Exception while editing fork")
266 h.flash(_('An error occurred during this operation'),
260 h.flash(_('An error occurred during this operation'),
267 category='error')
261 category='error')
268
262
269 raise HTTPFound(
263 raise HTTPFound(
270 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
264 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
271
265
272 @LoginRequired()
266 @LoginRequired()
273 @HasRepoPermissionAnyDecorator('repository.admin')
267 @HasRepoPermissionAnyDecorator('repository.admin')
274 @CSRFRequired()
268 @CSRFRequired()
275 @view_config(
269 @view_config(
276 route_name='edit_repo_advanced_locking', request_method='POST',
270 route_name='edit_repo_advanced_locking', request_method='POST',
277 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
271 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
278 def edit_advanced_locking(self):
272 def edit_advanced_locking(self):
279 """
273 """
280 Toggle locking of repository
274 Toggle locking of repository
281 """
275 """
282 _ = self.request.translate
276 _ = self.request.translate
283 set_lock = self.request.POST.get('set_lock')
277 set_lock = self.request.POST.get('set_lock')
284 set_unlock = self.request.POST.get('set_unlock')
278 set_unlock = self.request.POST.get('set_unlock')
285
279
286 try:
280 try:
287 if set_lock:
281 if set_lock:
288 Repository.lock(self.db_repo, self._rhodecode_user.user_id,
282 Repository.lock(self.db_repo, self._rhodecode_user.user_id,
289 lock_reason=Repository.LOCK_WEB)
283 lock_reason=Repository.LOCK_WEB)
290 h.flash(_('Locked repository'), category='success')
284 h.flash(_('Locked repository'), category='success')
291 elif set_unlock:
285 elif set_unlock:
292 Repository.unlock(self.db_repo)
286 Repository.unlock(self.db_repo)
293 h.flash(_('Unlocked repository'), category='success')
287 h.flash(_('Unlocked repository'), category='success')
294 except Exception as e:
288 except Exception as e:
295 log.exception("Exception during unlocking")
289 log.exception("Exception during unlocking")
296 h.flash(_('An error occurred during unlocking'), category='error')
290 h.flash(_('An error occurred during unlocking'), category='error')
297
291
298 raise HTTPFound(
292 raise HTTPFound(
299 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
293 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
300
294
301 @LoginRequired()
295 @LoginRequired()
302 @HasRepoPermissionAnyDecorator('repository.admin')
296 @HasRepoPermissionAnyDecorator('repository.admin')
303 @view_config(
297 @view_config(
304 route_name='edit_repo_advanced_hooks', request_method='GET',
298 route_name='edit_repo_advanced_hooks', request_method='GET',
305 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
299 renderer='rhodecode:templates/admin/repos/repo_edit.mako')
306 def edit_advanced_install_hooks(self):
300 def edit_advanced_install_hooks(self):
307 """
301 """
308 Install Hooks for repository
302 Install Hooks for repository
309 """
303 """
310 _ = self.request.translate
304 _ = self.request.translate
311 self.load_default_context()
305 self.load_default_context()
312 self.rhodecode_vcs_repo.install_hooks(force=True)
306 self.rhodecode_vcs_repo.install_hooks(force=True)
313 h.flash(_('installed updated hooks into this repository'),
307 h.flash(_('installed updated hooks into this repository'),
314 category='success')
308 category='success')
315 raise HTTPFound(
309 raise HTTPFound(
316 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
310 h.route_path('edit_repo_advanced', repo_name=self.db_repo_name))
@@ -1,459 +1,463 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2019 RhodeCode GmbH
3 # Copyright (C) 2012-2019 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 deform
21 import deform
22 import logging
22 import logging
23 import peppercorn
23 import peppercorn
24 import webhelpers.paginate
24 import webhelpers.paginate
25
25
26 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPNotFound
26 from pyramid.httpexceptions import HTTPFound, HTTPForbidden, HTTPNotFound
27
27
28 from rhodecode.integrations import integration_type_registry
28 from rhodecode.integrations import integration_type_registry
29 from rhodecode.apps._base import BaseAppView
29 from rhodecode.apps._base import BaseAppView
30 from rhodecode.apps._base.navigation import navigation_list
30 from rhodecode.apps._base.navigation import navigation_list
31 from rhodecode.lib.auth import (
31 from rhodecode.lib.auth import (
32 LoginRequired, CSRFRequired, HasPermissionAnyDecorator,
32 LoginRequired, CSRFRequired, HasPermissionAnyDecorator,
33 HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator)
33 HasRepoPermissionAnyDecorator, HasRepoGroupPermissionAnyDecorator)
34 from rhodecode.lib.utils2 import safe_int
34 from rhodecode.lib.utils2 import safe_int
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.model.db import Repository, RepoGroup, Session, Integration
36 from rhodecode.model.db import Repository, RepoGroup, Session, Integration
37 from rhodecode.model.scm import ScmModel
37 from rhodecode.model.scm import ScmModel
38 from rhodecode.model.integration import IntegrationModel
38 from rhodecode.model.integration import IntegrationModel
39 from rhodecode.model.validation_schema.schemas.integration_schema import (
39 from rhodecode.model.validation_schema.schemas.integration_schema import (
40 make_integration_schema, IntegrationScopeType)
40 make_integration_schema, IntegrationScopeType)
41
41
42 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
43
43
44
44
45 class IntegrationSettingsViewBase(BaseAppView):
45 class IntegrationSettingsViewBase(BaseAppView):
46 """
46 """
47 Base Integration settings view used by both repo / global settings
47 Base Integration settings view used by both repo / global settings
48 """
48 """
49
49
50 def __init__(self, context, request):
50 def __init__(self, context, request):
51 super(IntegrationSettingsViewBase, self).__init__(context, request)
51 super(IntegrationSettingsViewBase, self).__init__(context, request)
52 self._load_view_context()
52 self._load_view_context()
53
53
54 def _load_view_context(self):
54 def _load_view_context(self):
55 """
55 """
56 This avoids boilerplate for repo/global+list/edit+views/templates
56 This avoids boilerplate for repo/global+list/edit+views/templates
57 by doing all possible contexts at the same time however it should
57 by doing all possible contexts at the same time however it should
58 be split up into separate functions once more "contexts" exist
58 be split up into separate functions once more "contexts" exist
59 """
59 """
60
60
61 self.IntegrationType = None
61 self.IntegrationType = None
62 self.repo = None
62 self.repo = None
63 self.repo_group = None
63 self.repo_group = None
64 self.integration = None
64 self.integration = None
65 self.integrations = {}
65 self.integrations = {}
66
66
67 request = self.request
67 request = self.request
68
68
69 if 'repo_name' in request.matchdict: # in repo settings context
69 if 'repo_name' in request.matchdict: # in repo settings context
70 repo_name = request.matchdict['repo_name']
70 repo_name = request.matchdict['repo_name']
71 self.repo = Repository.get_by_repo_name(repo_name)
71 self.repo = Repository.get_by_repo_name(repo_name)
72
72
73 if 'repo_group_name' in request.matchdict: # in group settings context
73 if 'repo_group_name' in request.matchdict: # in group settings context
74 repo_group_name = request.matchdict['repo_group_name']
74 repo_group_name = request.matchdict['repo_group_name']
75 self.repo_group = RepoGroup.get_by_group_name(repo_group_name)
75 self.repo_group = RepoGroup.get_by_group_name(repo_group_name)
76
76
77 if 'integration' in request.matchdict: # integration type context
77 if 'integration' in request.matchdict: # integration type context
78 integration_type = request.matchdict['integration']
78 integration_type = request.matchdict['integration']
79 if integration_type not in integration_type_registry:
79 if integration_type not in integration_type_registry:
80 raise HTTPNotFound()
80 raise HTTPNotFound()
81
81
82 self.IntegrationType = integration_type_registry[integration_type]
82 self.IntegrationType = integration_type_registry[integration_type]
83 if self.IntegrationType.is_dummy:
83 if self.IntegrationType.is_dummy:
84 raise HTTPNotFound()
84 raise HTTPNotFound()
85
85
86 if 'integration_id' in request.matchdict: # single integration context
86 if 'integration_id' in request.matchdict: # single integration context
87 integration_id = request.matchdict['integration_id']
87 integration_id = request.matchdict['integration_id']
88 self.integration = Integration.get(integration_id)
88 self.integration = Integration.get(integration_id)
89
89
90 # extra perms check just in case
90 # extra perms check just in case
91 if not self._has_perms_for_integration(self.integration):
91 if not self._has_perms_for_integration(self.integration):
92 raise HTTPForbidden()
92 raise HTTPForbidden()
93
93
94 self.settings = self.integration and self.integration.settings or {}
94 self.settings = self.integration and self.integration.settings or {}
95 self.admin_view = not (self.repo or self.repo_group)
95 self.admin_view = not (self.repo or self.repo_group)
96
96
97 def _has_perms_for_integration(self, integration):
97 def _has_perms_for_integration(self, integration):
98 perms = self.request.user.permissions
98 perms = self.request.user.permissions
99
99
100 if 'hg.admin' in perms['global']:
100 if 'hg.admin' in perms['global']:
101 return True
101 return True
102
102
103 if integration.repo:
103 if integration.repo:
104 return perms['repositories'].get(
104 return perms['repositories'].get(
105 integration.repo.repo_name) == 'repository.admin'
105 integration.repo.repo_name) == 'repository.admin'
106
106
107 if integration.repo_group:
107 if integration.repo_group:
108 return perms['repositories_groups'].get(
108 return perms['repositories_groups'].get(
109 integration.repo_group.group_name) == 'group.admin'
109 integration.repo_group.group_name) == 'group.admin'
110
110
111 return False
111 return False
112
112
113 def _get_local_tmpl_context(self, include_app_defaults=True):
113 def _get_local_tmpl_context(self, include_app_defaults=True):
114 _ = self.request.translate
114 _ = self.request.translate
115 c = super(IntegrationSettingsViewBase, self)._get_local_tmpl_context(
115 c = super(IntegrationSettingsViewBase, self)._get_local_tmpl_context(
116 include_app_defaults=include_app_defaults)
116 include_app_defaults=include_app_defaults)
117
118 c.active = 'integrations'
117 c.active = 'integrations'
119
118
120 return c
119 return c
121
120
122 def _form_schema(self):
121 def _form_schema(self):
123 schema = make_integration_schema(IntegrationType=self.IntegrationType,
122 schema = make_integration_schema(IntegrationType=self.IntegrationType,
124 settings=self.settings)
123 settings=self.settings)
125
124
126 # returns a clone, important if mutating the schema later
125 # returns a clone, important if mutating the schema later
127 return schema.bind(
126 return schema.bind(
128 permissions=self.request.user.permissions,
127 permissions=self.request.user.permissions,
129 no_scope=not self.admin_view)
128 no_scope=not self.admin_view)
130
129
131 def _form_defaults(self):
130 def _form_defaults(self):
132 _ = self.request.translate
131 _ = self.request.translate
133 defaults = {}
132 defaults = {}
134
133
135 if self.integration:
134 if self.integration:
136 defaults['settings'] = self.integration.settings or {}
135 defaults['settings'] = self.integration.settings or {}
137 defaults['options'] = {
136 defaults['options'] = {
138 'name': self.integration.name,
137 'name': self.integration.name,
139 'enabled': self.integration.enabled,
138 'enabled': self.integration.enabled,
140 'scope': {
139 'scope': {
141 'repo': self.integration.repo,
140 'repo': self.integration.repo,
142 'repo_group': self.integration.repo_group,
141 'repo_group': self.integration.repo_group,
143 'child_repos_only': self.integration.child_repos_only,
142 'child_repos_only': self.integration.child_repos_only,
144 },
143 },
145 }
144 }
146 else:
145 else:
147 if self.repo:
146 if self.repo:
148 scope = _('{repo_name} repository').format(
147 scope = _('{repo_name} repository').format(
149 repo_name=self.repo.repo_name)
148 repo_name=self.repo.repo_name)
150 elif self.repo_group:
149 elif self.repo_group:
151 scope = _('{repo_group_name} repo group').format(
150 scope = _('{repo_group_name} repo group').format(
152 repo_group_name=self.repo_group.group_name)
151 repo_group_name=self.repo_group.group_name)
153 else:
152 else:
154 scope = _('Global')
153 scope = _('Global')
155
154
156 defaults['options'] = {
155 defaults['options'] = {
157 'enabled': True,
156 'enabled': True,
158 'name': _('{name} integration').format(
157 'name': _('{name} integration').format(
159 name=self.IntegrationType.display_name),
158 name=self.IntegrationType.display_name),
160 }
159 }
161 defaults['options']['scope'] = {
160 defaults['options']['scope'] = {
162 'repo': self.repo,
161 'repo': self.repo,
163 'repo_group': self.repo_group,
162 'repo_group': self.repo_group,
164 }
163 }
165
164
166 return defaults
165 return defaults
167
166
168 def _delete_integration(self, integration):
167 def _delete_integration(self, integration):
169 _ = self.request.translate
168 _ = self.request.translate
170 Session().delete(integration)
169 Session().delete(integration)
171 Session().commit()
170 Session().commit()
172 h.flash(
171 h.flash(
173 _('Integration {integration_name} deleted successfully.').format(
172 _('Integration {integration_name} deleted successfully.').format(
174 integration_name=integration.name),
173 integration_name=integration.name),
175 category='success')
174 category='success')
176
175
177 if self.repo:
176 if self.repo:
178 redirect_to = self.request.route_path(
177 redirect_to = self.request.route_path(
179 'repo_integrations_home', repo_name=self.repo.repo_name)
178 'repo_integrations_home', repo_name=self.repo.repo_name)
180 elif self.repo_group:
179 elif self.repo_group:
181 redirect_to = self.request.route_path(
180 redirect_to = self.request.route_path(
182 'repo_group_integrations_home',
181 'repo_group_integrations_home',
183 repo_group_name=self.repo_group.group_name)
182 repo_group_name=self.repo_group.group_name)
184 else:
183 else:
185 redirect_to = self.request.route_path('global_integrations_home')
184 redirect_to = self.request.route_path('global_integrations_home')
186 raise HTTPFound(redirect_to)
185 raise HTTPFound(redirect_to)
187
186
188 def _integration_list(self):
187 def _integration_list(self):
189 """ List integrations """
188 """ List integrations """
190
189
191 c = self.load_default_context()
190 c = self.load_default_context()
192 if self.repo:
191 if self.repo:
193 scope = self.repo
192 scope = self.repo
194 elif self.repo_group:
193 elif self.repo_group:
195 scope = self.repo_group
194 scope = self.repo_group
196 else:
195 else:
197 scope = 'all'
196 scope = 'all'
198
197
199 integrations = []
198 integrations = []
200
199
201 for IntType, integration in IntegrationModel().get_integrations(
200 for IntType, integration in IntegrationModel().get_integrations(
202 scope=scope, IntegrationType=self.IntegrationType):
201 scope=scope, IntegrationType=self.IntegrationType):
203
202
204 # extra permissions check *just in case*
203 # extra permissions check *just in case*
205 if not self._has_perms_for_integration(integration):
204 if not self._has_perms_for_integration(integration):
206 continue
205 continue
207
206
208 integrations.append((IntType, integration))
207 integrations.append((IntType, integration))
209
208
210 sort_arg = self.request.GET.get('sort', 'name:asc')
209 sort_arg = self.request.GET.get('sort', 'name:asc')
211 sort_dir = 'asc'
210 sort_dir = 'asc'
212 if ':' in sort_arg:
211 if ':' in sort_arg:
213 sort_field, sort_dir = sort_arg.split(':')
212 sort_field, sort_dir = sort_arg.split(':')
214 else:
213 else:
215 sort_field = sort_arg, 'asc'
214 sort_field = sort_arg, 'asc'
216
215
217 assert sort_field in ('name', 'integration_type', 'enabled', 'scope')
216 assert sort_field in ('name', 'integration_type', 'enabled', 'scope')
218
217
219 integrations.sort(
218 integrations.sort(
220 key=lambda x: getattr(x[1], sort_field),
219 key=lambda x: getattr(x[1], sort_field),
221 reverse=(sort_dir == 'desc'))
220 reverse=(sort_dir == 'desc'))
222
221
223 page_url = webhelpers.paginate.PageURL(
222 page_url = webhelpers.paginate.PageURL(
224 self.request.path, self.request.GET)
223 self.request.path, self.request.GET)
225 page = safe_int(self.request.GET.get('page', 1), 1)
224 page = safe_int(self.request.GET.get('page', 1), 1)
226
225
227 integrations = h.Page(
226 integrations = h.Page(
228 integrations, page=page, items_per_page=10, url=page_url)
227 integrations, page=page, items_per_page=10, url=page_url)
229
228
230 c.rev_sort_dir = sort_dir != 'desc' and 'desc' or 'asc'
229 c.rev_sort_dir = sort_dir != 'desc' and 'desc' or 'asc'
231
230
232 c.current_IntegrationType = self.IntegrationType
231 c.current_IntegrationType = self.IntegrationType
233 c.integrations_list = integrations
232 c.integrations_list = integrations
234 c.available_integrations = integration_type_registry
233 c.available_integrations = integration_type_registry
235
234
236 return self._get_template_context(c)
235 return self._get_template_context(c)
237
236
238 def _settings_get(self, defaults=None, form=None):
237 def _settings_get(self, defaults=None, form=None):
239 """
238 """
240 View that displays the integration settings as a form.
239 View that displays the integration settings as a form.
241 """
240 """
242 c = self.load_default_context()
241 c = self.load_default_context()
243
242
244 defaults = defaults or self._form_defaults()
243 defaults = defaults or self._form_defaults()
245 schema = self._form_schema()
244 schema = self._form_schema()
246
245
247 if self.integration:
246 if self.integration:
248 buttons = ('submit', 'delete')
247 buttons = ('submit', 'delete')
249 else:
248 else:
250 buttons = ('submit',)
249 buttons = ('submit',)
251
250
252 form = form or deform.Form(schema, appstruct=defaults, buttons=buttons)
251 form = form or deform.Form(schema, appstruct=defaults, buttons=buttons)
253
252
254 c.form = form
253 c.form = form
255 c.current_IntegrationType = self.IntegrationType
254 c.current_IntegrationType = self.IntegrationType
256 c.integration = self.integration
255 c.integration = self.integration
257
256
258 return self._get_template_context(c)
257 return self._get_template_context(c)
259
258
260 def _settings_post(self):
259 def _settings_post(self):
261 """
260 """
262 View that validates and stores the integration settings.
261 View that validates and stores the integration settings.
263 """
262 """
264 _ = self.request.translate
263 _ = self.request.translate
265
264
266 controls = self.request.POST.items()
265 controls = self.request.POST.items()
267 pstruct = peppercorn.parse(controls)
266 pstruct = peppercorn.parse(controls)
268
267
269 if self.integration and pstruct.get('delete'):
268 if self.integration and pstruct.get('delete'):
270 return self._delete_integration(self.integration)
269 return self._delete_integration(self.integration)
271
270
272 schema = self._form_schema()
271 schema = self._form_schema()
273
272
274 skip_settings_validation = False
273 skip_settings_validation = False
275 if self.integration and 'enabled' not in pstruct.get('options', {}):
274 if self.integration and 'enabled' not in pstruct.get('options', {}):
276 skip_settings_validation = True
275 skip_settings_validation = True
277 schema['settings'].validator = None
276 schema['settings'].validator = None
278 for field in schema['settings'].children:
277 for field in schema['settings'].children:
279 field.validator = None
278 field.validator = None
280 field.missing = ''
279 field.missing = ''
281
280
282 if self.integration:
281 if self.integration:
283 buttons = ('submit', 'delete')
282 buttons = ('submit', 'delete')
284 else:
283 else:
285 buttons = ('submit',)
284 buttons = ('submit',)
286
285
287 form = deform.Form(schema, buttons=buttons)
286 form = deform.Form(schema, buttons=buttons)
288
287
289 if not self.admin_view:
288 if not self.admin_view:
290 # scope is read only field in these cases, and has to be added
289 # scope is read only field in these cases, and has to be added
291 options = pstruct.setdefault('options', {})
290 options = pstruct.setdefault('options', {})
292 if 'scope' not in options:
291 if 'scope' not in options:
293 options['scope'] = IntegrationScopeType().serialize(None, {
292 options['scope'] = IntegrationScopeType().serialize(None, {
294 'repo': self.repo,
293 'repo': self.repo,
295 'repo_group': self.repo_group,
294 'repo_group': self.repo_group,
296 })
295 })
297
296
298 try:
297 try:
299 valid_data = form.validate_pstruct(pstruct)
298 valid_data = form.validate_pstruct(pstruct)
300 except deform.ValidationFailure as e:
299 except deform.ValidationFailure as e:
301 h.flash(
300 h.flash(
302 _('Errors exist when saving integration settings. '
301 _('Errors exist when saving integration settings. '
303 'Please check the form inputs.'),
302 'Please check the form inputs.'),
304 category='error')
303 category='error')
305 return self._settings_get(form=e)
304 return self._settings_get(form=e)
306
305
307 if not self.integration:
306 if not self.integration:
308 self.integration = Integration()
307 self.integration = Integration()
309 self.integration.integration_type = self.IntegrationType.key
308 self.integration.integration_type = self.IntegrationType.key
310 Session().add(self.integration)
309 Session().add(self.integration)
311
310
312 scope = valid_data['options']['scope']
311 scope = valid_data['options']['scope']
313
312
314 IntegrationModel().update_integration(self.integration,
313 IntegrationModel().update_integration(self.integration,
315 name=valid_data['options']['name'],
314 name=valid_data['options']['name'],
316 enabled=valid_data['options']['enabled'],
315 enabled=valid_data['options']['enabled'],
317 settings=valid_data['settings'],
316 settings=valid_data['settings'],
318 repo=scope['repo'],
317 repo=scope['repo'],
319 repo_group=scope['repo_group'],
318 repo_group=scope['repo_group'],
320 child_repos_only=scope['child_repos_only'],
319 child_repos_only=scope['child_repos_only'],
321 )
320 )
322
321
323 self.integration.settings = valid_data['settings']
322 self.integration.settings = valid_data['settings']
324 Session().commit()
323 Session().commit()
325 # Display success message and redirect.
324 # Display success message and redirect.
326 h.flash(
325 h.flash(
327 _('Integration {integration_name} updated successfully.').format(
326 _('Integration {integration_name} updated successfully.').format(
328 integration_name=self.IntegrationType.display_name),
327 integration_name=self.IntegrationType.display_name),
329 category='success')
328 category='success')
330
329
331 # if integration scope changes, we must redirect to the right place
330 # if integration scope changes, we must redirect to the right place
332 # keeping in mind if the original view was for /repo/ or /_admin/
331 # keeping in mind if the original view was for /repo/ or /_admin/
333 admin_view = not (self.repo or self.repo_group)
332 admin_view = not (self.repo or self.repo_group)
334
333
335 if self.integration.repo and not admin_view:
334 if self.integration.repo and not admin_view:
336 redirect_to = self.request.route_path(
335 redirect_to = self.request.route_path(
337 'repo_integrations_edit',
336 'repo_integrations_edit',
338 repo_name=self.integration.repo.repo_name,
337 repo_name=self.integration.repo.repo_name,
339 integration=self.integration.integration_type,
338 integration=self.integration.integration_type,
340 integration_id=self.integration.integration_id)
339 integration_id=self.integration.integration_id)
341 elif self.integration.repo_group and not admin_view:
340 elif self.integration.repo_group and not admin_view:
342 redirect_to = self.request.route_path(
341 redirect_to = self.request.route_path(
343 'repo_group_integrations_edit',
342 'repo_group_integrations_edit',
344 repo_group_name=self.integration.repo_group.group_name,
343 repo_group_name=self.integration.repo_group.group_name,
345 integration=self.integration.integration_type,
344 integration=self.integration.integration_type,
346 integration_id=self.integration.integration_id)
345 integration_id=self.integration.integration_id)
347 else:
346 else:
348 redirect_to = self.request.route_path(
347 redirect_to = self.request.route_path(
349 'global_integrations_edit',
348 'global_integrations_edit',
350 integration=self.integration.integration_type,
349 integration=self.integration.integration_type,
351 integration_id=self.integration.integration_id)
350 integration_id=self.integration.integration_id)
352
351
353 return HTTPFound(redirect_to)
352 return HTTPFound(redirect_to)
354
353
355 def _new_integration(self):
354 def _new_integration(self):
356 c = self.load_default_context()
355 c = self.load_default_context()
357 c.available_integrations = integration_type_registry
356 c.available_integrations = integration_type_registry
358 return self._get_template_context(c)
357 return self._get_template_context(c)
359
358
360 def load_default_context(self):
359 def load_default_context(self):
361 raise NotImplementedError()
360 raise NotImplementedError()
362
361
363
362
364 class GlobalIntegrationsView(IntegrationSettingsViewBase):
363 class GlobalIntegrationsView(IntegrationSettingsViewBase):
365 def load_default_context(self):
364 def load_default_context(self):
366 c = self._get_local_tmpl_context()
365 c = self._get_local_tmpl_context()
367 c.repo = self.repo
366 c.repo = self.repo
368 c.repo_group = self.repo_group
367 c.repo_group = self.repo_group
369 c.navlist = navigation_list(self.request)
368 c.navlist = navigation_list(self.request)
370
369
371 return c
370 return c
372
371
373 @LoginRequired()
372 @LoginRequired()
374 @HasPermissionAnyDecorator('hg.admin')
373 @HasPermissionAnyDecorator('hg.admin')
375 def integration_list(self):
374 def integration_list(self):
376 return self._integration_list()
375 return self._integration_list()
377
376
378 @LoginRequired()
377 @LoginRequired()
379 @HasPermissionAnyDecorator('hg.admin')
378 @HasPermissionAnyDecorator('hg.admin')
380 def settings_get(self):
379 def settings_get(self):
381 return self._settings_get()
380 return self._settings_get()
382
381
383 @LoginRequired()
382 @LoginRequired()
384 @HasPermissionAnyDecorator('hg.admin')
383 @HasPermissionAnyDecorator('hg.admin')
385 @CSRFRequired()
384 @CSRFRequired()
386 def settings_post(self):
385 def settings_post(self):
387 return self._settings_post()
386 return self._settings_post()
388
387
389 @LoginRequired()
388 @LoginRequired()
390 @HasPermissionAnyDecorator('hg.admin')
389 @HasPermissionAnyDecorator('hg.admin')
391 def new_integration(self):
390 def new_integration(self):
392 return self._new_integration()
391 return self._new_integration()
393
392
394
393
395 class RepoIntegrationsView(IntegrationSettingsViewBase):
394 class RepoIntegrationsView(IntegrationSettingsViewBase):
396 def load_default_context(self):
395 def load_default_context(self):
397 c = self._get_local_tmpl_context()
396 c = self._get_local_tmpl_context()
398
397
399 c.repo = self.repo
398 c.repo = self.repo
400 c.repo_group = self.repo_group
399 c.repo_group = self.repo_group
401
400
402 self.db_repo = self.repo
401 self.db_repo = self.repo
403 c.rhodecode_db_repo = self.repo
402 c.rhodecode_db_repo = self.repo
404 c.repo_name = self.db_repo.repo_name
403 c.repo_name = self.db_repo.repo_name
405 c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
404 c.repository_pull_requests = ScmModel().get_pull_requests(self.repo)
406
405
406 c.has_origin_repo_read_perm = False
407 if self.db_repo.fork:
408 c.has_origin_repo_read_perm = h.HasRepoPermissionAny(
409 'repository.write', 'repository.read', 'repository.admin')(
410 self.db_repo.fork.repo_name, 'summary fork link')
407 return c
411 return c
408
412
409 @LoginRequired()
413 @LoginRequired()
410 @HasRepoPermissionAnyDecorator('repository.admin')
414 @HasRepoPermissionAnyDecorator('repository.admin')
411 def integration_list(self):
415 def integration_list(self):
412 return self._integration_list()
416 return self._integration_list()
413
417
414 @LoginRequired()
418 @LoginRequired()
415 @HasRepoPermissionAnyDecorator('repository.admin')
419 @HasRepoPermissionAnyDecorator('repository.admin')
416 def settings_get(self):
420 def settings_get(self):
417 return self._settings_get()
421 return self._settings_get()
418
422
419 @LoginRequired()
423 @LoginRequired()
420 @HasRepoPermissionAnyDecorator('repository.admin')
424 @HasRepoPermissionAnyDecorator('repository.admin')
421 @CSRFRequired()
425 @CSRFRequired()
422 def settings_post(self):
426 def settings_post(self):
423 return self._settings_post()
427 return self._settings_post()
424
428
425 @LoginRequired()
429 @LoginRequired()
426 @HasRepoPermissionAnyDecorator('repository.admin')
430 @HasRepoPermissionAnyDecorator('repository.admin')
427 def new_integration(self):
431 def new_integration(self):
428 return self._new_integration()
432 return self._new_integration()
429
433
430
434
431 class RepoGroupIntegrationsView(IntegrationSettingsViewBase):
435 class RepoGroupIntegrationsView(IntegrationSettingsViewBase):
432 def load_default_context(self):
436 def load_default_context(self):
433 c = self._get_local_tmpl_context()
437 c = self._get_local_tmpl_context()
434 c.repo = self.repo
438 c.repo = self.repo
435 c.repo_group = self.repo_group
439 c.repo_group = self.repo_group
436 c.navlist = navigation_list(self.request)
440 c.navlist = navigation_list(self.request)
437
441
438 return c
442 return c
439
443
440 @LoginRequired()
444 @LoginRequired()
441 @HasRepoGroupPermissionAnyDecorator('group.admin')
445 @HasRepoGroupPermissionAnyDecorator('group.admin')
442 def integration_list(self):
446 def integration_list(self):
443 return self._integration_list()
447 return self._integration_list()
444
448
445 @LoginRequired()
449 @LoginRequired()
446 @HasRepoGroupPermissionAnyDecorator('group.admin')
450 @HasRepoGroupPermissionAnyDecorator('group.admin')
447 def settings_get(self):
451 def settings_get(self):
448 return self._settings_get()
452 return self._settings_get()
449
453
450 @LoginRequired()
454 @LoginRequired()
451 @HasRepoGroupPermissionAnyDecorator('group.admin')
455 @HasRepoGroupPermissionAnyDecorator('group.admin')
452 @CSRFRequired()
456 @CSRFRequired()
453 def settings_post(self):
457 def settings_post(self):
454 return self._settings_post()
458 return self._settings_post()
455
459
456 @LoginRequired()
460 @LoginRequired()
457 @HasRepoGroupPermissionAnyDecorator('group.admin')
461 @HasRepoGroupPermissionAnyDecorator('group.admin')
458 def new_integration(self):
462 def new_integration(self):
459 return self._new_integration()
463 return self._new_integration()
General Comments 0
You need to be logged in to leave comments. Login now