##// END OF EJS Templates
git-lfs: settings for GIT repos to enable git-lfs and set store location...
marcink -
r1570:f2271c3d default
parent child Browse files
Show More
@@ -1,692 +1,694 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 settings controller for rhodecode admin
23 settings controller for rhodecode admin
24 """
24 """
25
25
26 import collections
26 import collections
27 import logging
27 import logging
28
28
29 import datetime
29 import datetime
30 import formencode
30 import formencode
31 from formencode import htmlfill
31 from formencode import htmlfill
32 from pylons import request, tmpl_context as c, url, config
32 from pylons import request, tmpl_context as c, url, config
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from pylons.i18n.translation import _
34 from pylons.i18n.translation import _
35 from pyramid.threadlocal import get_current_registry
35 from pyramid.threadlocal import get_current_registry
36 from webob.exc import HTTPBadRequest
36 from webob.exc import HTTPBadRequest
37
37
38 import rhodecode
38 import rhodecode
39 from rhodecode.apps.admin.navigation import navigation_list
39 from rhodecode.apps.admin.navigation import navigation_list
40 from rhodecode.apps.svn_support.config_keys import generate_config
40 from rhodecode.apps.svn_support.config_keys import generate_config
41 from rhodecode.lib import auth
41 from rhodecode.lib import auth
42 from rhodecode.lib import helpers as h
42 from rhodecode.lib import helpers as h
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
43 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
44 from rhodecode.lib.base import BaseController, render
44 from rhodecode.lib.base import BaseController, render
45 from rhodecode.lib.celerylib import tasks, run_task
45 from rhodecode.lib.celerylib import tasks, run_task
46 from rhodecode.lib.utils import repo2db_mapper
46 from rhodecode.lib.utils import repo2db_mapper
47 from rhodecode.lib.utils2 import (
47 from rhodecode.lib.utils2 import (
48 str2bool, safe_unicode, AttributeDict, safe_int)
48 str2bool, safe_unicode, AttributeDict, safe_int)
49 from rhodecode.lib.compat import OrderedDict
49 from rhodecode.lib.compat import OrderedDict
50 from rhodecode.lib.utils import jsonify
50 from rhodecode.lib.utils import jsonify
51
51
52 from rhodecode.model.db import RhodeCodeUi, Repository
52 from rhodecode.model.db import RhodeCodeUi, Repository
53 from rhodecode.model.forms import ApplicationSettingsForm, \
53 from rhodecode.model.forms import ApplicationSettingsForm, \
54 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
54 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
55 LabsSettingsForm, IssueTrackerPatternsForm
55 LabsSettingsForm, IssueTrackerPatternsForm
56 from rhodecode.model.repo_group import RepoGroupModel
56 from rhodecode.model.repo_group import RepoGroupModel
57
57
58 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.scm import ScmModel
59 from rhodecode.model.notification import EmailNotificationModel
59 from rhodecode.model.notification import EmailNotificationModel
60 from rhodecode.model.meta import Session
60 from rhodecode.model.meta import Session
61 from rhodecode.model.settings import (
61 from rhodecode.model.settings import (
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
62 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
63 SettingsModel)
63 SettingsModel)
64
64
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
65 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
66
66
67
67
68 log = logging.getLogger(__name__)
68 log = logging.getLogger(__name__)
69
69
70
70
71 class SettingsController(BaseController):
71 class SettingsController(BaseController):
72 """REST Controller styled on the Atom Publishing Protocol"""
72 """REST Controller styled on the Atom Publishing Protocol"""
73 # To properly map this controller, ensure your config/routing.py
73 # To properly map this controller, ensure your config/routing.py
74 # file has a resource setup:
74 # file has a resource setup:
75 # map.resource('setting', 'settings', controller='admin/settings',
75 # map.resource('setting', 'settings', controller='admin/settings',
76 # path_prefix='/admin', name_prefix='admin_')
76 # path_prefix='/admin', name_prefix='admin_')
77
77
78 @LoginRequired()
78 @LoginRequired()
79 def __before__(self):
79 def __before__(self):
80 super(SettingsController, self).__before__()
80 super(SettingsController, self).__before__()
81 c.labs_active = str2bool(
81 c.labs_active = str2bool(
82 rhodecode.CONFIG.get('labs_settings_active', 'true'))
82 rhodecode.CONFIG.get('labs_settings_active', 'true'))
83 c.navlist = navigation_list(request)
83 c.navlist = navigation_list(request)
84
84
85 def _get_hg_ui_settings(self):
85 def _get_ui_settings(self):
86 ret = RhodeCodeUi.query().all()
86 ret = RhodeCodeUi.query().all()
87
87
88 if not ret:
88 if not ret:
89 raise Exception('Could not get application ui settings !')
89 raise Exception('Could not get application ui settings !')
90 settings = {}
90 settings = {}
91 for each in ret:
91 for each in ret:
92 k = each.ui_key
92 k = each.ui_key
93 v = each.ui_value
93 v = each.ui_value
94 if k == '/':
94 if k == '/':
95 k = 'root_path'
95 k = 'root_path'
96
96
97 if k in ['push_ssl', 'publish']:
97 if k in ['push_ssl', 'publish', 'enabled']:
98 v = str2bool(v)
98 v = str2bool(v)
99
99
100 if k.find('.') != -1:
100 if k.find('.') != -1:
101 k = k.replace('.', '_')
101 k = k.replace('.', '_')
102
102
103 if each.ui_section in ['hooks', 'extensions']:
103 if each.ui_section in ['hooks', 'extensions']:
104 v = each.ui_active
104 v = each.ui_active
105
105
106 settings[each.ui_section + '_' + k] = v
106 settings[each.ui_section + '_' + k] = v
107 return settings
107 return settings
108
108
109 @HasPermissionAllDecorator('hg.admin')
109 @HasPermissionAllDecorator('hg.admin')
110 @auth.CSRFRequired()
110 @auth.CSRFRequired()
111 @jsonify
111 @jsonify
112 def delete_svn_pattern(self):
112 def delete_svn_pattern(self):
113 if not request.is_xhr:
113 if not request.is_xhr:
114 raise HTTPBadRequest()
114 raise HTTPBadRequest()
115
115
116 delete_pattern_id = request.POST.get('delete_svn_pattern')
116 delete_pattern_id = request.POST.get('delete_svn_pattern')
117 model = VcsSettingsModel()
117 model = VcsSettingsModel()
118 try:
118 try:
119 model.delete_global_svn_pattern(delete_pattern_id)
119 model.delete_global_svn_pattern(delete_pattern_id)
120 except SettingNotFound:
120 except SettingNotFound:
121 raise HTTPBadRequest()
121 raise HTTPBadRequest()
122
122
123 Session().commit()
123 Session().commit()
124 return True
124 return True
125
125
126 @HasPermissionAllDecorator('hg.admin')
126 @HasPermissionAllDecorator('hg.admin')
127 @auth.CSRFRequired()
127 @auth.CSRFRequired()
128 def settings_vcs_update(self):
128 def settings_vcs_update(self):
129 """POST /admin/settings: All items in the collection"""
129 """POST /admin/settings: All items in the collection"""
130 # url('admin_settings_vcs')
130 # url('admin_settings_vcs')
131 c.active = 'vcs'
131 c.active = 'vcs'
132
132
133 model = VcsSettingsModel()
133 model = VcsSettingsModel()
134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
136
136
137 # TODO: Replace with request.registry after migrating to pyramid.
137 # TODO: Replace with request.registry after migrating to pyramid.
138 pyramid_settings = get_current_registry().settings
138 pyramid_settings = get_current_registry().settings
139 c.svn_proxy_generate_config = pyramid_settings[generate_config]
139 c.svn_proxy_generate_config = pyramid_settings[generate_config]
140
140
141 application_form = ApplicationUiSettingsForm()()
141 application_form = ApplicationUiSettingsForm()()
142
142
143 try:
143 try:
144 form_result = application_form.to_python(dict(request.POST))
144 form_result = application_form.to_python(dict(request.POST))
145 except formencode.Invalid as errors:
145 except formencode.Invalid as errors:
146 h.flash(
146 h.flash(
147 _("Some form inputs contain invalid data."),
147 _("Some form inputs contain invalid data."),
148 category='error')
148 category='error')
149 return htmlfill.render(
149 return htmlfill.render(
150 render('admin/settings/settings.mako'),
150 render('admin/settings/settings.mako'),
151 defaults=errors.value,
151 defaults=errors.value,
152 errors=errors.error_dict or {},
152 errors=errors.error_dict or {},
153 prefix_error=False,
153 prefix_error=False,
154 encoding="UTF-8",
154 encoding="UTF-8",
155 force_defaults=False
155 force_defaults=False
156 )
156 )
157
157
158 try:
158 try:
159 if c.visual.allow_repo_location_change:
159 if c.visual.allow_repo_location_change:
160 model.update_global_path_setting(
160 model.update_global_path_setting(
161 form_result['paths_root_path'])
161 form_result['paths_root_path'])
162
162
163 model.update_global_ssl_setting(form_result['web_push_ssl'])
163 model.update_global_ssl_setting(form_result['web_push_ssl'])
164 model.update_global_hook_settings(form_result)
164 model.update_global_hook_settings(form_result)
165
165
166 model.create_or_update_global_svn_settings(form_result)
166 model.create_or_update_global_svn_settings(form_result)
167 model.create_or_update_global_hg_settings(form_result)
167 model.create_or_update_global_hg_settings(form_result)
168 model.create_or_update_global_git_settings(form_result)
168 model.create_or_update_global_pr_settings(form_result)
169 model.create_or_update_global_pr_settings(form_result)
169 except Exception:
170 except Exception:
170 log.exception("Exception while updating settings")
171 log.exception("Exception while updating settings")
171 h.flash(_('Error occurred during updating '
172 h.flash(_('Error occurred during updating '
172 'application settings'), category='error')
173 'application settings'), category='error')
173 else:
174 else:
174 Session().commit()
175 Session().commit()
175 h.flash(_('Updated VCS settings'), category='success')
176 h.flash(_('Updated VCS settings'), category='success')
176 return redirect(url('admin_settings_vcs'))
177 return redirect(url('admin_settings_vcs'))
177
178
178 return htmlfill.render(
179 return htmlfill.render(
179 render('admin/settings/settings.mako'),
180 render('admin/settings/settings.mako'),
180 defaults=self._form_defaults(),
181 defaults=self._form_defaults(),
181 encoding="UTF-8",
182 encoding="UTF-8",
182 force_defaults=False)
183 force_defaults=False)
183
184
184 @HasPermissionAllDecorator('hg.admin')
185 @HasPermissionAllDecorator('hg.admin')
185 def settings_vcs(self):
186 def settings_vcs(self):
186 """GET /admin/settings: All items in the collection"""
187 """GET /admin/settings: All items in the collection"""
187 # url('admin_settings_vcs')
188 # url('admin_settings_vcs')
188 c.active = 'vcs'
189 c.active = 'vcs'
189 model = VcsSettingsModel()
190 model = VcsSettingsModel()
190 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
191 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
191 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
192 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
192
193
193 # TODO: Replace with request.registry after migrating to pyramid.
194 # TODO: Replace with request.registry after migrating to pyramid.
194 pyramid_settings = get_current_registry().settings
195 pyramid_settings = get_current_registry().settings
195 c.svn_proxy_generate_config = pyramid_settings[generate_config]
196 c.svn_proxy_generate_config = pyramid_settings[generate_config]
196
197
197 return htmlfill.render(
198 return htmlfill.render(
198 render('admin/settings/settings.mako'),
199 render('admin/settings/settings.mako'),
199 defaults=self._form_defaults(),
200 defaults=self._form_defaults(),
200 encoding="UTF-8",
201 encoding="UTF-8",
201 force_defaults=False)
202 force_defaults=False)
202
203
203 @HasPermissionAllDecorator('hg.admin')
204 @HasPermissionAllDecorator('hg.admin')
204 @auth.CSRFRequired()
205 @auth.CSRFRequired()
205 def settings_mapping_update(self):
206 def settings_mapping_update(self):
206 """POST /admin/settings/mapping: All items in the collection"""
207 """POST /admin/settings/mapping: All items in the collection"""
207 # url('admin_settings_mapping')
208 # url('admin_settings_mapping')
208 c.active = 'mapping'
209 c.active = 'mapping'
209 rm_obsolete = request.POST.get('destroy', False)
210 rm_obsolete = request.POST.get('destroy', False)
210 invalidate_cache = request.POST.get('invalidate', False)
211 invalidate_cache = request.POST.get('invalidate', False)
211 log.debug(
212 log.debug(
212 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
213 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
213
214
214 if invalidate_cache:
215 if invalidate_cache:
215 log.debug('invalidating all repositories cache')
216 log.debug('invalidating all repositories cache')
216 for repo in Repository.get_all():
217 for repo in Repository.get_all():
217 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
218 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
218
219
219 filesystem_repos = ScmModel().repo_scan()
220 filesystem_repos = ScmModel().repo_scan()
220 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
221 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
221 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
222 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
222 h.flash(_('Repositories successfully '
223 h.flash(_('Repositories successfully '
223 'rescanned added: %s ; removed: %s') %
224 'rescanned added: %s ; removed: %s') %
224 (_repr(added), _repr(removed)),
225 (_repr(added), _repr(removed)),
225 category='success')
226 category='success')
226 return redirect(url('admin_settings_mapping'))
227 return redirect(url('admin_settings_mapping'))
227
228
228 @HasPermissionAllDecorator('hg.admin')
229 @HasPermissionAllDecorator('hg.admin')
229 def settings_mapping(self):
230 def settings_mapping(self):
230 """GET /admin/settings/mapping: All items in the collection"""
231 """GET /admin/settings/mapping: All items in the collection"""
231 # url('admin_settings_mapping')
232 # url('admin_settings_mapping')
232 c.active = 'mapping'
233 c.active = 'mapping'
233
234
234 return htmlfill.render(
235 return htmlfill.render(
235 render('admin/settings/settings.mako'),
236 render('admin/settings/settings.mako'),
236 defaults=self._form_defaults(),
237 defaults=self._form_defaults(),
237 encoding="UTF-8",
238 encoding="UTF-8",
238 force_defaults=False)
239 force_defaults=False)
239
240
240 @HasPermissionAllDecorator('hg.admin')
241 @HasPermissionAllDecorator('hg.admin')
241 @auth.CSRFRequired()
242 @auth.CSRFRequired()
242 def settings_global_update(self):
243 def settings_global_update(self):
243 """POST /admin/settings/global: All items in the collection"""
244 """POST /admin/settings/global: All items in the collection"""
244 # url('admin_settings_global')
245 # url('admin_settings_global')
245 c.active = 'global'
246 c.active = 'global'
246 c.personal_repo_group_default_pattern = RepoGroupModel()\
247 c.personal_repo_group_default_pattern = RepoGroupModel()\
247 .get_personal_group_name_pattern()
248 .get_personal_group_name_pattern()
248 application_form = ApplicationSettingsForm()()
249 application_form = ApplicationSettingsForm()()
249 try:
250 try:
250 form_result = application_form.to_python(dict(request.POST))
251 form_result = application_form.to_python(dict(request.POST))
251 except formencode.Invalid as errors:
252 except formencode.Invalid as errors:
252 return htmlfill.render(
253 return htmlfill.render(
253 render('admin/settings/settings.mako'),
254 render('admin/settings/settings.mako'),
254 defaults=errors.value,
255 defaults=errors.value,
255 errors=errors.error_dict or {},
256 errors=errors.error_dict or {},
256 prefix_error=False,
257 prefix_error=False,
257 encoding="UTF-8",
258 encoding="UTF-8",
258 force_defaults=False)
259 force_defaults=False)
259
260
260 try:
261 try:
261 settings = [
262 settings = [
262 ('title', 'rhodecode_title', 'unicode'),
263 ('title', 'rhodecode_title', 'unicode'),
263 ('realm', 'rhodecode_realm', 'unicode'),
264 ('realm', 'rhodecode_realm', 'unicode'),
264 ('pre_code', 'rhodecode_pre_code', 'unicode'),
265 ('pre_code', 'rhodecode_pre_code', 'unicode'),
265 ('post_code', 'rhodecode_post_code', 'unicode'),
266 ('post_code', 'rhodecode_post_code', 'unicode'),
266 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
267 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
267 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
268 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
268 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
269 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
269 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
270 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
270 ]
271 ]
271 for setting, form_key, type_ in settings:
272 for setting, form_key, type_ in settings:
272 sett = SettingsModel().create_or_update_setting(
273 sett = SettingsModel().create_or_update_setting(
273 setting, form_result[form_key], type_)
274 setting, form_result[form_key], type_)
274 Session().add(sett)
275 Session().add(sett)
275
276
276 Session().commit()
277 Session().commit()
277 SettingsModel().invalidate_settings_cache()
278 SettingsModel().invalidate_settings_cache()
278 h.flash(_('Updated application settings'), category='success')
279 h.flash(_('Updated application settings'), category='success')
279 except Exception:
280 except Exception:
280 log.exception("Exception while updating application settings")
281 log.exception("Exception while updating application settings")
281 h.flash(
282 h.flash(
282 _('Error occurred during updating application settings'),
283 _('Error occurred during updating application settings'),
283 category='error')
284 category='error')
284
285
285 return redirect(url('admin_settings_global'))
286 return redirect(url('admin_settings_global'))
286
287
287 @HasPermissionAllDecorator('hg.admin')
288 @HasPermissionAllDecorator('hg.admin')
288 def settings_global(self):
289 def settings_global(self):
289 """GET /admin/settings/global: All items in the collection"""
290 """GET /admin/settings/global: All items in the collection"""
290 # url('admin_settings_global')
291 # url('admin_settings_global')
291 c.active = 'global'
292 c.active = 'global'
292 c.personal_repo_group_default_pattern = RepoGroupModel()\
293 c.personal_repo_group_default_pattern = RepoGroupModel()\
293 .get_personal_group_name_pattern()
294 .get_personal_group_name_pattern()
294
295
295 return htmlfill.render(
296 return htmlfill.render(
296 render('admin/settings/settings.mako'),
297 render('admin/settings/settings.mako'),
297 defaults=self._form_defaults(),
298 defaults=self._form_defaults(),
298 encoding="UTF-8",
299 encoding="UTF-8",
299 force_defaults=False)
300 force_defaults=False)
300
301
301 @HasPermissionAllDecorator('hg.admin')
302 @HasPermissionAllDecorator('hg.admin')
302 @auth.CSRFRequired()
303 @auth.CSRFRequired()
303 def settings_visual_update(self):
304 def settings_visual_update(self):
304 """POST /admin/settings/visual: All items in the collection"""
305 """POST /admin/settings/visual: All items in the collection"""
305 # url('admin_settings_visual')
306 # url('admin_settings_visual')
306 c.active = 'visual'
307 c.active = 'visual'
307 application_form = ApplicationVisualisationForm()()
308 application_form = ApplicationVisualisationForm()()
308 try:
309 try:
309 form_result = application_form.to_python(dict(request.POST))
310 form_result = application_form.to_python(dict(request.POST))
310 except formencode.Invalid as errors:
311 except formencode.Invalid as errors:
311 return htmlfill.render(
312 return htmlfill.render(
312 render('admin/settings/settings.mako'),
313 render('admin/settings/settings.mako'),
313 defaults=errors.value,
314 defaults=errors.value,
314 errors=errors.error_dict or {},
315 errors=errors.error_dict or {},
315 prefix_error=False,
316 prefix_error=False,
316 encoding="UTF-8",
317 encoding="UTF-8",
317 force_defaults=False
318 force_defaults=False
318 )
319 )
319
320
320 try:
321 try:
321 settings = [
322 settings = [
322 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
323 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
323 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
324 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
324 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
325 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
325 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
326 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
326 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
327 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
327 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
328 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
328 ('show_version', 'rhodecode_show_version', 'bool'),
329 ('show_version', 'rhodecode_show_version', 'bool'),
329 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
330 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
330 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
331 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
331 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
332 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
332 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
333 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
333 ('support_url', 'rhodecode_support_url', 'unicode'),
334 ('support_url', 'rhodecode_support_url', 'unicode'),
334 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
335 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
335 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
336 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
336 ]
337 ]
337 for setting, form_key, type_ in settings:
338 for setting, form_key, type_ in settings:
338 sett = SettingsModel().create_or_update_setting(
339 sett = SettingsModel().create_or_update_setting(
339 setting, form_result[form_key], type_)
340 setting, form_result[form_key], type_)
340 Session().add(sett)
341 Session().add(sett)
341
342
342 Session().commit()
343 Session().commit()
343 SettingsModel().invalidate_settings_cache()
344 SettingsModel().invalidate_settings_cache()
344 h.flash(_('Updated visualisation settings'), category='success')
345 h.flash(_('Updated visualisation settings'), category='success')
345 except Exception:
346 except Exception:
346 log.exception("Exception updating visualization settings")
347 log.exception("Exception updating visualization settings")
347 h.flash(_('Error occurred during updating '
348 h.flash(_('Error occurred during updating '
348 'visualisation settings'),
349 'visualisation settings'),
349 category='error')
350 category='error')
350
351
351 return redirect(url('admin_settings_visual'))
352 return redirect(url('admin_settings_visual'))
352
353
353 @HasPermissionAllDecorator('hg.admin')
354 @HasPermissionAllDecorator('hg.admin')
354 def settings_visual(self):
355 def settings_visual(self):
355 """GET /admin/settings/visual: All items in the collection"""
356 """GET /admin/settings/visual: All items in the collection"""
356 # url('admin_settings_visual')
357 # url('admin_settings_visual')
357 c.active = 'visual'
358 c.active = 'visual'
358
359
359 return htmlfill.render(
360 return htmlfill.render(
360 render('admin/settings/settings.mako'),
361 render('admin/settings/settings.mako'),
361 defaults=self._form_defaults(),
362 defaults=self._form_defaults(),
362 encoding="UTF-8",
363 encoding="UTF-8",
363 force_defaults=False)
364 force_defaults=False)
364
365
365 @HasPermissionAllDecorator('hg.admin')
366 @HasPermissionAllDecorator('hg.admin')
366 @auth.CSRFRequired()
367 @auth.CSRFRequired()
367 def settings_issuetracker_test(self):
368 def settings_issuetracker_test(self):
368 if request.is_xhr:
369 if request.is_xhr:
369 return h.urlify_commit_message(
370 return h.urlify_commit_message(
370 request.POST.get('test_text', ''),
371 request.POST.get('test_text', ''),
371 'repo_group/test_repo1')
372 'repo_group/test_repo1')
372 else:
373 else:
373 raise HTTPBadRequest()
374 raise HTTPBadRequest()
374
375
375 @HasPermissionAllDecorator('hg.admin')
376 @HasPermissionAllDecorator('hg.admin')
376 @auth.CSRFRequired()
377 @auth.CSRFRequired()
377 def settings_issuetracker_delete(self):
378 def settings_issuetracker_delete(self):
378 uid = request.POST.get('uid')
379 uid = request.POST.get('uid')
379 IssueTrackerSettingsModel().delete_entries(uid)
380 IssueTrackerSettingsModel().delete_entries(uid)
380 h.flash(_('Removed issue tracker entry'), category='success')
381 h.flash(_('Removed issue tracker entry'), category='success')
381 return redirect(url('admin_settings_issuetracker'))
382 return redirect(url('admin_settings_issuetracker'))
382
383
383 @HasPermissionAllDecorator('hg.admin')
384 @HasPermissionAllDecorator('hg.admin')
384 def settings_issuetracker(self):
385 def settings_issuetracker(self):
385 """GET /admin/settings/issue-tracker: All items in the collection"""
386 """GET /admin/settings/issue-tracker: All items in the collection"""
386 # url('admin_settings_issuetracker')
387 # url('admin_settings_issuetracker')
387 c.active = 'issuetracker'
388 c.active = 'issuetracker'
388 defaults = SettingsModel().get_all_settings()
389 defaults = SettingsModel().get_all_settings()
389
390
390 entry_key = 'rhodecode_issuetracker_pat_'
391 entry_key = 'rhodecode_issuetracker_pat_'
391
392
392 c.issuetracker_entries = {}
393 c.issuetracker_entries = {}
393 for k, v in defaults.items():
394 for k, v in defaults.items():
394 if k.startswith(entry_key):
395 if k.startswith(entry_key):
395 uid = k[len(entry_key):]
396 uid = k[len(entry_key):]
396 c.issuetracker_entries[uid] = None
397 c.issuetracker_entries[uid] = None
397
398
398 for uid in c.issuetracker_entries:
399 for uid in c.issuetracker_entries:
399 c.issuetracker_entries[uid] = AttributeDict({
400 c.issuetracker_entries[uid] = AttributeDict({
400 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
401 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
401 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
402 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
402 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
403 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
403 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
404 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
404 })
405 })
405
406
406 return render('admin/settings/settings.mako')
407 return render('admin/settings/settings.mako')
407
408
408 @HasPermissionAllDecorator('hg.admin')
409 @HasPermissionAllDecorator('hg.admin')
409 @auth.CSRFRequired()
410 @auth.CSRFRequired()
410 def settings_issuetracker_save(self):
411 def settings_issuetracker_save(self):
411 settings_model = IssueTrackerSettingsModel()
412 settings_model = IssueTrackerSettingsModel()
412
413
413 form = IssueTrackerPatternsForm()().to_python(request.POST)
414 form = IssueTrackerPatternsForm()().to_python(request.POST)
414 if form:
415 if form:
415 for uid in form.get('delete_patterns', []):
416 for uid in form.get('delete_patterns', []):
416 settings_model.delete_entries(uid)
417 settings_model.delete_entries(uid)
417
418
418 for pattern in form.get('patterns', []):
419 for pattern in form.get('patterns', []):
419 for setting, value, type_ in pattern:
420 for setting, value, type_ in pattern:
420 sett = settings_model.create_or_update_setting(
421 sett = settings_model.create_or_update_setting(
421 setting, value, type_)
422 setting, value, type_)
422 Session().add(sett)
423 Session().add(sett)
423
424
424 Session().commit()
425 Session().commit()
425
426
426 SettingsModel().invalidate_settings_cache()
427 SettingsModel().invalidate_settings_cache()
427 h.flash(_('Updated issue tracker entries'), category='success')
428 h.flash(_('Updated issue tracker entries'), category='success')
428 return redirect(url('admin_settings_issuetracker'))
429 return redirect(url('admin_settings_issuetracker'))
429
430
430 @HasPermissionAllDecorator('hg.admin')
431 @HasPermissionAllDecorator('hg.admin')
431 @auth.CSRFRequired()
432 @auth.CSRFRequired()
432 def settings_email_update(self):
433 def settings_email_update(self):
433 """POST /admin/settings/email: All items in the collection"""
434 """POST /admin/settings/email: All items in the collection"""
434 # url('admin_settings_email')
435 # url('admin_settings_email')
435 c.active = 'email'
436 c.active = 'email'
436
437
437 test_email = request.POST.get('test_email')
438 test_email = request.POST.get('test_email')
438
439
439 if not test_email:
440 if not test_email:
440 h.flash(_('Please enter email address'), category='error')
441 h.flash(_('Please enter email address'), category='error')
441 return redirect(url('admin_settings_email'))
442 return redirect(url('admin_settings_email'))
442
443
443 email_kwargs = {
444 email_kwargs = {
444 'date': datetime.datetime.now(),
445 'date': datetime.datetime.now(),
445 'user': c.rhodecode_user,
446 'user': c.rhodecode_user,
446 'rhodecode_version': c.rhodecode_version
447 'rhodecode_version': c.rhodecode_version
447 }
448 }
448
449
449 (subject, headers, email_body,
450 (subject, headers, email_body,
450 email_body_plaintext) = EmailNotificationModel().render_email(
451 email_body_plaintext) = EmailNotificationModel().render_email(
451 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
452 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
452
453
453 recipients = [test_email] if test_email else None
454 recipients = [test_email] if test_email else None
454
455
455 run_task(tasks.send_email, recipients, subject,
456 run_task(tasks.send_email, recipients, subject,
456 email_body_plaintext, email_body)
457 email_body_plaintext, email_body)
457
458
458 h.flash(_('Send email task created'), category='success')
459 h.flash(_('Send email task created'), category='success')
459 return redirect(url('admin_settings_email'))
460 return redirect(url('admin_settings_email'))
460
461
461 @HasPermissionAllDecorator('hg.admin')
462 @HasPermissionAllDecorator('hg.admin')
462 def settings_email(self):
463 def settings_email(self):
463 """GET /admin/settings/email: All items in the collection"""
464 """GET /admin/settings/email: All items in the collection"""
464 # url('admin_settings_email')
465 # url('admin_settings_email')
465 c.active = 'email'
466 c.active = 'email'
466 c.rhodecode_ini = rhodecode.CONFIG
467 c.rhodecode_ini = rhodecode.CONFIG
467
468
468 return htmlfill.render(
469 return htmlfill.render(
469 render('admin/settings/settings.mako'),
470 render('admin/settings/settings.mako'),
470 defaults=self._form_defaults(),
471 defaults=self._form_defaults(),
471 encoding="UTF-8",
472 encoding="UTF-8",
472 force_defaults=False)
473 force_defaults=False)
473
474
474 @HasPermissionAllDecorator('hg.admin')
475 @HasPermissionAllDecorator('hg.admin')
475 @auth.CSRFRequired()
476 @auth.CSRFRequired()
476 def settings_hooks_update(self):
477 def settings_hooks_update(self):
477 """POST or DELETE /admin/settings/hooks: All items in the collection"""
478 """POST or DELETE /admin/settings/hooks: All items in the collection"""
478 # url('admin_settings_hooks')
479 # url('admin_settings_hooks')
479 c.active = 'hooks'
480 c.active = 'hooks'
480 if c.visual.allow_custom_hooks_settings:
481 if c.visual.allow_custom_hooks_settings:
481 ui_key = request.POST.get('new_hook_ui_key')
482 ui_key = request.POST.get('new_hook_ui_key')
482 ui_value = request.POST.get('new_hook_ui_value')
483 ui_value = request.POST.get('new_hook_ui_value')
483
484
484 hook_id = request.POST.get('hook_id')
485 hook_id = request.POST.get('hook_id')
485 new_hook = False
486 new_hook = False
486
487
487 model = SettingsModel()
488 model = SettingsModel()
488 try:
489 try:
489 if ui_value and ui_key:
490 if ui_value and ui_key:
490 model.create_or_update_hook(ui_key, ui_value)
491 model.create_or_update_hook(ui_key, ui_value)
491 h.flash(_('Added new hook'), category='success')
492 h.flash(_('Added new hook'), category='success')
492 new_hook = True
493 new_hook = True
493 elif hook_id:
494 elif hook_id:
494 RhodeCodeUi.delete(hook_id)
495 RhodeCodeUi.delete(hook_id)
495 Session().commit()
496 Session().commit()
496
497
497 # check for edits
498 # check for edits
498 update = False
499 update = False
499 _d = request.POST.dict_of_lists()
500 _d = request.POST.dict_of_lists()
500 for k, v in zip(_d.get('hook_ui_key', []),
501 for k, v in zip(_d.get('hook_ui_key', []),
501 _d.get('hook_ui_value_new', [])):
502 _d.get('hook_ui_value_new', [])):
502 model.create_or_update_hook(k, v)
503 model.create_or_update_hook(k, v)
503 update = True
504 update = True
504
505
505 if update and not new_hook:
506 if update and not new_hook:
506 h.flash(_('Updated hooks'), category='success')
507 h.flash(_('Updated hooks'), category='success')
507 Session().commit()
508 Session().commit()
508 except Exception:
509 except Exception:
509 log.exception("Exception during hook creation")
510 log.exception("Exception during hook creation")
510 h.flash(_('Error occurred during hook creation'),
511 h.flash(_('Error occurred during hook creation'),
511 category='error')
512 category='error')
512
513
513 return redirect(url('admin_settings_hooks'))
514 return redirect(url('admin_settings_hooks'))
514
515
515 @HasPermissionAllDecorator('hg.admin')
516 @HasPermissionAllDecorator('hg.admin')
516 def settings_hooks(self):
517 def settings_hooks(self):
517 """GET /admin/settings/hooks: All items in the collection"""
518 """GET /admin/settings/hooks: All items in the collection"""
518 # url('admin_settings_hooks')
519 # url('admin_settings_hooks')
519 c.active = 'hooks'
520 c.active = 'hooks'
520
521
521 model = SettingsModel()
522 model = SettingsModel()
522 c.hooks = model.get_builtin_hooks()
523 c.hooks = model.get_builtin_hooks()
523 c.custom_hooks = model.get_custom_hooks()
524 c.custom_hooks = model.get_custom_hooks()
524
525
525 return htmlfill.render(
526 return htmlfill.render(
526 render('admin/settings/settings.mako'),
527 render('admin/settings/settings.mako'),
527 defaults=self._form_defaults(),
528 defaults=self._form_defaults(),
528 encoding="UTF-8",
529 encoding="UTF-8",
529 force_defaults=False)
530 force_defaults=False)
530
531
531 @HasPermissionAllDecorator('hg.admin')
532 @HasPermissionAllDecorator('hg.admin')
532 def settings_search(self):
533 def settings_search(self):
533 """GET /admin/settings/search: All items in the collection"""
534 """GET /admin/settings/search: All items in the collection"""
534 # url('admin_settings_search')
535 # url('admin_settings_search')
535 c.active = 'search'
536 c.active = 'search'
536
537
537 from rhodecode.lib.index import searcher_from_config
538 from rhodecode.lib.index import searcher_from_config
538 searcher = searcher_from_config(config)
539 searcher = searcher_from_config(config)
539 c.statistics = searcher.statistics()
540 c.statistics = searcher.statistics()
540
541
541 return render('admin/settings/settings.mako')
542 return render('admin/settings/settings.mako')
542
543
543 @HasPermissionAllDecorator('hg.admin')
544 @HasPermissionAllDecorator('hg.admin')
544 def settings_supervisor(self):
545 def settings_supervisor(self):
545 c.rhodecode_ini = rhodecode.CONFIG
546 c.rhodecode_ini = rhodecode.CONFIG
546 c.active = 'supervisor'
547 c.active = 'supervisor'
547
548
548 c.supervisor_procs = OrderedDict([
549 c.supervisor_procs = OrderedDict([
549 (SUPERVISOR_MASTER, {}),
550 (SUPERVISOR_MASTER, {}),
550 ])
551 ])
551
552
552 c.log_size = 10240
553 c.log_size = 10240
553 supervisor = SupervisorModel()
554 supervisor = SupervisorModel()
554
555
555 _connection = supervisor.get_connection(
556 _connection = supervisor.get_connection(
556 c.rhodecode_ini.get('supervisor.uri'))
557 c.rhodecode_ini.get('supervisor.uri'))
557 c.connection_error = None
558 c.connection_error = None
558 try:
559 try:
559 _connection.supervisor.getAllProcessInfo()
560 _connection.supervisor.getAllProcessInfo()
560 except Exception as e:
561 except Exception as e:
561 c.connection_error = str(e)
562 c.connection_error = str(e)
562 log.exception("Exception reading supervisor data")
563 log.exception("Exception reading supervisor data")
563 return render('admin/settings/settings.mako')
564 return render('admin/settings/settings.mako')
564
565
565 groupid = c.rhodecode_ini.get('supervisor.group_id')
566 groupid = c.rhodecode_ini.get('supervisor.group_id')
566
567
567 # feed our group processes to the main
568 # feed our group processes to the main
568 for proc in supervisor.get_group_processes(_connection, groupid):
569 for proc in supervisor.get_group_processes(_connection, groupid):
569 c.supervisor_procs[proc['name']] = {}
570 c.supervisor_procs[proc['name']] = {}
570
571
571 for k in c.supervisor_procs.keys():
572 for k in c.supervisor_procs.keys():
572 try:
573 try:
573 # master process info
574 # master process info
574 if k == SUPERVISOR_MASTER:
575 if k == SUPERVISOR_MASTER:
575 _data = supervisor.get_master_state(_connection)
576 _data = supervisor.get_master_state(_connection)
576 _data['name'] = 'supervisor master'
577 _data['name'] = 'supervisor master'
577 _data['description'] = 'pid %s, id: %s, ver: %s' % (
578 _data['description'] = 'pid %s, id: %s, ver: %s' % (
578 _data['pid'], _data['id'], _data['ver'])
579 _data['pid'], _data['id'], _data['ver'])
579 c.supervisor_procs[k] = _data
580 c.supervisor_procs[k] = _data
580 else:
581 else:
581 procid = groupid + ":" + k
582 procid = groupid + ":" + k
582 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
583 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
583 except Exception as e:
584 except Exception as e:
584 log.exception("Exception reading supervisor data")
585 log.exception("Exception reading supervisor data")
585 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
586 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
586
587
587 return render('admin/settings/settings.mako')
588 return render('admin/settings/settings.mako')
588
589
589 @HasPermissionAllDecorator('hg.admin')
590 @HasPermissionAllDecorator('hg.admin')
590 def settings_supervisor_log(self, procid):
591 def settings_supervisor_log(self, procid):
591 import rhodecode
592 import rhodecode
592 c.rhodecode_ini = rhodecode.CONFIG
593 c.rhodecode_ini = rhodecode.CONFIG
593 c.active = 'supervisor_tail'
594 c.active = 'supervisor_tail'
594
595
595 supervisor = SupervisorModel()
596 supervisor = SupervisorModel()
596 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
597 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
597 groupid = c.rhodecode_ini.get('supervisor.group_id')
598 groupid = c.rhodecode_ini.get('supervisor.group_id')
598 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
599 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
599
600
600 c.log_size = 10240
601 c.log_size = 10240
601 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
602 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
602 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
603 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
603
604
604 return render('admin/settings/settings.mako')
605 return render('admin/settings/settings.mako')
605
606
606 @HasPermissionAllDecorator('hg.admin')
607 @HasPermissionAllDecorator('hg.admin')
607 @auth.CSRFRequired()
608 @auth.CSRFRequired()
608 def settings_labs_update(self):
609 def settings_labs_update(self):
609 """POST /admin/settings/labs: All items in the collection"""
610 """POST /admin/settings/labs: All items in the collection"""
610 # url('admin_settings/labs', method={'POST'})
611 # url('admin_settings/labs', method={'POST'})
611 c.active = 'labs'
612 c.active = 'labs'
612
613
613 application_form = LabsSettingsForm()()
614 application_form = LabsSettingsForm()()
614 try:
615 try:
615 form_result = application_form.to_python(dict(request.POST))
616 form_result = application_form.to_python(dict(request.POST))
616 except formencode.Invalid as errors:
617 except formencode.Invalid as errors:
617 h.flash(
618 h.flash(
618 _('Some form inputs contain invalid data.'),
619 _('Some form inputs contain invalid data.'),
619 category='error')
620 category='error')
620 return htmlfill.render(
621 return htmlfill.render(
621 render('admin/settings/settings.mako'),
622 render('admin/settings/settings.mako'),
622 defaults=errors.value,
623 defaults=errors.value,
623 errors=errors.error_dict or {},
624 errors=errors.error_dict or {},
624 prefix_error=False,
625 prefix_error=False,
625 encoding='UTF-8',
626 encoding='UTF-8',
626 force_defaults=False
627 force_defaults=False
627 )
628 )
628
629
629 try:
630 try:
630 session = Session()
631 session = Session()
631 for setting in _LAB_SETTINGS:
632 for setting in _LAB_SETTINGS:
632 setting_name = setting.key[len('rhodecode_'):]
633 setting_name = setting.key[len('rhodecode_'):]
633 sett = SettingsModel().create_or_update_setting(
634 sett = SettingsModel().create_or_update_setting(
634 setting_name, form_result[setting.key], setting.type)
635 setting_name, form_result[setting.key], setting.type)
635 session.add(sett)
636 session.add(sett)
636
637
637 except Exception:
638 except Exception:
638 log.exception('Exception while updating lab settings')
639 log.exception('Exception while updating lab settings')
639 h.flash(_('Error occurred during updating labs settings'),
640 h.flash(_('Error occurred during updating labs settings'),
640 category='error')
641 category='error')
641 else:
642 else:
642 Session().commit()
643 Session().commit()
643 SettingsModel().invalidate_settings_cache()
644 SettingsModel().invalidate_settings_cache()
644 h.flash(_('Updated Labs settings'), category='success')
645 h.flash(_('Updated Labs settings'), category='success')
645 return redirect(url('admin_settings_labs'))
646 return redirect(url('admin_settings_labs'))
646
647
647 return htmlfill.render(
648 return htmlfill.render(
648 render('admin/settings/settings.mako'),
649 render('admin/settings/settings.mako'),
649 defaults=self._form_defaults(),
650 defaults=self._form_defaults(),
650 encoding='UTF-8',
651 encoding='UTF-8',
651 force_defaults=False)
652 force_defaults=False)
652
653
653 @HasPermissionAllDecorator('hg.admin')
654 @HasPermissionAllDecorator('hg.admin')
654 def settings_labs(self):
655 def settings_labs(self):
655 """GET /admin/settings/labs: All items in the collection"""
656 """GET /admin/settings/labs: All items in the collection"""
656 # url('admin_settings_labs')
657 # url('admin_settings_labs')
657 if not c.labs_active:
658 if not c.labs_active:
658 redirect(url('admin_settings'))
659 redirect(url('admin_settings'))
659
660
660 c.active = 'labs'
661 c.active = 'labs'
661 c.lab_settings = _LAB_SETTINGS
662 c.lab_settings = _LAB_SETTINGS
662
663
663 return htmlfill.render(
664 return htmlfill.render(
664 render('admin/settings/settings.mako'),
665 render('admin/settings/settings.mako'),
665 defaults=self._form_defaults(),
666 defaults=self._form_defaults(),
666 encoding='UTF-8',
667 encoding='UTF-8',
667 force_defaults=False)
668 force_defaults=False)
668
669
669 def _form_defaults(self):
670 def _form_defaults(self):
670 defaults = SettingsModel().get_all_settings()
671 defaults = SettingsModel().get_all_settings()
671 defaults.update(self._get_hg_ui_settings())
672 defaults.update(self._get_ui_settings())
673
672 defaults.update({
674 defaults.update({
673 'new_svn_branch': '',
675 'new_svn_branch': '',
674 'new_svn_tag': '',
676 'new_svn_tag': '',
675 })
677 })
676 return defaults
678 return defaults
677
679
678
680
679 # :param key: name of the setting including the 'rhodecode_' prefix
681 # :param key: name of the setting including the 'rhodecode_' prefix
680 # :param type: the RhodeCodeSetting type to use.
682 # :param type: the RhodeCodeSetting type to use.
681 # :param group: the i18ned group in which we should dispaly this setting
683 # :param group: the i18ned group in which we should dispaly this setting
682 # :param label: the i18ned label we should display for this setting
684 # :param label: the i18ned label we should display for this setting
683 # :param help: the i18ned help we should dispaly for this setting
685 # :param help: the i18ned help we should dispaly for this setting
684 LabSetting = collections.namedtuple(
686 LabSetting = collections.namedtuple(
685 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
687 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
686
688
687
689
688 # This list has to be kept in sync with the form
690 # This list has to be kept in sync with the form
689 # rhodecode.model.forms.LabsSettingsForm.
691 # rhodecode.model.forms.LabsSettingsForm.
690 _LAB_SETTINGS = [
692 _LAB_SETTINGS = [
691
693
692 ]
694 ]
@@ -1,553 +1,561 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 this is forms validation classes
22 this is forms validation classes
23 http://formencode.org/module-formencode.validators.html
23 http://formencode.org/module-formencode.validators.html
24 for list off all availible validators
24 for list off all availible validators
25
25
26 we can create our own validators
26 we can create our own validators
27
27
28 The table below outlines the options which can be used in a schema in addition to the validators themselves
28 The table below outlines the options which can be used in a schema in addition to the validators themselves
29 pre_validators [] These validators will be applied before the schema
29 pre_validators [] These validators will be applied before the schema
30 chained_validators [] These validators will be applied after the schema
30 chained_validators [] These validators will be applied after the schema
31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
31 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
32 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
33 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
34 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
35
35
36
36
37 <name> = formencode.validators.<name of validator>
37 <name> = formencode.validators.<name of validator>
38 <name> must equal form name
38 <name> must equal form name
39 list=[1,2,3,4,5]
39 list=[1,2,3,4,5]
40 for SELECT use formencode.All(OneOf(list), Int())
40 for SELECT use formencode.All(OneOf(list), Int())
41
41
42 """
42 """
43
43
44 import deform
44 import deform
45 import logging
45 import logging
46 import formencode
46 import formencode
47
47
48 from pkg_resources import resource_filename
48 from pkg_resources import resource_filename
49 from formencode import All, Pipe
49 from formencode import All, Pipe
50
50
51 from pylons.i18n.translation import _
51 from pylons.i18n.translation import _
52
52
53 from rhodecode import BACKENDS
53 from rhodecode import BACKENDS
54 from rhodecode.lib import helpers
54 from rhodecode.lib import helpers
55 from rhodecode.model import validators as v
55 from rhodecode.model import validators as v
56
56
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59
59
60 deform_templates = resource_filename('deform', 'templates')
60 deform_templates = resource_filename('deform', 'templates')
61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
61 rhodecode_templates = resource_filename('rhodecode', 'templates/forms')
62 search_path = (rhodecode_templates, deform_templates)
62 search_path = (rhodecode_templates, deform_templates)
63
63
64
64
65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
65 class RhodecodeFormZPTRendererFactory(deform.ZPTRendererFactory):
66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
66 """ Subclass of ZPTRendererFactory to add rhodecode context variables """
67 def __call__(self, template_name, **kw):
67 def __call__(self, template_name, **kw):
68 kw['h'] = helpers
68 kw['h'] = helpers
69 return self.load(template_name)(**kw)
69 return self.load(template_name)(**kw)
70
70
71
71
72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
72 form_renderer = RhodecodeFormZPTRendererFactory(search_path)
73 deform.Form.set_default_renderer(form_renderer)
73 deform.Form.set_default_renderer(form_renderer)
74
74
75
75
76 def LoginForm():
76 def LoginForm():
77 class _LoginForm(formencode.Schema):
77 class _LoginForm(formencode.Schema):
78 allow_extra_fields = True
78 allow_extra_fields = True
79 filter_extra_fields = True
79 filter_extra_fields = True
80 username = v.UnicodeString(
80 username = v.UnicodeString(
81 strip=True,
81 strip=True,
82 min=1,
82 min=1,
83 not_empty=True,
83 not_empty=True,
84 messages={
84 messages={
85 'empty': _(u'Please enter a login'),
85 'empty': _(u'Please enter a login'),
86 'tooShort': _(u'Enter a value %(min)i characters long or more')
86 'tooShort': _(u'Enter a value %(min)i characters long or more')
87 }
87 }
88 )
88 )
89
89
90 password = v.UnicodeString(
90 password = v.UnicodeString(
91 strip=False,
91 strip=False,
92 min=3,
92 min=3,
93 not_empty=True,
93 not_empty=True,
94 messages={
94 messages={
95 'empty': _(u'Please enter a password'),
95 'empty': _(u'Please enter a password'),
96 'tooShort': _(u'Enter %(min)i characters or more')}
96 'tooShort': _(u'Enter %(min)i characters or more')}
97 )
97 )
98
98
99 remember = v.StringBoolean(if_missing=False)
99 remember = v.StringBoolean(if_missing=False)
100
100
101 chained_validators = [v.ValidAuth()]
101 chained_validators = [v.ValidAuth()]
102 return _LoginForm
102 return _LoginForm
103
103
104
104
105 def UserForm(edit=False, available_languages=[], old_data={}):
105 def UserForm(edit=False, available_languages=[], old_data={}):
106 class _UserForm(formencode.Schema):
106 class _UserForm(formencode.Schema):
107 allow_extra_fields = True
107 allow_extra_fields = True
108 filter_extra_fields = True
108 filter_extra_fields = True
109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
109 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
110 v.ValidUsername(edit, old_data))
110 v.ValidUsername(edit, old_data))
111 if edit:
111 if edit:
112 new_password = All(
112 new_password = All(
113 v.ValidPassword(),
113 v.ValidPassword(),
114 v.UnicodeString(strip=False, min=6, not_empty=False)
114 v.UnicodeString(strip=False, min=6, not_empty=False)
115 )
115 )
116 password_confirmation = All(
116 password_confirmation = All(
117 v.ValidPassword(),
117 v.ValidPassword(),
118 v.UnicodeString(strip=False, min=6, not_empty=False),
118 v.UnicodeString(strip=False, min=6, not_empty=False),
119 )
119 )
120 admin = v.StringBoolean(if_missing=False)
120 admin = v.StringBoolean(if_missing=False)
121 else:
121 else:
122 password = All(
122 password = All(
123 v.ValidPassword(),
123 v.ValidPassword(),
124 v.UnicodeString(strip=False, min=6, not_empty=True)
124 v.UnicodeString(strip=False, min=6, not_empty=True)
125 )
125 )
126 password_confirmation = All(
126 password_confirmation = All(
127 v.ValidPassword(),
127 v.ValidPassword(),
128 v.UnicodeString(strip=False, min=6, not_empty=False)
128 v.UnicodeString(strip=False, min=6, not_empty=False)
129 )
129 )
130
130
131 password_change = v.StringBoolean(if_missing=False)
131 password_change = v.StringBoolean(if_missing=False)
132 create_repo_group = v.StringBoolean(if_missing=False)
132 create_repo_group = v.StringBoolean(if_missing=False)
133
133
134 active = v.StringBoolean(if_missing=False)
134 active = v.StringBoolean(if_missing=False)
135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
135 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
136 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
137 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
138 extern_name = v.UnicodeString(strip=True)
138 extern_name = v.UnicodeString(strip=True)
139 extern_type = v.UnicodeString(strip=True)
139 extern_type = v.UnicodeString(strip=True)
140 language = v.OneOf(available_languages, hideList=False,
140 language = v.OneOf(available_languages, hideList=False,
141 testValueList=True, if_missing=None)
141 testValueList=True, if_missing=None)
142 chained_validators = [v.ValidPasswordsMatch()]
142 chained_validators = [v.ValidPasswordsMatch()]
143 return _UserForm
143 return _UserForm
144
144
145
145
146 def UserGroupForm(edit=False, old_data=None, allow_disabled=False):
146 def UserGroupForm(edit=False, old_data=None, allow_disabled=False):
147 old_data = old_data or {}
147 old_data = old_data or {}
148
148
149 class _UserGroupForm(formencode.Schema):
149 class _UserGroupForm(formencode.Schema):
150 allow_extra_fields = True
150 allow_extra_fields = True
151 filter_extra_fields = True
151 filter_extra_fields = True
152
152
153 users_group_name = All(
153 users_group_name = All(
154 v.UnicodeString(strip=True, min=1, not_empty=True),
154 v.UnicodeString(strip=True, min=1, not_empty=True),
155 v.ValidUserGroup(edit, old_data)
155 v.ValidUserGroup(edit, old_data)
156 )
156 )
157 user_group_description = v.UnicodeString(strip=True, min=1,
157 user_group_description = v.UnicodeString(strip=True, min=1,
158 not_empty=False)
158 not_empty=False)
159
159
160 users_group_active = v.StringBoolean(if_missing=False)
160 users_group_active = v.StringBoolean(if_missing=False)
161
161
162 if edit:
162 if edit:
163 # this is user group owner
163 # this is user group owner
164 user = All(
164 user = All(
165 v.UnicodeString(not_empty=True),
165 v.UnicodeString(not_empty=True),
166 v.ValidRepoUser(allow_disabled))
166 v.ValidRepoUser(allow_disabled))
167 return _UserGroupForm
167 return _UserGroupForm
168
168
169
169
170 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
170 def RepoGroupForm(edit=False, old_data=None, available_groups=None,
171 can_create_in_root=False, allow_disabled=False):
171 can_create_in_root=False, allow_disabled=False):
172 old_data = old_data or {}
172 old_data = old_data or {}
173 available_groups = available_groups or []
173 available_groups = available_groups or []
174
174
175 class _RepoGroupForm(formencode.Schema):
175 class _RepoGroupForm(formencode.Schema):
176 allow_extra_fields = True
176 allow_extra_fields = True
177 filter_extra_fields = False
177 filter_extra_fields = False
178
178
179 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
179 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
180 v.SlugifyName(),)
180 v.SlugifyName(),)
181 group_description = v.UnicodeString(strip=True, min=1,
181 group_description = v.UnicodeString(strip=True, min=1,
182 not_empty=False)
182 not_empty=False)
183 group_copy_permissions = v.StringBoolean(if_missing=False)
183 group_copy_permissions = v.StringBoolean(if_missing=False)
184
184
185 group_parent_id = v.OneOf(available_groups, hideList=False,
185 group_parent_id = v.OneOf(available_groups, hideList=False,
186 testValueList=True, not_empty=True)
186 testValueList=True, not_empty=True)
187 enable_locking = v.StringBoolean(if_missing=False)
187 enable_locking = v.StringBoolean(if_missing=False)
188 chained_validators = [
188 chained_validators = [
189 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
189 v.ValidRepoGroup(edit, old_data, can_create_in_root)]
190
190
191 if edit:
191 if edit:
192 # this is repo group owner
192 # this is repo group owner
193 user = All(
193 user = All(
194 v.UnicodeString(not_empty=True),
194 v.UnicodeString(not_empty=True),
195 v.ValidRepoUser(allow_disabled))
195 v.ValidRepoUser(allow_disabled))
196
196
197 return _RepoGroupForm
197 return _RepoGroupForm
198
198
199
199
200 def RegisterForm(edit=False, old_data={}):
200 def RegisterForm(edit=False, old_data={}):
201 class _RegisterForm(formencode.Schema):
201 class _RegisterForm(formencode.Schema):
202 allow_extra_fields = True
202 allow_extra_fields = True
203 filter_extra_fields = True
203 filter_extra_fields = True
204 username = All(
204 username = All(
205 v.ValidUsername(edit, old_data),
205 v.ValidUsername(edit, old_data),
206 v.UnicodeString(strip=True, min=1, not_empty=True)
206 v.UnicodeString(strip=True, min=1, not_empty=True)
207 )
207 )
208 password = All(
208 password = All(
209 v.ValidPassword(),
209 v.ValidPassword(),
210 v.UnicodeString(strip=False, min=6, not_empty=True)
210 v.UnicodeString(strip=False, min=6, not_empty=True)
211 )
211 )
212 password_confirmation = All(
212 password_confirmation = All(
213 v.ValidPassword(),
213 v.ValidPassword(),
214 v.UnicodeString(strip=False, min=6, not_empty=True)
214 v.UnicodeString(strip=False, min=6, not_empty=True)
215 )
215 )
216 active = v.StringBoolean(if_missing=False)
216 active = v.StringBoolean(if_missing=False)
217 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
217 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
218 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
218 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
219 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
219 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
220
220
221 chained_validators = [v.ValidPasswordsMatch()]
221 chained_validators = [v.ValidPasswordsMatch()]
222
222
223 return _RegisterForm
223 return _RegisterForm
224
224
225
225
226 def PasswordResetForm():
226 def PasswordResetForm():
227 class _PasswordResetForm(formencode.Schema):
227 class _PasswordResetForm(formencode.Schema):
228 allow_extra_fields = True
228 allow_extra_fields = True
229 filter_extra_fields = True
229 filter_extra_fields = True
230 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
230 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
231 return _PasswordResetForm
231 return _PasswordResetForm
232
232
233
233
234 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
234 def RepoForm(edit=False, old_data=None, repo_groups=None, landing_revs=None,
235 allow_disabled=False):
235 allow_disabled=False):
236 old_data = old_data or {}
236 old_data = old_data or {}
237 repo_groups = repo_groups or []
237 repo_groups = repo_groups or []
238 landing_revs = landing_revs or []
238 landing_revs = landing_revs or []
239 supported_backends = BACKENDS.keys()
239 supported_backends = BACKENDS.keys()
240
240
241 class _RepoForm(formencode.Schema):
241 class _RepoForm(formencode.Schema):
242 allow_extra_fields = True
242 allow_extra_fields = True
243 filter_extra_fields = False
243 filter_extra_fields = False
244 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
244 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
245 v.SlugifyName())
245 v.SlugifyName())
246 repo_group = All(v.CanWriteGroup(old_data),
246 repo_group = All(v.CanWriteGroup(old_data),
247 v.OneOf(repo_groups, hideList=True))
247 v.OneOf(repo_groups, hideList=True))
248 repo_type = v.OneOf(supported_backends, required=False,
248 repo_type = v.OneOf(supported_backends, required=False,
249 if_missing=old_data.get('repo_type'))
249 if_missing=old_data.get('repo_type'))
250 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
250 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
251 repo_private = v.StringBoolean(if_missing=False)
251 repo_private = v.StringBoolean(if_missing=False)
252 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
252 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
253 repo_copy_permissions = v.StringBoolean(if_missing=False)
253 repo_copy_permissions = v.StringBoolean(if_missing=False)
254 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
254 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
255
255
256 repo_enable_statistics = v.StringBoolean(if_missing=False)
256 repo_enable_statistics = v.StringBoolean(if_missing=False)
257 repo_enable_downloads = v.StringBoolean(if_missing=False)
257 repo_enable_downloads = v.StringBoolean(if_missing=False)
258 repo_enable_locking = v.StringBoolean(if_missing=False)
258 repo_enable_locking = v.StringBoolean(if_missing=False)
259
259
260 if edit:
260 if edit:
261 # this is repo owner
261 # this is repo owner
262 user = All(
262 user = All(
263 v.UnicodeString(not_empty=True),
263 v.UnicodeString(not_empty=True),
264 v.ValidRepoUser(allow_disabled))
264 v.ValidRepoUser(allow_disabled))
265 clone_uri_change = v.UnicodeString(
265 clone_uri_change = v.UnicodeString(
266 not_empty=False, if_missing=v.Missing)
266 not_empty=False, if_missing=v.Missing)
267
267
268 chained_validators = [v.ValidCloneUri(),
268 chained_validators = [v.ValidCloneUri(),
269 v.ValidRepoName(edit, old_data)]
269 v.ValidRepoName(edit, old_data)]
270 return _RepoForm
270 return _RepoForm
271
271
272
272
273 def RepoPermsForm():
273 def RepoPermsForm():
274 class _RepoPermsForm(formencode.Schema):
274 class _RepoPermsForm(formencode.Schema):
275 allow_extra_fields = True
275 allow_extra_fields = True
276 filter_extra_fields = False
276 filter_extra_fields = False
277 chained_validators = [v.ValidPerms(type_='repo')]
277 chained_validators = [v.ValidPerms(type_='repo')]
278 return _RepoPermsForm
278 return _RepoPermsForm
279
279
280
280
281 def RepoGroupPermsForm(valid_recursive_choices):
281 def RepoGroupPermsForm(valid_recursive_choices):
282 class _RepoGroupPermsForm(formencode.Schema):
282 class _RepoGroupPermsForm(formencode.Schema):
283 allow_extra_fields = True
283 allow_extra_fields = True
284 filter_extra_fields = False
284 filter_extra_fields = False
285 recursive = v.OneOf(valid_recursive_choices)
285 recursive = v.OneOf(valid_recursive_choices)
286 chained_validators = [v.ValidPerms(type_='repo_group')]
286 chained_validators = [v.ValidPerms(type_='repo_group')]
287 return _RepoGroupPermsForm
287 return _RepoGroupPermsForm
288
288
289
289
290 def UserGroupPermsForm():
290 def UserGroupPermsForm():
291 class _UserPermsForm(formencode.Schema):
291 class _UserPermsForm(formencode.Schema):
292 allow_extra_fields = True
292 allow_extra_fields = True
293 filter_extra_fields = False
293 filter_extra_fields = False
294 chained_validators = [v.ValidPerms(type_='user_group')]
294 chained_validators = [v.ValidPerms(type_='user_group')]
295 return _UserPermsForm
295 return _UserPermsForm
296
296
297
297
298 def RepoFieldForm():
298 def RepoFieldForm():
299 class _RepoFieldForm(formencode.Schema):
299 class _RepoFieldForm(formencode.Schema):
300 filter_extra_fields = True
300 filter_extra_fields = True
301 allow_extra_fields = True
301 allow_extra_fields = True
302
302
303 new_field_key = All(v.FieldKey(),
303 new_field_key = All(v.FieldKey(),
304 v.UnicodeString(strip=True, min=3, not_empty=True))
304 v.UnicodeString(strip=True, min=3, not_empty=True))
305 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
305 new_field_value = v.UnicodeString(not_empty=False, if_missing=u'')
306 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
306 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
307 if_missing='str')
307 if_missing='str')
308 new_field_label = v.UnicodeString(not_empty=False)
308 new_field_label = v.UnicodeString(not_empty=False)
309 new_field_desc = v.UnicodeString(not_empty=False)
309 new_field_desc = v.UnicodeString(not_empty=False)
310
310
311 return _RepoFieldForm
311 return _RepoFieldForm
312
312
313
313
314 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
314 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
315 repo_groups=[], landing_revs=[]):
315 repo_groups=[], landing_revs=[]):
316 class _RepoForkForm(formencode.Schema):
316 class _RepoForkForm(formencode.Schema):
317 allow_extra_fields = True
317 allow_extra_fields = True
318 filter_extra_fields = False
318 filter_extra_fields = False
319 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
319 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
320 v.SlugifyName())
320 v.SlugifyName())
321 repo_group = All(v.CanWriteGroup(),
321 repo_group = All(v.CanWriteGroup(),
322 v.OneOf(repo_groups, hideList=True))
322 v.OneOf(repo_groups, hideList=True))
323 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
323 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
324 description = v.UnicodeString(strip=True, min=1, not_empty=True)
324 description = v.UnicodeString(strip=True, min=1, not_empty=True)
325 private = v.StringBoolean(if_missing=False)
325 private = v.StringBoolean(if_missing=False)
326 copy_permissions = v.StringBoolean(if_missing=False)
326 copy_permissions = v.StringBoolean(if_missing=False)
327 fork_parent_id = v.UnicodeString()
327 fork_parent_id = v.UnicodeString()
328 chained_validators = [v.ValidForkName(edit, old_data)]
328 chained_validators = [v.ValidForkName(edit, old_data)]
329 landing_rev = v.OneOf(landing_revs, hideList=True)
329 landing_rev = v.OneOf(landing_revs, hideList=True)
330
330
331 return _RepoForkForm
331 return _RepoForkForm
332
332
333
333
334 def ApplicationSettingsForm():
334 def ApplicationSettingsForm():
335 class _ApplicationSettingsForm(formencode.Schema):
335 class _ApplicationSettingsForm(formencode.Schema):
336 allow_extra_fields = True
336 allow_extra_fields = True
337 filter_extra_fields = False
337 filter_extra_fields = False
338 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
338 rhodecode_title = v.UnicodeString(strip=True, max=40, not_empty=False)
339 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
339 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
340 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
340 rhodecode_pre_code = v.UnicodeString(strip=True, min=1, not_empty=False)
341 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
341 rhodecode_post_code = v.UnicodeString(strip=True, min=1, not_empty=False)
342 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
342 rhodecode_captcha_public_key = v.UnicodeString(strip=True, min=1, not_empty=False)
343 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
343 rhodecode_captcha_private_key = v.UnicodeString(strip=True, min=1, not_empty=False)
344 rhodecode_create_personal_repo_group = v.StringBoolean(if_missing=False)
344 rhodecode_create_personal_repo_group = v.StringBoolean(if_missing=False)
345 rhodecode_personal_repo_group_pattern = v.UnicodeString(strip=True, min=1, not_empty=False)
345 rhodecode_personal_repo_group_pattern = v.UnicodeString(strip=True, min=1, not_empty=False)
346
346
347 return _ApplicationSettingsForm
347 return _ApplicationSettingsForm
348
348
349
349
350 def ApplicationVisualisationForm():
350 def ApplicationVisualisationForm():
351 class _ApplicationVisualisationForm(formencode.Schema):
351 class _ApplicationVisualisationForm(formencode.Schema):
352 allow_extra_fields = True
352 allow_extra_fields = True
353 filter_extra_fields = False
353 filter_extra_fields = False
354 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
354 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
355 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
355 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
356 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
356 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
357
357
358 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
358 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
359 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
359 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
360 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
360 rhodecode_dashboard_items = v.Int(min=5, not_empty=True)
361 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
361 rhodecode_admin_grid_items = v.Int(min=5, not_empty=True)
362 rhodecode_show_version = v.StringBoolean(if_missing=False)
362 rhodecode_show_version = v.StringBoolean(if_missing=False)
363 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
363 rhodecode_use_gravatar = v.StringBoolean(if_missing=False)
364 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
364 rhodecode_markup_renderer = v.OneOf(['markdown', 'rst'])
365 rhodecode_gravatar_url = v.UnicodeString(min=3)
365 rhodecode_gravatar_url = v.UnicodeString(min=3)
366 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
366 rhodecode_clone_uri_tmpl = v.UnicodeString(min=3)
367 rhodecode_support_url = v.UnicodeString()
367 rhodecode_support_url = v.UnicodeString()
368 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
368 rhodecode_show_revision_number = v.StringBoolean(if_missing=False)
369 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
369 rhodecode_show_sha_length = v.Int(min=4, not_empty=True)
370
370
371 return _ApplicationVisualisationForm
371 return _ApplicationVisualisationForm
372
372
373
373
374 class _BaseVcsSettingsForm(formencode.Schema):
374 class _BaseVcsSettingsForm(formencode.Schema):
375 allow_extra_fields = True
375 allow_extra_fields = True
376 filter_extra_fields = False
376 filter_extra_fields = False
377 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
377 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
378 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
378 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
379 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
379 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
380
380
381 # PR/Code-review
382 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
383 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
384
385 # hg
381 extensions_largefiles = v.StringBoolean(if_missing=False)
386 extensions_largefiles = v.StringBoolean(if_missing=False)
382 phases_publish = v.StringBoolean(if_missing=False)
387 phases_publish = v.StringBoolean(if_missing=False)
383
384 rhodecode_pr_merge_enabled = v.StringBoolean(if_missing=False)
385 rhodecode_use_outdated_comments = v.StringBoolean(if_missing=False)
386 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
388 rhodecode_hg_use_rebase_for_merging = v.StringBoolean(if_missing=False)
387
389
390 # git
391 vcs_git_lfs_enabled = v.StringBoolean(if_missing=False)
392
393 # svn
388 vcs_svn_proxy_http_requests_enabled = v.StringBoolean(if_missing=False)
394 vcs_svn_proxy_http_requests_enabled = v.StringBoolean(if_missing=False)
389 vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None)
395 vcs_svn_proxy_http_server_url = v.UnicodeString(strip=True, if_missing=None)
390
396
391
397
392 def ApplicationUiSettingsForm():
398 def ApplicationUiSettingsForm():
393 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
399 class _ApplicationUiSettingsForm(_BaseVcsSettingsForm):
394 web_push_ssl = v.StringBoolean(if_missing=False)
400 web_push_ssl = v.StringBoolean(if_missing=False)
395 paths_root_path = All(
401 paths_root_path = All(
396 v.ValidPath(),
402 v.ValidPath(),
397 v.UnicodeString(strip=True, min=1, not_empty=True)
403 v.UnicodeString(strip=True, min=1, not_empty=True)
398 )
404 )
399 largefiles_usercache = All(
405 largefiles_usercache = All(
400 v.ValidPath(),
406 v.ValidPath(),
401 v.UnicodeString(strip=True, min=2, not_empty=True)
407 v.UnicodeString(strip=True, min=2, not_empty=True))
402 )
408 vcs_git_lfs_store_location = All(
409 v.ValidPath(),
410 v.UnicodeString(strip=True, min=2, not_empty=True))
403 extensions_hgsubversion = v.StringBoolean(if_missing=False)
411 extensions_hgsubversion = v.StringBoolean(if_missing=False)
404 extensions_hggit = v.StringBoolean(if_missing=False)
412 extensions_hggit = v.StringBoolean(if_missing=False)
405 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
413 new_svn_branch = v.ValidSvnPattern(section='vcs_svn_branch')
406 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
414 new_svn_tag = v.ValidSvnPattern(section='vcs_svn_tag')
407
415
408 return _ApplicationUiSettingsForm
416 return _ApplicationUiSettingsForm
409
417
410
418
411 def RepoVcsSettingsForm(repo_name):
419 def RepoVcsSettingsForm(repo_name):
412 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
420 class _RepoVcsSettingsForm(_BaseVcsSettingsForm):
413 inherit_global_settings = v.StringBoolean(if_missing=False)
421 inherit_global_settings = v.StringBoolean(if_missing=False)
414 new_svn_branch = v.ValidSvnPattern(
422 new_svn_branch = v.ValidSvnPattern(
415 section='vcs_svn_branch', repo_name=repo_name)
423 section='vcs_svn_branch', repo_name=repo_name)
416 new_svn_tag = v.ValidSvnPattern(
424 new_svn_tag = v.ValidSvnPattern(
417 section='vcs_svn_tag', repo_name=repo_name)
425 section='vcs_svn_tag', repo_name=repo_name)
418
426
419 return _RepoVcsSettingsForm
427 return _RepoVcsSettingsForm
420
428
421
429
422 def LabsSettingsForm():
430 def LabsSettingsForm():
423 class _LabSettingsForm(formencode.Schema):
431 class _LabSettingsForm(formencode.Schema):
424 allow_extra_fields = True
432 allow_extra_fields = True
425 filter_extra_fields = False
433 filter_extra_fields = False
426
434
427 return _LabSettingsForm
435 return _LabSettingsForm
428
436
429
437
430 def ApplicationPermissionsForm(
438 def ApplicationPermissionsForm(
431 register_choices, password_reset_choices, extern_activate_choices):
439 register_choices, password_reset_choices, extern_activate_choices):
432 class _DefaultPermissionsForm(formencode.Schema):
440 class _DefaultPermissionsForm(formencode.Schema):
433 allow_extra_fields = True
441 allow_extra_fields = True
434 filter_extra_fields = True
442 filter_extra_fields = True
435
443
436 anonymous = v.StringBoolean(if_missing=False)
444 anonymous = v.StringBoolean(if_missing=False)
437 default_register = v.OneOf(register_choices)
445 default_register = v.OneOf(register_choices)
438 default_register_message = v.UnicodeString()
446 default_register_message = v.UnicodeString()
439 default_password_reset = v.OneOf(password_reset_choices)
447 default_password_reset = v.OneOf(password_reset_choices)
440 default_extern_activate = v.OneOf(extern_activate_choices)
448 default_extern_activate = v.OneOf(extern_activate_choices)
441
449
442 return _DefaultPermissionsForm
450 return _DefaultPermissionsForm
443
451
444
452
445 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
453 def ObjectPermissionsForm(repo_perms_choices, group_perms_choices,
446 user_group_perms_choices):
454 user_group_perms_choices):
447 class _ObjectPermissionsForm(formencode.Schema):
455 class _ObjectPermissionsForm(formencode.Schema):
448 allow_extra_fields = True
456 allow_extra_fields = True
449 filter_extra_fields = True
457 filter_extra_fields = True
450 overwrite_default_repo = v.StringBoolean(if_missing=False)
458 overwrite_default_repo = v.StringBoolean(if_missing=False)
451 overwrite_default_group = v.StringBoolean(if_missing=False)
459 overwrite_default_group = v.StringBoolean(if_missing=False)
452 overwrite_default_user_group = v.StringBoolean(if_missing=False)
460 overwrite_default_user_group = v.StringBoolean(if_missing=False)
453 default_repo_perm = v.OneOf(repo_perms_choices)
461 default_repo_perm = v.OneOf(repo_perms_choices)
454 default_group_perm = v.OneOf(group_perms_choices)
462 default_group_perm = v.OneOf(group_perms_choices)
455 default_user_group_perm = v.OneOf(user_group_perms_choices)
463 default_user_group_perm = v.OneOf(user_group_perms_choices)
456
464
457 return _ObjectPermissionsForm
465 return _ObjectPermissionsForm
458
466
459
467
460 def UserPermissionsForm(create_choices, create_on_write_choices,
468 def UserPermissionsForm(create_choices, create_on_write_choices,
461 repo_group_create_choices, user_group_create_choices,
469 repo_group_create_choices, user_group_create_choices,
462 fork_choices, inherit_default_permissions_choices):
470 fork_choices, inherit_default_permissions_choices):
463 class _DefaultPermissionsForm(formencode.Schema):
471 class _DefaultPermissionsForm(formencode.Schema):
464 allow_extra_fields = True
472 allow_extra_fields = True
465 filter_extra_fields = True
473 filter_extra_fields = True
466
474
467 anonymous = v.StringBoolean(if_missing=False)
475 anonymous = v.StringBoolean(if_missing=False)
468
476
469 default_repo_create = v.OneOf(create_choices)
477 default_repo_create = v.OneOf(create_choices)
470 default_repo_create_on_write = v.OneOf(create_on_write_choices)
478 default_repo_create_on_write = v.OneOf(create_on_write_choices)
471 default_user_group_create = v.OneOf(user_group_create_choices)
479 default_user_group_create = v.OneOf(user_group_create_choices)
472 default_repo_group_create = v.OneOf(repo_group_create_choices)
480 default_repo_group_create = v.OneOf(repo_group_create_choices)
473 default_fork_create = v.OneOf(fork_choices)
481 default_fork_create = v.OneOf(fork_choices)
474 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
482 default_inherit_default_permissions = v.OneOf(inherit_default_permissions_choices)
475
483
476 return _DefaultPermissionsForm
484 return _DefaultPermissionsForm
477
485
478
486
479 def UserIndividualPermissionsForm():
487 def UserIndividualPermissionsForm():
480 class _DefaultPermissionsForm(formencode.Schema):
488 class _DefaultPermissionsForm(formencode.Schema):
481 allow_extra_fields = True
489 allow_extra_fields = True
482 filter_extra_fields = True
490 filter_extra_fields = True
483
491
484 inherit_default_permissions = v.StringBoolean(if_missing=False)
492 inherit_default_permissions = v.StringBoolean(if_missing=False)
485
493
486 return _DefaultPermissionsForm
494 return _DefaultPermissionsForm
487
495
488
496
489 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
497 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
490 class _DefaultsForm(formencode.Schema):
498 class _DefaultsForm(formencode.Schema):
491 allow_extra_fields = True
499 allow_extra_fields = True
492 filter_extra_fields = True
500 filter_extra_fields = True
493 default_repo_type = v.OneOf(supported_backends)
501 default_repo_type = v.OneOf(supported_backends)
494 default_repo_private = v.StringBoolean(if_missing=False)
502 default_repo_private = v.StringBoolean(if_missing=False)
495 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
503 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
496 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
504 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
497 default_repo_enable_locking = v.StringBoolean(if_missing=False)
505 default_repo_enable_locking = v.StringBoolean(if_missing=False)
498
506
499 return _DefaultsForm
507 return _DefaultsForm
500
508
501
509
502 def AuthSettingsForm():
510 def AuthSettingsForm():
503 class _AuthSettingsForm(formencode.Schema):
511 class _AuthSettingsForm(formencode.Schema):
504 allow_extra_fields = True
512 allow_extra_fields = True
505 filter_extra_fields = True
513 filter_extra_fields = True
506 auth_plugins = All(v.ValidAuthPlugins(),
514 auth_plugins = All(v.ValidAuthPlugins(),
507 v.UniqueListFromString()(not_empty=True))
515 v.UniqueListFromString()(not_empty=True))
508
516
509 return _AuthSettingsForm
517 return _AuthSettingsForm
510
518
511
519
512 def UserExtraEmailForm():
520 def UserExtraEmailForm():
513 class _UserExtraEmailForm(formencode.Schema):
521 class _UserExtraEmailForm(formencode.Schema):
514 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
522 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
515 return _UserExtraEmailForm
523 return _UserExtraEmailForm
516
524
517
525
518 def UserExtraIpForm():
526 def UserExtraIpForm():
519 class _UserExtraIpForm(formencode.Schema):
527 class _UserExtraIpForm(formencode.Schema):
520 ip = v.ValidIp()(not_empty=True)
528 ip = v.ValidIp()(not_empty=True)
521 return _UserExtraIpForm
529 return _UserExtraIpForm
522
530
523
531
524
532
525 def PullRequestForm(repo_id):
533 def PullRequestForm(repo_id):
526 class ReviewerForm(formencode.Schema):
534 class ReviewerForm(formencode.Schema):
527 user_id = v.Int(not_empty=True)
535 user_id = v.Int(not_empty=True)
528 reasons = All()
536 reasons = All()
529
537
530 class _PullRequestForm(formencode.Schema):
538 class _PullRequestForm(formencode.Schema):
531 allow_extra_fields = True
539 allow_extra_fields = True
532 filter_extra_fields = True
540 filter_extra_fields = True
533
541
534 user = v.UnicodeString(strip=True, required=True)
542 user = v.UnicodeString(strip=True, required=True)
535 source_repo = v.UnicodeString(strip=True, required=True)
543 source_repo = v.UnicodeString(strip=True, required=True)
536 source_ref = v.UnicodeString(strip=True, required=True)
544 source_ref = v.UnicodeString(strip=True, required=True)
537 target_repo = v.UnicodeString(strip=True, required=True)
545 target_repo = v.UnicodeString(strip=True, required=True)
538 target_ref = v.UnicodeString(strip=True, required=True)
546 target_ref = v.UnicodeString(strip=True, required=True)
539 revisions = All(#v.NotReviewedRevisions(repo_id)(),
547 revisions = All(#v.NotReviewedRevisions(repo_id)(),
540 v.UniqueList()(not_empty=True))
548 v.UniqueList()(not_empty=True))
541 review_members = formencode.ForEach(ReviewerForm())
549 review_members = formencode.ForEach(ReviewerForm())
542 pullrequest_title = v.UnicodeString(strip=True, required=True)
550 pullrequest_title = v.UnicodeString(strip=True, required=True)
543 pullrequest_desc = v.UnicodeString(strip=True, required=False)
551 pullrequest_desc = v.UnicodeString(strip=True, required=False)
544
552
545 return _PullRequestForm
553 return _PullRequestForm
546
554
547
555
548 def IssueTrackerPatternsForm():
556 def IssueTrackerPatternsForm():
549 class _IssueTrackerPatternsForm(formencode.Schema):
557 class _IssueTrackerPatternsForm(formencode.Schema):
550 allow_extra_fields = True
558 allow_extra_fields = True
551 filter_extra_fields = False
559 filter_extra_fields = False
552 chained_validators = [v.ValidPattern()]
560 chained_validators = [v.ValidPattern()]
553 return _IssueTrackerPatternsForm
561 return _IssueTrackerPatternsForm
@@ -1,737 +1,776 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 hashlib
21 import hashlib
22 import logging
22 import logging
23 from collections import namedtuple
23 from collections import namedtuple
24 from functools import wraps
24 from functools import wraps
25
25
26 from rhodecode.lib import caches
26 from rhodecode.lib import caches
27 from rhodecode.lib.utils2 import (
27 from rhodecode.lib.utils2 import (
28 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
28 Optional, AttributeDict, safe_str, remove_prefix, str2bool)
29 from rhodecode.lib.vcs.backends import base
29 from rhodecode.lib.vcs.backends import base
30 from rhodecode.model import BaseModel
30 from rhodecode.model import BaseModel
31 from rhodecode.model.db import (
31 from rhodecode.model.db import (
32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
32 RepoRhodeCodeUi, RepoRhodeCodeSetting, RhodeCodeUi, RhodeCodeSetting)
33 from rhodecode.model.meta import Session
33 from rhodecode.model.meta import Session
34
34
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 UiSetting = namedtuple(
39 UiSetting = namedtuple(
40 'UiSetting', ['section', 'key', 'value', 'active'])
40 'UiSetting', ['section', 'key', 'value', 'active'])
41
41
42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
42 SOCIAL_PLUGINS_LIST = ['github', 'bitbucket', 'twitter', 'google']
43
43
44
44
45 class SettingNotFound(Exception):
45 class SettingNotFound(Exception):
46 def __init__(self):
46 def __init__(self):
47 super(SettingNotFound, self).__init__('Setting is not found')
47 super(SettingNotFound, self).__init__('Setting is not found')
48
48
49
49
50 class SettingsModel(BaseModel):
50 class SettingsModel(BaseModel):
51 BUILTIN_HOOKS = (
51 BUILTIN_HOOKS = (
52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
52 RhodeCodeUi.HOOK_REPO_SIZE, RhodeCodeUi.HOOK_PUSH,
53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
53 RhodeCodeUi.HOOK_PRE_PUSH, RhodeCodeUi.HOOK_PRETX_PUSH,
54 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL)
54 RhodeCodeUi.HOOK_PULL, RhodeCodeUi.HOOK_PRE_PULL)
55 HOOKS_SECTION = 'hooks'
55 HOOKS_SECTION = 'hooks'
56
56
57 def __init__(self, sa=None, repo=None):
57 def __init__(self, sa=None, repo=None):
58 self.repo = repo
58 self.repo = repo
59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
59 self.UiDbModel = RepoRhodeCodeUi if repo else RhodeCodeUi
60 self.SettingsDbModel = (
60 self.SettingsDbModel = (
61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
61 RepoRhodeCodeSetting if repo else RhodeCodeSetting)
62 super(SettingsModel, self).__init__(sa)
62 super(SettingsModel, self).__init__(sa)
63
63
64 def get_ui_by_key(self, key):
64 def get_ui_by_key(self, key):
65 q = self.UiDbModel.query()
65 q = self.UiDbModel.query()
66 q = q.filter(self.UiDbModel.ui_key == key)
66 q = q.filter(self.UiDbModel.ui_key == key)
67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
67 q = self._filter_by_repo(RepoRhodeCodeUi, q)
68 return q.scalar()
68 return q.scalar()
69
69
70 def get_ui_by_section(self, section):
70 def get_ui_by_section(self, section):
71 q = self.UiDbModel.query()
71 q = self.UiDbModel.query()
72 q = q.filter(self.UiDbModel.ui_section == section)
72 q = q.filter(self.UiDbModel.ui_section == section)
73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
73 q = self._filter_by_repo(RepoRhodeCodeUi, q)
74 return q.all()
74 return q.all()
75
75
76 def get_ui_by_section_and_key(self, section, key):
76 def get_ui_by_section_and_key(self, section, key):
77 q = self.UiDbModel.query()
77 q = self.UiDbModel.query()
78 q = q.filter(self.UiDbModel.ui_section == section)
78 q = q.filter(self.UiDbModel.ui_section == section)
79 q = q.filter(self.UiDbModel.ui_key == key)
79 q = q.filter(self.UiDbModel.ui_key == key)
80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
80 q = self._filter_by_repo(RepoRhodeCodeUi, q)
81 return q.scalar()
81 return q.scalar()
82
82
83 def get_ui(self, section=None, key=None):
83 def get_ui(self, section=None, key=None):
84 q = self.UiDbModel.query()
84 q = self.UiDbModel.query()
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
85 q = self._filter_by_repo(RepoRhodeCodeUi, q)
86
86
87 if section:
87 if section:
88 q = q.filter(self.UiDbModel.ui_section == section)
88 q = q.filter(self.UiDbModel.ui_section == section)
89 if key:
89 if key:
90 q = q.filter(self.UiDbModel.ui_key == key)
90 q = q.filter(self.UiDbModel.ui_key == key)
91
91
92 # TODO: mikhail: add caching
92 # TODO: mikhail: add caching
93 result = [
93 result = [
94 UiSetting(
94 UiSetting(
95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
95 section=safe_str(r.ui_section), key=safe_str(r.ui_key),
96 value=safe_str(r.ui_value), active=r.ui_active
96 value=safe_str(r.ui_value), active=r.ui_active
97 )
97 )
98 for r in q.all()
98 for r in q.all()
99 ]
99 ]
100 return result
100 return result
101
101
102 def get_builtin_hooks(self):
102 def get_builtin_hooks(self):
103 q = self.UiDbModel.query()
103 q = self.UiDbModel.query()
104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
104 q = q.filter(self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
105 return self._get_hooks(q)
105 return self._get_hooks(q)
106
106
107 def get_custom_hooks(self):
107 def get_custom_hooks(self):
108 q = self.UiDbModel.query()
108 q = self.UiDbModel.query()
109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
109 q = q.filter(~self.UiDbModel.ui_key.in_(self.BUILTIN_HOOKS))
110 return self._get_hooks(q)
110 return self._get_hooks(q)
111
111
112 def create_ui_section_value(self, section, val, key=None, active=True):
112 def create_ui_section_value(self, section, val, key=None, active=True):
113 new_ui = self.UiDbModel()
113 new_ui = self.UiDbModel()
114 new_ui.ui_section = section
114 new_ui.ui_section = section
115 new_ui.ui_value = val
115 new_ui.ui_value = val
116 new_ui.ui_active = active
116 new_ui.ui_active = active
117
117
118 if self.repo:
118 if self.repo:
119 repo = self._get_repo(self.repo)
119 repo = self._get_repo(self.repo)
120 repository_id = repo.repo_id
120 repository_id = repo.repo_id
121 new_ui.repository_id = repository_id
121 new_ui.repository_id = repository_id
122
122
123 if not key:
123 if not key:
124 # keys are unique so they need appended info
124 # keys are unique so they need appended info
125 if self.repo:
125 if self.repo:
126 key = hashlib.sha1(
126 key = hashlib.sha1(
127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
127 '{}{}{}'.format(section, val, repository_id)).hexdigest()
128 else:
128 else:
129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
129 key = hashlib.sha1('{}{}'.format(section, val)).hexdigest()
130
130
131 new_ui.ui_key = key
131 new_ui.ui_key = key
132
132
133 Session().add(new_ui)
133 Session().add(new_ui)
134 return new_ui
134 return new_ui
135
135
136 def create_or_update_hook(self, key, value):
136 def create_or_update_hook(self, key, value):
137 ui = (
137 ui = (
138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
138 self.get_ui_by_section_and_key(self.HOOKS_SECTION, key) or
139 self.UiDbModel())
139 self.UiDbModel())
140 ui.ui_section = self.HOOKS_SECTION
140 ui.ui_section = self.HOOKS_SECTION
141 ui.ui_active = True
141 ui.ui_active = True
142 ui.ui_key = key
142 ui.ui_key = key
143 ui.ui_value = value
143 ui.ui_value = value
144
144
145 if self.repo:
145 if self.repo:
146 repo = self._get_repo(self.repo)
146 repo = self._get_repo(self.repo)
147 repository_id = repo.repo_id
147 repository_id = repo.repo_id
148 ui.repository_id = repository_id
148 ui.repository_id = repository_id
149
149
150 Session().add(ui)
150 Session().add(ui)
151 return ui
151 return ui
152
152
153 def delete_ui(self, id_):
153 def delete_ui(self, id_):
154 ui = self.UiDbModel.get(id_)
154 ui = self.UiDbModel.get(id_)
155 if not ui:
155 if not ui:
156 raise SettingNotFound()
156 raise SettingNotFound()
157 Session().delete(ui)
157 Session().delete(ui)
158
158
159 def get_setting_by_name(self, name):
159 def get_setting_by_name(self, name):
160 q = self._get_settings_query()
160 q = self._get_settings_query()
161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
161 q = q.filter(self.SettingsDbModel.app_settings_name == name)
162 return q.scalar()
162 return q.scalar()
163
163
164 def create_or_update_setting(
164 def create_or_update_setting(
165 self, name, val=Optional(''), type_=Optional('unicode')):
165 self, name, val=Optional(''), type_=Optional('unicode')):
166 """
166 """
167 Creates or updates RhodeCode setting. If updates is triggered it will
167 Creates or updates RhodeCode setting. If updates is triggered it will
168 only update parameters that are explicityl set Optional instance will
168 only update parameters that are explicityl set Optional instance will
169 be skipped
169 be skipped
170
170
171 :param name:
171 :param name:
172 :param val:
172 :param val:
173 :param type_:
173 :param type_:
174 :return:
174 :return:
175 """
175 """
176
176
177 res = self.get_setting_by_name(name)
177 res = self.get_setting_by_name(name)
178 repo = self._get_repo(self.repo) if self.repo else None
178 repo = self._get_repo(self.repo) if self.repo else None
179
179
180 if not res:
180 if not res:
181 val = Optional.extract(val)
181 val = Optional.extract(val)
182 type_ = Optional.extract(type_)
182 type_ = Optional.extract(type_)
183
183
184 args = (
184 args = (
185 (repo.repo_id, name, val, type_)
185 (repo.repo_id, name, val, type_)
186 if repo else (name, val, type_))
186 if repo else (name, val, type_))
187 res = self.SettingsDbModel(*args)
187 res = self.SettingsDbModel(*args)
188
188
189 else:
189 else:
190 if self.repo:
190 if self.repo:
191 res.repository_id = repo.repo_id
191 res.repository_id = repo.repo_id
192
192
193 res.app_settings_name = name
193 res.app_settings_name = name
194 if not isinstance(type_, Optional):
194 if not isinstance(type_, Optional):
195 # update if set
195 # update if set
196 res.app_settings_type = type_
196 res.app_settings_type = type_
197 if not isinstance(val, Optional):
197 if not isinstance(val, Optional):
198 # update if set
198 # update if set
199 res.app_settings_value = val
199 res.app_settings_value = val
200
200
201 Session().add(res)
201 Session().add(res)
202 return res
202 return res
203
203
204 def invalidate_settings_cache(self):
204 def invalidate_settings_cache(self):
205 namespace = 'rhodecode_settings'
205 namespace = 'rhodecode_settings'
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
206 cache_manager = caches.get_cache_manager('sql_cache_short', namespace)
207 caches.clear_cache_manager(cache_manager)
207 caches.clear_cache_manager(cache_manager)
208
208
209 def get_all_settings(self, cache=False):
209 def get_all_settings(self, cache=False):
210 def _compute():
210 def _compute():
211 q = self._get_settings_query()
211 q = self._get_settings_query()
212 if not q:
212 if not q:
213 raise Exception('Could not get application settings !')
213 raise Exception('Could not get application settings !')
214
214
215 settings = {
215 settings = {
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
216 'rhodecode_' + result.app_settings_name: result.app_settings_value
217 for result in q
217 for result in q
218 }
218 }
219 return settings
219 return settings
220
220
221 if cache:
221 if cache:
222 log.debug('Fetching app settings using cache')
222 log.debug('Fetching app settings using cache')
223 repo = self._get_repo(self.repo) if self.repo else None
223 repo = self._get_repo(self.repo) if self.repo else None
224 namespace = 'rhodecode_settings'
224 namespace = 'rhodecode_settings'
225 cache_manager = caches.get_cache_manager(
225 cache_manager = caches.get_cache_manager(
226 'sql_cache_short', namespace)
226 'sql_cache_short', namespace)
227 _cache_key = (
227 _cache_key = (
228 "get_repo_{}_settings".format(repo.repo_id)
228 "get_repo_{}_settings".format(repo.repo_id)
229 if repo else "get_app_settings")
229 if repo else "get_app_settings")
230
230
231 return cache_manager.get(_cache_key, createfunc=_compute)
231 return cache_manager.get(_cache_key, createfunc=_compute)
232
232
233 else:
233 else:
234 return _compute()
234 return _compute()
235
235
236 def get_auth_settings(self):
236 def get_auth_settings(self):
237 q = self._get_settings_query()
237 q = self._get_settings_query()
238 q = q.filter(
238 q = q.filter(
239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
239 self.SettingsDbModel.app_settings_name.startswith('auth_'))
240 rows = q.all()
240 rows = q.all()
241 auth_settings = {
241 auth_settings = {
242 row.app_settings_name: row.app_settings_value for row in rows}
242 row.app_settings_name: row.app_settings_value for row in rows}
243 return auth_settings
243 return auth_settings
244
244
245 def get_auth_plugins(self):
245 def get_auth_plugins(self):
246 auth_plugins = self.get_setting_by_name("auth_plugins")
246 auth_plugins = self.get_setting_by_name("auth_plugins")
247 return auth_plugins.app_settings_value
247 return auth_plugins.app_settings_value
248
248
249 def get_default_repo_settings(self, strip_prefix=False):
249 def get_default_repo_settings(self, strip_prefix=False):
250 q = self._get_settings_query()
250 q = self._get_settings_query()
251 q = q.filter(
251 q = q.filter(
252 self.SettingsDbModel.app_settings_name.startswith('default_'))
252 self.SettingsDbModel.app_settings_name.startswith('default_'))
253 rows = q.all()
253 rows = q.all()
254
254
255 result = {}
255 result = {}
256 for row in rows:
256 for row in rows:
257 key = row.app_settings_name
257 key = row.app_settings_name
258 if strip_prefix:
258 if strip_prefix:
259 key = remove_prefix(key, prefix='default_')
259 key = remove_prefix(key, prefix='default_')
260 result.update({key: row.app_settings_value})
260 result.update({key: row.app_settings_value})
261 return result
261 return result
262
262
263 def get_repo(self):
263 def get_repo(self):
264 repo = self._get_repo(self.repo)
264 repo = self._get_repo(self.repo)
265 if not repo:
265 if not repo:
266 raise Exception(
266 raise Exception(
267 'Repository `{}` cannot be found inside the database'.format(
267 'Repository `{}` cannot be found inside the database'.format(
268 self.repo))
268 self.repo))
269 return repo
269 return repo
270
270
271 def _filter_by_repo(self, model, query):
271 def _filter_by_repo(self, model, query):
272 if self.repo:
272 if self.repo:
273 repo = self.get_repo()
273 repo = self.get_repo()
274 query = query.filter(model.repository_id == repo.repo_id)
274 query = query.filter(model.repository_id == repo.repo_id)
275 return query
275 return query
276
276
277 def _get_hooks(self, query):
277 def _get_hooks(self, query):
278 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
278 query = query.filter(self.UiDbModel.ui_section == self.HOOKS_SECTION)
279 query = self._filter_by_repo(RepoRhodeCodeUi, query)
279 query = self._filter_by_repo(RepoRhodeCodeUi, query)
280 return query.all()
280 return query.all()
281
281
282 def _get_settings_query(self):
282 def _get_settings_query(self):
283 q = self.SettingsDbModel.query()
283 q = self.SettingsDbModel.query()
284 return self._filter_by_repo(RepoRhodeCodeSetting, q)
284 return self._filter_by_repo(RepoRhodeCodeSetting, q)
285
285
286 def list_enabled_social_plugins(self, settings):
286 def list_enabled_social_plugins(self, settings):
287 enabled = []
287 enabled = []
288 for plug in SOCIAL_PLUGINS_LIST:
288 for plug in SOCIAL_PLUGINS_LIST:
289 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
289 if str2bool(settings.get('rhodecode_auth_{}_enabled'.format(plug)
290 )):
290 )):
291 enabled.append(plug)
291 enabled.append(plug)
292 return enabled
292 return enabled
293
293
294
294
295 def assert_repo_settings(func):
295 def assert_repo_settings(func):
296 @wraps(func)
296 @wraps(func)
297 def _wrapper(self, *args, **kwargs):
297 def _wrapper(self, *args, **kwargs):
298 if not self.repo_settings:
298 if not self.repo_settings:
299 raise Exception('Repository is not specified')
299 raise Exception('Repository is not specified')
300 return func(self, *args, **kwargs)
300 return func(self, *args, **kwargs)
301 return _wrapper
301 return _wrapper
302
302
303
303
304 class IssueTrackerSettingsModel(object):
304 class IssueTrackerSettingsModel(object):
305 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
305 INHERIT_SETTINGS = 'inherit_issue_tracker_settings'
306 SETTINGS_PREFIX = 'issuetracker_'
306 SETTINGS_PREFIX = 'issuetracker_'
307
307
308 def __init__(self, sa=None, repo=None):
308 def __init__(self, sa=None, repo=None):
309 self.global_settings = SettingsModel(sa=sa)
309 self.global_settings = SettingsModel(sa=sa)
310 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
310 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
311
311
312 @property
312 @property
313 def inherit_global_settings(self):
313 def inherit_global_settings(self):
314 if not self.repo_settings:
314 if not self.repo_settings:
315 return True
315 return True
316 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
316 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
317 return setting.app_settings_value if setting else True
317 return setting.app_settings_value if setting else True
318
318
319 @inherit_global_settings.setter
319 @inherit_global_settings.setter
320 def inherit_global_settings(self, value):
320 def inherit_global_settings(self, value):
321 if self.repo_settings:
321 if self.repo_settings:
322 settings = self.repo_settings.create_or_update_setting(
322 settings = self.repo_settings.create_or_update_setting(
323 self.INHERIT_SETTINGS, value, type_='bool')
323 self.INHERIT_SETTINGS, value, type_='bool')
324 Session().add(settings)
324 Session().add(settings)
325
325
326 def _get_keyname(self, key, uid, prefix=''):
326 def _get_keyname(self, key, uid, prefix=''):
327 return '{0}{1}{2}_{3}'.format(
327 return '{0}{1}{2}_{3}'.format(
328 prefix, self.SETTINGS_PREFIX, key, uid)
328 prefix, self.SETTINGS_PREFIX, key, uid)
329
329
330 def _make_dict_for_settings(self, qs):
330 def _make_dict_for_settings(self, qs):
331 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
331 prefix_match = self._get_keyname('pat', '', 'rhodecode_')
332
332
333 issuetracker_entries = {}
333 issuetracker_entries = {}
334 # create keys
334 # create keys
335 for k, v in qs.items():
335 for k, v in qs.items():
336 if k.startswith(prefix_match):
336 if k.startswith(prefix_match):
337 uid = k[len(prefix_match):]
337 uid = k[len(prefix_match):]
338 issuetracker_entries[uid] = None
338 issuetracker_entries[uid] = None
339
339
340 # populate
340 # populate
341 for uid in issuetracker_entries:
341 for uid in issuetracker_entries:
342 issuetracker_entries[uid] = AttributeDict({
342 issuetracker_entries[uid] = AttributeDict({
343 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
343 'pat': qs.get(self._get_keyname('pat', uid, 'rhodecode_')),
344 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
344 'url': qs.get(self._get_keyname('url', uid, 'rhodecode_')),
345 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
345 'pref': qs.get(self._get_keyname('pref', uid, 'rhodecode_')),
346 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
346 'desc': qs.get(self._get_keyname('desc', uid, 'rhodecode_')),
347 })
347 })
348 return issuetracker_entries
348 return issuetracker_entries
349
349
350 def get_global_settings(self, cache=False):
350 def get_global_settings(self, cache=False):
351 """
351 """
352 Returns list of global issue tracker settings
352 Returns list of global issue tracker settings
353 """
353 """
354 defaults = self.global_settings.get_all_settings(cache=cache)
354 defaults = self.global_settings.get_all_settings(cache=cache)
355 settings = self._make_dict_for_settings(defaults)
355 settings = self._make_dict_for_settings(defaults)
356 return settings
356 return settings
357
357
358 def get_repo_settings(self, cache=False):
358 def get_repo_settings(self, cache=False):
359 """
359 """
360 Returns list of issue tracker settings per repository
360 Returns list of issue tracker settings per repository
361 """
361 """
362 if not self.repo_settings:
362 if not self.repo_settings:
363 raise Exception('Repository is not specified')
363 raise Exception('Repository is not specified')
364 all_settings = self.repo_settings.get_all_settings(cache=cache)
364 all_settings = self.repo_settings.get_all_settings(cache=cache)
365 settings = self._make_dict_for_settings(all_settings)
365 settings = self._make_dict_for_settings(all_settings)
366 return settings
366 return settings
367
367
368 def get_settings(self, cache=False):
368 def get_settings(self, cache=False):
369 if self.inherit_global_settings:
369 if self.inherit_global_settings:
370 return self.get_global_settings(cache=cache)
370 return self.get_global_settings(cache=cache)
371 else:
371 else:
372 return self.get_repo_settings(cache=cache)
372 return self.get_repo_settings(cache=cache)
373
373
374 def delete_entries(self, uid):
374 def delete_entries(self, uid):
375 if self.repo_settings:
375 if self.repo_settings:
376 all_patterns = self.get_repo_settings()
376 all_patterns = self.get_repo_settings()
377 settings_model = self.repo_settings
377 settings_model = self.repo_settings
378 else:
378 else:
379 all_patterns = self.get_global_settings()
379 all_patterns = self.get_global_settings()
380 settings_model = self.global_settings
380 settings_model = self.global_settings
381 entries = all_patterns.get(uid)
381 entries = all_patterns.get(uid)
382
382
383 for del_key in entries:
383 for del_key in entries:
384 setting_name = self._get_keyname(del_key, uid)
384 setting_name = self._get_keyname(del_key, uid)
385 entry = settings_model.get_setting_by_name(setting_name)
385 entry = settings_model.get_setting_by_name(setting_name)
386 if entry:
386 if entry:
387 Session().delete(entry)
387 Session().delete(entry)
388
388
389 Session().commit()
389 Session().commit()
390
390
391 def create_or_update_setting(
391 def create_or_update_setting(
392 self, name, val=Optional(''), type_=Optional('unicode')):
392 self, name, val=Optional(''), type_=Optional('unicode')):
393 if self.repo_settings:
393 if self.repo_settings:
394 setting = self.repo_settings.create_or_update_setting(
394 setting = self.repo_settings.create_or_update_setting(
395 name, val, type_)
395 name, val, type_)
396 else:
396 else:
397 setting = self.global_settings.create_or_update_setting(
397 setting = self.global_settings.create_or_update_setting(
398 name, val, type_)
398 name, val, type_)
399 return setting
399 return setting
400
400
401
401
402 class VcsSettingsModel(object):
402 class VcsSettingsModel(object):
403
403
404 INHERIT_SETTINGS = 'inherit_vcs_settings'
404 INHERIT_SETTINGS = 'inherit_vcs_settings'
405 GENERAL_SETTINGS = (
405 GENERAL_SETTINGS = (
406 'use_outdated_comments',
406 'use_outdated_comments',
407 'pr_merge_enabled',
407 'pr_merge_enabled',
408 'hg_use_rebase_for_merging')
408 'hg_use_rebase_for_merging')
409
409
410 HOOKS_SETTINGS = (
410 HOOKS_SETTINGS = (
411 ('hooks', 'changegroup.repo_size'),
411 ('hooks', 'changegroup.repo_size'),
412 ('hooks', 'changegroup.push_logger'),
412 ('hooks', 'changegroup.push_logger'),
413 ('hooks', 'outgoing.pull_logger'))
413 ('hooks', 'outgoing.pull_logger'),)
414 HG_SETTINGS = (
414 HG_SETTINGS = (
415 ('extensions', 'largefiles'),
415 ('extensions', 'largefiles'),
416 ('phases', 'publish'))
416 ('phases', 'publish'),)
417 GIT_SETTINGS = (
418 ('vcs_git_lfs', 'enabled'),)
419
417 GLOBAL_HG_SETTINGS = (
420 GLOBAL_HG_SETTINGS = (
418 ('extensions', 'largefiles'),
421 ('extensions', 'largefiles'),
419 ('largefiles', 'usercache'),
422 ('largefiles', 'usercache'),
420 ('phases', 'publish'),
423 ('phases', 'publish'),
421 ('extensions', 'hgsubversion'))
424 ('extensions', 'hgsubversion'))
425 GLOBAL_GIT_SETTINGS = (
426 ('vcs_git_lfs', 'enabled'),
427 ('vcs_git_lfs', 'store_location'))
422 GLOBAL_SVN_SETTINGS = (
428 GLOBAL_SVN_SETTINGS = (
423 ('vcs_svn_proxy', 'http_requests_enabled'),
429 ('vcs_svn_proxy', 'http_requests_enabled'),
424 ('vcs_svn_proxy', 'http_server_url'))
430 ('vcs_svn_proxy', 'http_server_url'))
425
431
426 SVN_BRANCH_SECTION = 'vcs_svn_branch'
432 SVN_BRANCH_SECTION = 'vcs_svn_branch'
427 SVN_TAG_SECTION = 'vcs_svn_tag'
433 SVN_TAG_SECTION = 'vcs_svn_tag'
428 SSL_SETTING = ('web', 'push_ssl')
434 SSL_SETTING = ('web', 'push_ssl')
429 PATH_SETTING = ('paths', '/')
435 PATH_SETTING = ('paths', '/')
430
436
431 def __init__(self, sa=None, repo=None):
437 def __init__(self, sa=None, repo=None):
432 self.global_settings = SettingsModel(sa=sa)
438 self.global_settings = SettingsModel(sa=sa)
433 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
439 self.repo_settings = SettingsModel(sa=sa, repo=repo) if repo else None
434 self._ui_settings = self.HG_SETTINGS + self.HOOKS_SETTINGS
440 self._ui_settings = (
441 self.HG_SETTINGS + self.GIT_SETTINGS + self.HOOKS_SETTINGS)
435 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
442 self._svn_sections = (self.SVN_BRANCH_SECTION, self.SVN_TAG_SECTION)
436
443
437 @property
444 @property
438 @assert_repo_settings
445 @assert_repo_settings
439 def inherit_global_settings(self):
446 def inherit_global_settings(self):
440 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
447 setting = self.repo_settings.get_setting_by_name(self.INHERIT_SETTINGS)
441 return setting.app_settings_value if setting else True
448 return setting.app_settings_value if setting else True
442
449
443 @inherit_global_settings.setter
450 @inherit_global_settings.setter
444 @assert_repo_settings
451 @assert_repo_settings
445 def inherit_global_settings(self, value):
452 def inherit_global_settings(self, value):
446 self.repo_settings.create_or_update_setting(
453 self.repo_settings.create_or_update_setting(
447 self.INHERIT_SETTINGS, value, type_='bool')
454 self.INHERIT_SETTINGS, value, type_='bool')
448
455
449 def get_global_svn_branch_patterns(self):
456 def get_global_svn_branch_patterns(self):
450 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
457 return self.global_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
451
458
452 @assert_repo_settings
459 @assert_repo_settings
453 def get_repo_svn_branch_patterns(self):
460 def get_repo_svn_branch_patterns(self):
454 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
461 return self.repo_settings.get_ui_by_section(self.SVN_BRANCH_SECTION)
455
462
456 def get_global_svn_tag_patterns(self):
463 def get_global_svn_tag_patterns(self):
457 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
464 return self.global_settings.get_ui_by_section(self.SVN_TAG_SECTION)
458
465
459 @assert_repo_settings
466 @assert_repo_settings
460 def get_repo_svn_tag_patterns(self):
467 def get_repo_svn_tag_patterns(self):
461 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
468 return self.repo_settings.get_ui_by_section(self.SVN_TAG_SECTION)
462
469
463 def get_global_settings(self):
470 def get_global_settings(self):
464 return self._collect_all_settings(global_=True)
471 return self._collect_all_settings(global_=True)
465
472
466 @assert_repo_settings
473 @assert_repo_settings
467 def get_repo_settings(self):
474 def get_repo_settings(self):
468 return self._collect_all_settings(global_=False)
475 return self._collect_all_settings(global_=False)
469
476
470 @assert_repo_settings
477 @assert_repo_settings
471 def create_or_update_repo_settings(
478 def create_or_update_repo_settings(
472 self, data, inherit_global_settings=False):
479 self, data, inherit_global_settings=False):
473 from rhodecode.model.scm import ScmModel
480 from rhodecode.model.scm import ScmModel
474
481
475 self.inherit_global_settings = inherit_global_settings
482 self.inherit_global_settings = inherit_global_settings
476
483
477 repo = self.repo_settings.get_repo()
484 repo = self.repo_settings.get_repo()
478 if not inherit_global_settings:
485 if not inherit_global_settings:
479 if repo.repo_type == 'svn':
486 if repo.repo_type == 'svn':
480 self.create_repo_svn_settings(data)
487 self.create_repo_svn_settings(data)
481 else:
488 else:
482 self.create_or_update_repo_hook_settings(data)
489 self.create_or_update_repo_hook_settings(data)
483 self.create_or_update_repo_pr_settings(data)
490 self.create_or_update_repo_pr_settings(data)
484
491
485 if repo.repo_type == 'hg':
492 if repo.repo_type == 'hg':
486 self.create_or_update_repo_hg_settings(data)
493 self.create_or_update_repo_hg_settings(data)
487
494
495 if repo.repo_type == 'git':
496 self.create_or_update_repo_git_settings(data)
497
488 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
498 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
489
499
490 @assert_repo_settings
500 @assert_repo_settings
491 def create_or_update_repo_hook_settings(self, data):
501 def create_or_update_repo_hook_settings(self, data):
492 for section, key in self.HOOKS_SETTINGS:
502 for section, key in self.HOOKS_SETTINGS:
493 data_key = self._get_form_ui_key(section, key)
503 data_key = self._get_form_ui_key(section, key)
494 if data_key not in data:
504 if data_key not in data:
495 raise ValueError(
505 raise ValueError(
496 'The given data does not contain {} key'.format(data_key))
506 'The given data does not contain {} key'.format(data_key))
497
507
498 active = data.get(data_key)
508 active = data.get(data_key)
499 repo_setting = self.repo_settings.get_ui_by_section_and_key(
509 repo_setting = self.repo_settings.get_ui_by_section_and_key(
500 section, key)
510 section, key)
501 if not repo_setting:
511 if not repo_setting:
502 global_setting = self.global_settings.\
512 global_setting = self.global_settings.\
503 get_ui_by_section_and_key(section, key)
513 get_ui_by_section_and_key(section, key)
504 self.repo_settings.create_ui_section_value(
514 self.repo_settings.create_ui_section_value(
505 section, global_setting.ui_value, key=key, active=active)
515 section, global_setting.ui_value, key=key, active=active)
506 else:
516 else:
507 repo_setting.ui_active = active
517 repo_setting.ui_active = active
508 Session().add(repo_setting)
518 Session().add(repo_setting)
509
519
510 def update_global_hook_settings(self, data):
520 def update_global_hook_settings(self, data):
511 for section, key in self.HOOKS_SETTINGS:
521 for section, key in self.HOOKS_SETTINGS:
512 data_key = self._get_form_ui_key(section, key)
522 data_key = self._get_form_ui_key(section, key)
513 if data_key not in data:
523 if data_key not in data:
514 raise ValueError(
524 raise ValueError(
515 'The given data does not contain {} key'.format(data_key))
525 'The given data does not contain {} key'.format(data_key))
516 active = data.get(data_key)
526 active = data.get(data_key)
517 repo_setting = self.global_settings.get_ui_by_section_and_key(
527 repo_setting = self.global_settings.get_ui_by_section_and_key(
518 section, key)
528 section, key)
519 repo_setting.ui_active = active
529 repo_setting.ui_active = active
520 Session().add(repo_setting)
530 Session().add(repo_setting)
521
531
522 @assert_repo_settings
532 @assert_repo_settings
523 def create_or_update_repo_pr_settings(self, data):
533 def create_or_update_repo_pr_settings(self, data):
524 return self._create_or_update_general_settings(
534 return self._create_or_update_general_settings(
525 self.repo_settings, data)
535 self.repo_settings, data)
526
536
527 def create_or_update_global_pr_settings(self, data):
537 def create_or_update_global_pr_settings(self, data):
528 return self._create_or_update_general_settings(
538 return self._create_or_update_general_settings(
529 self.global_settings, data)
539 self.global_settings, data)
530
540
531 @assert_repo_settings
541 @assert_repo_settings
532 def create_repo_svn_settings(self, data):
542 def create_repo_svn_settings(self, data):
533 return self._create_svn_settings(self.repo_settings, data)
543 return self._create_svn_settings(self.repo_settings, data)
534
544
535 @assert_repo_settings
545 @assert_repo_settings
536 def create_or_update_repo_hg_settings(self, data):
546 def create_or_update_repo_hg_settings(self, data):
537 largefiles, phases = self.HG_SETTINGS
547 largefiles, phases = \
538 largefiles_key, phases_key = self._get_settings_keys(
548 self.HG_SETTINGS
539 self.HG_SETTINGS, data)
549 largefiles_key, phases_key = \
550 self._get_settings_keys(self.HG_SETTINGS, data)
551
540 self._create_or_update_ui(
552 self._create_or_update_ui(
541 self.repo_settings, *largefiles, value='',
553 self.repo_settings, *largefiles, value='',
542 active=data[largefiles_key])
554 active=data[largefiles_key])
543 self._create_or_update_ui(
555 self._create_or_update_ui(
544 self.repo_settings, *phases, value=safe_str(data[phases_key]))
556 self.repo_settings, *phases, value=safe_str(data[phases_key]))
545
557
546 def create_or_update_global_hg_settings(self, data):
558 def create_or_update_global_hg_settings(self, data):
547 largefiles, largefiles_store, phases, hgsubversion \
559 largefiles, largefiles_store, phases, hgsubversion \
548 = self.GLOBAL_HG_SETTINGS
560 = self.GLOBAL_HG_SETTINGS
549 largefiles_key, largefiles_store_key, phases_key, subversion_key \
561 largefiles_key, largefiles_store_key, phases_key, subversion_key \
550 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS, data)
562 = self._get_settings_keys(self.GLOBAL_HG_SETTINGS, data)
551
552 self._create_or_update_ui(
563 self._create_or_update_ui(
553 self.global_settings, *largefiles, value='',
564 self.global_settings, *largefiles, value='',
554 active=data[largefiles_key])
565 active=data[largefiles_key])
555 self._create_or_update_ui(
566 self._create_or_update_ui(
556 self.global_settings, *largefiles_store,
567 self.global_settings, *largefiles_store,
557 value=data[largefiles_store_key])
568 value=data[largefiles_store_key])
558 self._create_or_update_ui(
569 self._create_or_update_ui(
559 self.global_settings, *phases, value=safe_str(data[phases_key]))
570 self.global_settings, *phases, value=safe_str(data[phases_key]))
560 self._create_or_update_ui(
571 self._create_or_update_ui(
561 self.global_settings, *hgsubversion, active=data[subversion_key])
572 self.global_settings, *hgsubversion, active=data[subversion_key])
562
573
574 def create_or_update_repo_git_settings(self, data):
575 # NOTE(marcink): # comma make unpack work properly
576 lfs_enabled, \
577 = self.GIT_SETTINGS
578
579 lfs_enabled_key, \
580 = self._get_settings_keys(self.GIT_SETTINGS, data)
581
582 self._create_or_update_ui(
583 self.repo_settings, *lfs_enabled, value=data[lfs_enabled_key],
584 active=data[lfs_enabled_key])
585
586 def create_or_update_global_git_settings(self, data):
587 lfs_enabled, lfs_store_location \
588 = self.GLOBAL_GIT_SETTINGS
589 lfs_enabled_key, lfs_store_location_key \
590 = self._get_settings_keys(self.GLOBAL_GIT_SETTINGS, data)
591
592 self._create_or_update_ui(
593 self.global_settings, *lfs_enabled, value=data[lfs_enabled_key],
594 active=data[lfs_enabled_key])
595 self._create_or_update_ui(
596 self.global_settings, *lfs_store_location,
597 value=data[lfs_store_location_key])
598
563 def create_or_update_global_svn_settings(self, data):
599 def create_or_update_global_svn_settings(self, data):
564 # branch/tags patterns
600 # branch/tags patterns
565 self._create_svn_settings(self.global_settings, data)
601 self._create_svn_settings(self.global_settings, data)
566
602
567 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
603 http_requests_enabled, http_server_url = self.GLOBAL_SVN_SETTINGS
568 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
604 http_requests_enabled_key, http_server_url_key = self._get_settings_keys(
569 self.GLOBAL_SVN_SETTINGS, data)
605 self.GLOBAL_SVN_SETTINGS, data)
570
606
571 self._create_or_update_ui(
607 self._create_or_update_ui(
572 self.global_settings, *http_requests_enabled,
608 self.global_settings, *http_requests_enabled,
573 value=safe_str(data[http_requests_enabled_key]))
609 value=safe_str(data[http_requests_enabled_key]))
574 self._create_or_update_ui(
610 self._create_or_update_ui(
575 self.global_settings, *http_server_url,
611 self.global_settings, *http_server_url,
576 value=data[http_server_url_key])
612 value=data[http_server_url_key])
577
613
578 def update_global_ssl_setting(self, value):
614 def update_global_ssl_setting(self, value):
579 self._create_or_update_ui(
615 self._create_or_update_ui(
580 self.global_settings, *self.SSL_SETTING, value=value)
616 self.global_settings, *self.SSL_SETTING, value=value)
581
617
582 def update_global_path_setting(self, value):
618 def update_global_path_setting(self, value):
583 self._create_or_update_ui(
619 self._create_or_update_ui(
584 self.global_settings, *self.PATH_SETTING, value=value)
620 self.global_settings, *self.PATH_SETTING, value=value)
585
621
586 @assert_repo_settings
622 @assert_repo_settings
587 def delete_repo_svn_pattern(self, id_):
623 def delete_repo_svn_pattern(self, id_):
588 self.repo_settings.delete_ui(id_)
624 self.repo_settings.delete_ui(id_)
589
625
590 def delete_global_svn_pattern(self, id_):
626 def delete_global_svn_pattern(self, id_):
591 self.global_settings.delete_ui(id_)
627 self.global_settings.delete_ui(id_)
592
628
593 @assert_repo_settings
629 @assert_repo_settings
594 def get_repo_ui_settings(self, section=None, key=None):
630 def get_repo_ui_settings(self, section=None, key=None):
595 global_uis = self.global_settings.get_ui(section, key)
631 global_uis = self.global_settings.get_ui(section, key)
596 repo_uis = self.repo_settings.get_ui(section, key)
632 repo_uis = self.repo_settings.get_ui(section, key)
597 filtered_repo_uis = self._filter_ui_settings(repo_uis)
633 filtered_repo_uis = self._filter_ui_settings(repo_uis)
598 filtered_repo_uis_keys = [
634 filtered_repo_uis_keys = [
599 (s.section, s.key) for s in filtered_repo_uis]
635 (s.section, s.key) for s in filtered_repo_uis]
600
636
601 def _is_global_ui_filtered(ui):
637 def _is_global_ui_filtered(ui):
602 return (
638 return (
603 (ui.section, ui.key) in filtered_repo_uis_keys
639 (ui.section, ui.key) in filtered_repo_uis_keys
604 or ui.section in self._svn_sections)
640 or ui.section in self._svn_sections)
605
641
606 filtered_global_uis = [
642 filtered_global_uis = [
607 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
643 ui for ui in global_uis if not _is_global_ui_filtered(ui)]
608
644
609 return filtered_global_uis + filtered_repo_uis
645 return filtered_global_uis + filtered_repo_uis
610
646
611 def get_global_ui_settings(self, section=None, key=None):
647 def get_global_ui_settings(self, section=None, key=None):
612 return self.global_settings.get_ui(section, key)
648 return self.global_settings.get_ui(section, key)
613
649
614 def get_ui_settings_as_config_obj(self, section=None, key=None):
650 def get_ui_settings_as_config_obj(self, section=None, key=None):
615 config = base.Config()
651 config = base.Config()
616
652
617 ui_settings = self.get_ui_settings(section=section, key=key)
653 ui_settings = self.get_ui_settings(section=section, key=key)
618
654
619 for entry in ui_settings:
655 for entry in ui_settings:
620 config.set(entry.section, entry.key, entry.value)
656 config.set(entry.section, entry.key, entry.value)
621
657
622 return config
658 return config
623
659
624 def get_ui_settings(self, section=None, key=None):
660 def get_ui_settings(self, section=None, key=None):
625 if not self.repo_settings or self.inherit_global_settings:
661 if not self.repo_settings or self.inherit_global_settings:
626 return self.get_global_ui_settings(section, key)
662 return self.get_global_ui_settings(section, key)
627 else:
663 else:
628 return self.get_repo_ui_settings(section, key)
664 return self.get_repo_ui_settings(section, key)
629
665
630 def get_svn_patterns(self, section=None):
666 def get_svn_patterns(self, section=None):
631 if not self.repo_settings:
667 if not self.repo_settings:
632 return self.get_global_ui_settings(section)
668 return self.get_global_ui_settings(section)
633 else:
669 else:
634 return self.get_repo_ui_settings(section)
670 return self.get_repo_ui_settings(section)
635
671
636 @assert_repo_settings
672 @assert_repo_settings
637 def get_repo_general_settings(self):
673 def get_repo_general_settings(self):
638 global_settings = self.global_settings.get_all_settings()
674 global_settings = self.global_settings.get_all_settings()
639 repo_settings = self.repo_settings.get_all_settings()
675 repo_settings = self.repo_settings.get_all_settings()
640 filtered_repo_settings = self._filter_general_settings(repo_settings)
676 filtered_repo_settings = self._filter_general_settings(repo_settings)
641 global_settings.update(filtered_repo_settings)
677 global_settings.update(filtered_repo_settings)
642 return global_settings
678 return global_settings
643
679
644 def get_global_general_settings(self):
680 def get_global_general_settings(self):
645 return self.global_settings.get_all_settings()
681 return self.global_settings.get_all_settings()
646
682
647 def get_general_settings(self):
683 def get_general_settings(self):
648 if not self.repo_settings or self.inherit_global_settings:
684 if not self.repo_settings or self.inherit_global_settings:
649 return self.get_global_general_settings()
685 return self.get_global_general_settings()
650 else:
686 else:
651 return self.get_repo_general_settings()
687 return self.get_repo_general_settings()
652
688
653 def get_repos_location(self):
689 def get_repos_location(self):
654 return self.global_settings.get_ui_by_key('/').ui_value
690 return self.global_settings.get_ui_by_key('/').ui_value
655
691
656 def _filter_ui_settings(self, settings):
692 def _filter_ui_settings(self, settings):
657 filtered_settings = [
693 filtered_settings = [
658 s for s in settings if self._should_keep_setting(s)]
694 s for s in settings if self._should_keep_setting(s)]
659 return filtered_settings
695 return filtered_settings
660
696
661 def _should_keep_setting(self, setting):
697 def _should_keep_setting(self, setting):
662 keep = (
698 keep = (
663 (setting.section, setting.key) in self._ui_settings or
699 (setting.section, setting.key) in self._ui_settings or
664 setting.section in self._svn_sections)
700 setting.section in self._svn_sections)
665 return keep
701 return keep
666
702
667 def _filter_general_settings(self, settings):
703 def _filter_general_settings(self, settings):
668 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
704 keys = ['rhodecode_{}'.format(key) for key in self.GENERAL_SETTINGS]
669 return {
705 return {
670 k: settings[k]
706 k: settings[k]
671 for k in settings if k in keys}
707 for k in settings if k in keys}
672
708
673 def _collect_all_settings(self, global_=False):
709 def _collect_all_settings(self, global_=False):
674 settings = self.global_settings if global_ else self.repo_settings
710 settings = self.global_settings if global_ else self.repo_settings
675 result = {}
711 result = {}
676
712
677 for section, key in self._ui_settings:
713 for section, key in self._ui_settings:
678 ui = settings.get_ui_by_section_and_key(section, key)
714 ui = settings.get_ui_by_section_and_key(section, key)
679 result_key = self._get_form_ui_key(section, key)
715 result_key = self._get_form_ui_key(section, key)
716
680 if ui:
717 if ui:
681 if section in ('hooks', 'extensions'):
718 if section in ('hooks', 'extensions'):
682 result[result_key] = ui.ui_active
719 result[result_key] = ui.ui_active
720 elif result_key in ['vcs_git_lfs_enabled']:
721 result[result_key] = ui.ui_active
683 else:
722 else:
684 result[result_key] = ui.ui_value
723 result[result_key] = ui.ui_value
685
724
686 for name in self.GENERAL_SETTINGS:
725 for name in self.GENERAL_SETTINGS:
687 setting = settings.get_setting_by_name(name)
726 setting = settings.get_setting_by_name(name)
688 if setting:
727 if setting:
689 result_key = 'rhodecode_{}'.format(name)
728 result_key = 'rhodecode_{}'.format(name)
690 result[result_key] = setting.app_settings_value
729 result[result_key] = setting.app_settings_value
691
730
692 return result
731 return result
693
732
694 def _get_form_ui_key(self, section, key):
733 def _get_form_ui_key(self, section, key):
695 return '{section}_{key}'.format(
734 return '{section}_{key}'.format(
696 section=section, key=key.replace('.', '_'))
735 section=section, key=key.replace('.', '_'))
697
736
698 def _create_or_update_ui(
737 def _create_or_update_ui(
699 self, settings, section, key, value=None, active=None):
738 self, settings, section, key, value=None, active=None):
700 ui = settings.get_ui_by_section_and_key(section, key)
739 ui = settings.get_ui_by_section_and_key(section, key)
701 if not ui:
740 if not ui:
702 active = True if active is None else active
741 active = True if active is None else active
703 settings.create_ui_section_value(
742 settings.create_ui_section_value(
704 section, value, key=key, active=active)
743 section, value, key=key, active=active)
705 else:
744 else:
706 if active is not None:
745 if active is not None:
707 ui.ui_active = active
746 ui.ui_active = active
708 if value is not None:
747 if value is not None:
709 ui.ui_value = value
748 ui.ui_value = value
710 Session().add(ui)
749 Session().add(ui)
711
750
712 def _create_svn_settings(self, settings, data):
751 def _create_svn_settings(self, settings, data):
713 svn_settings = {
752 svn_settings = {
714 'new_svn_branch': self.SVN_BRANCH_SECTION,
753 'new_svn_branch': self.SVN_BRANCH_SECTION,
715 'new_svn_tag': self.SVN_TAG_SECTION
754 'new_svn_tag': self.SVN_TAG_SECTION
716 }
755 }
717 for key in svn_settings:
756 for key in svn_settings:
718 if data.get(key):
757 if data.get(key):
719 settings.create_ui_section_value(svn_settings[key], data[key])
758 settings.create_ui_section_value(svn_settings[key], data[key])
720
759
721 def _create_or_update_general_settings(self, settings, data):
760 def _create_or_update_general_settings(self, settings, data):
722 for name in self.GENERAL_SETTINGS:
761 for name in self.GENERAL_SETTINGS:
723 data_key = 'rhodecode_{}'.format(name)
762 data_key = 'rhodecode_{}'.format(name)
724 if data_key not in data:
763 if data_key not in data:
725 raise ValueError(
764 raise ValueError(
726 'The given data does not contain {} key'.format(data_key))
765 'The given data does not contain {} key'.format(data_key))
727 setting = settings.create_or_update_setting(
766 setting = settings.create_or_update_setting(
728 name, data[data_key], 'bool')
767 name, data[data_key], 'bool')
729 Session().add(setting)
768 Session().add(setting)
730
769
731 def _get_settings_keys(self, settings, data):
770 def _get_settings_keys(self, settings, data):
732 data_keys = [self._get_form_ui_key(*s) for s in settings]
771 data_keys = [self._get_form_ui_key(*s) for s in settings]
733 for data_key in data_keys:
772 for data_key in data_keys:
734 if data_key not in data:
773 if data_key not in data:
735 raise ValueError(
774 raise ValueError(
736 'The given data does not contain {} key'.format(data_key))
775 'The given data does not contain {} key'.format(data_key))
737 return data_keys
776 return data_keys
@@ -1,291 +1,324 b''
1 ## snippet for displaying vcs settings
1 ## snippet for displaying vcs settings
2 ## usage:
2 ## usage:
3 ## <%namespace name="vcss" file="/base/vcssettings.mako"/>
3 ## <%namespace name="vcss" file="/base/vcssettings.mako"/>
4 ## ${vcss.vcs_settings_fields()}
4 ## ${vcss.vcs_settings_fields()}
5
5
6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)">
6 <%def name="vcs_settings_fields(suffix='', svn_branch_patterns=None, svn_tag_patterns=None, repo_type=None, display_globals=False, allow_repo_location_change=False, **kwargs)">
7 % if display_globals:
7 % if display_globals:
8 <div class="panel panel-default">
8 <div class="panel panel-default">
9 <div class="panel-heading" id="general">
9 <div class="panel-heading" id="general">
10 <h3 class="panel-title">${_('General')}</h3>
10 <h3 class="panel-title">${_('General')}</h3>
11 </div>
11 </div>
12 <div class="panel-body">
12 <div class="panel-body">
13 <div class="field">
13 <div class="field">
14 <div class="checkbox">
14 <div class="checkbox">
15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
15 ${h.checkbox('web_push_ssl' + suffix, 'True')}
16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
16 <label for="web_push_ssl${suffix}">${_('Require SSL for vcs operations')}</label>
17 </div>
17 </div>
18 <div class="label">
18 <div class="label">
19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
19 <span class="help-block">${_('Activate to set RhodeCode to require SSL for pushing or pulling. If SSL certificate is missing it will return a HTTP Error 406: Not Acceptable.')}</span>
20 </div>
20 </div>
21 </div>
21 </div>
22 </div>
22 </div>
23 </div>
23 </div>
24 % endif
24 % endif
25
25
26 % if display_globals:
26 % if display_globals:
27 <div class="panel panel-default">
27 <div class="panel panel-default">
28 <div class="panel-heading">
28 <div class="panel-heading">
29 <h3 class="panel-title">${_('Main Storage Location')}</h3>
29 <h3 class="panel-title">${_('Main Storage Location')}</h3>
30 </div>
30 </div>
31 <div class="panel-body">
31 <div class="panel-body">
32 <div class="field">
32 <div class="field">
33 <div class="inputx locked_input">
33 <div class="inputx locked_input">
34 %if allow_repo_location_change:
34 %if allow_repo_location_change:
35 ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")}
35 ${h.text('paths_root_path',size=59,readonly="readonly", class_="disabled")}
36 <span id="path_unlock" class="tooltip"
36 <span id="path_unlock" class="tooltip"
37 title="${h.tooltip(_('Click to unlock. You must restart RhodeCode in order to make this setting take effect.'))}">
37 title="${h.tooltip(_('Click to unlock. You must restart RhodeCode in order to make this setting take effect.'))}">
38 <div class="btn btn-default lock_input_button"><i id="path_unlock_icon" class="icon-lock"></i></div>
38 <div class="btn btn-default lock_input_button"><i id="path_unlock_icon" class="icon-lock"></i></div>
39 </span>
39 </span>
40 %else:
40 %else:
41 ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')}
41 ${_('Repository location change is disabled. You can enable this by changing the `allow_repo_location_change` inside .ini file.')}
42 ## form still requires this but we cannot internally change it anyway
42 ## form still requires this but we cannot internally change it anyway
43 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
43 ${h.hidden('paths_root_path',size=30,readonly="readonly", class_="disabled")}
44 %endif
44 %endif
45 </div>
45 </div>
46 </div>
46 </div>
47 <div class="label">
47 <div class="label">
48 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
48 <span class="help-block">${_('Filesystem location where repositories should be stored. After changing this value a restart and rescan of the repository folder are required.')}</span>
49 </div>
49 </div>
50 </div>
50 </div>
51 </div>
51 </div>
52 % endif
52 % endif
53
53
54 % if display_globals or repo_type in ['git', 'hg']:
54 % if display_globals or repo_type in ['git', 'hg']:
55 <div class="panel panel-default">
55 <div class="panel panel-default">
56 <div class="panel-heading" id="general">
56 <div class="panel-heading" id="general">
57 <h3 class="panel-title">${_('Internal Hooks')}</h3>
57 <h3 class="panel-title">${_('Internal Hooks')}</h3>
58 </div>
58 </div>
59 <div class="panel-body">
59 <div class="panel-body">
60 <div class="field">
60 <div class="field">
61 <div class="checkbox">
61 <div class="checkbox">
62 ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)}
62 ${h.checkbox('hooks_changegroup_repo_size' + suffix, 'True', **kwargs)}
63 <label for="hooks_changegroup_repo_size${suffix}">${_('Show repository size after push')}</label>
63 <label for="hooks_changegroup_repo_size${suffix}">${_('Show repository size after push')}</label>
64 </div>
64 </div>
65
65
66 <div class="label">
66 <div class="label">
67 <span class="help-block">${_('Trigger a hook that calculates repository size after each push.')}</span>
67 <span class="help-block">${_('Trigger a hook that calculates repository size after each push.')}</span>
68 </div>
68 </div>
69 <div class="checkbox">
69 <div class="checkbox">
70 ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)}
70 ${h.checkbox('hooks_changegroup_push_logger' + suffix, 'True', **kwargs)}
71 <label for="hooks_changegroup_push_logger${suffix}">${_('Execute pre/post push hooks')}</label>
71 <label for="hooks_changegroup_push_logger${suffix}">${_('Execute pre/post push hooks')}</label>
72 </div>
72 </div>
73 <div class="label">
73 <div class="label">
74 <span class="help-block">${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')}</span>
74 <span class="help-block">${_('Execute Built in pre/post push hooks. This also executes rcextensions hooks.')}</span>
75 </div>
75 </div>
76 <div class="checkbox">
76 <div class="checkbox">
77 ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)}
77 ${h.checkbox('hooks_outgoing_pull_logger' + suffix, 'True', **kwargs)}
78 <label for="hooks_outgoing_pull_logger${suffix}">${_('Execute pre/post pull hooks')}</label>
78 <label for="hooks_outgoing_pull_logger${suffix}">${_('Execute pre/post pull hooks')}</label>
79 </div>
79 </div>
80 <div class="label">
80 <div class="label">
81 <span class="help-block">${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')}</span>
81 <span class="help-block">${_('Execute Built in pre/post pull hooks. This also executes rcextensions hooks.')}</span>
82 </div>
82 </div>
83 </div>
83 </div>
84 </div>
84 </div>
85 </div>
85 </div>
86 % endif
86 % endif
87
87
88 % if display_globals or repo_type in ['hg']:
88 % if display_globals or repo_type in ['hg']:
89 <div class="panel panel-default">
89 <div class="panel panel-default">
90 <div class="panel-heading">
90 <div class="panel-heading">
91 <h3 class="panel-title">${_('Mercurial Settings')}</h3>
91 <h3 class="panel-title">${_('Mercurial Settings')}</h3>
92 </div>
92 </div>
93 <div class="panel-body">
93 <div class="panel-body">
94 <div class="checkbox">
94 <div class="checkbox">
95 ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)}
95 ${h.checkbox('extensions_largefiles' + suffix, 'True', **kwargs)}
96 <label for="extensions_largefiles${suffix}">${_('Enable largefiles extension')}</label>
96 <label for="extensions_largefiles${suffix}">${_('Enable largefiles extension')}</label>
97 </div>
97 </div>
98 <div class="label">
98 <div class="label">
99 % if display_globals:
99 % if display_globals:
100 <span class="help-block">${_('Enable Largefiles extensions for all repositories.')}</span>
100 <span class="help-block">${_('Enable Largefiles extensions for all repositories.')}</span>
101 % else:
101 % else:
102 <span class="help-block">${_('Enable Largefiles extensions for this repository.')}</span>
102 <span class="help-block">${_('Enable Largefiles extensions for this repository.')}</span>
103 % endif
103 % endif
104 </div>
104 </div>
105
105
106 % if display_globals:
106 % if display_globals:
107 <div class="field">
107 <div class="field">
108 <div class="input">
108 <div class="input">
109 ${h.text('largefiles_usercache' + suffix, size=59)}
109 ${h.text('largefiles_usercache' + suffix, size=59)}
110 </div>
110 </div>
111 </div>
111 </div>
112 <div class="label">
112 <div class="label">
113 <span class="help-block">${_('Filesystem location where Mercurial largefile objects should be stored.')}</span>
113 <span class="help-block">${_('Filesystem location where Mercurial largefile objects should be stored.')}</span>
114 </div>
114 </div>
115 % endif
115 % endif
116
116
117 <div class="checkbox">
117 <div class="checkbox">
118 ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)}
118 ${h.checkbox('phases_publish' + suffix, 'True', **kwargs)}
119 <label for="phases_publish${suffix}">${_('Set repositories as publishing') if display_globals else _('Set repository as publishing')}</label>
119 <label for="phases_publish${suffix}">${_('Set repositories as publishing') if display_globals else _('Set repository as publishing')}</label>
120 </div>
120 </div>
121 <div class="label">
121 <div class="label">
122 <span class="help-block">${_('When this is enabled all commits in the repository are seen as public commits by clients.')}</span>
122 <span class="help-block">${_('When this is enabled all commits in the repository are seen as public commits by clients.')}</span>
123 </div>
123 </div>
124 % if display_globals:
124 % if display_globals:
125 <div class="checkbox">
125 <div class="checkbox">
126 ${h.checkbox('extensions_hgsubversion' + suffix,'True')}
126 ${h.checkbox('extensions_hgsubversion' + suffix,'True')}
127 <label for="extensions_hgsubversion${suffix}">${_('Enable hgsubversion extension')}</label>
127 <label for="extensions_hgsubversion${suffix}">${_('Enable hgsubversion extension')}</label>
128 </div>
128 </div>
129 <div class="label">
129 <div class="label">
130 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
130 <span class="help-block">${_('Requires hgsubversion library to be installed. Allows cloning remote SVN repositories and migrates them to Mercurial type.')}</span>
131 </div>
131 </div>
132 % endif
132 % endif
133 </div>
133 </div>
134 </div>
134 </div>
135 ## LABS for HG
135 ## LABS for HG
136 % if c.labs_active:
136 % if c.labs_active:
137 <div class="panel panel-danger">
137 <div class="panel panel-danger">
138 <div class="panel-heading">
138 <div class="panel-heading">
139 <h3 class="panel-title">${_('Mercurial Labs Settings')} (${_('These features are considered experimental and may not work as expected.')})</h3>
139 <h3 class="panel-title">${_('Mercurial Labs Settings')} (${_('These features are considered experimental and may not work as expected.')})</h3>
140 </div>
140 </div>
141 <div class="panel-body">
141 <div class="panel-body">
142
142
143 <div class="checkbox">
143 <div class="checkbox">
144 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
144 ${h.checkbox('rhodecode_hg_use_rebase_for_merging' + suffix, 'True', **kwargs)}
145 <label for="rhodecode_hg_use_rebase_for_merging${suffix}">${_('Use rebase as merge strategy')}</label>
145 <label for="rhodecode_hg_use_rebase_for_merging${suffix}">${_('Use rebase as merge strategy')}</label>
146 </div>
146 </div>
147 <div class="label">
147 <div class="label">
148 <span class="help-block">${_('Use rebase instead of creating a merge commit when merging via web interface.')}</span>
148 <span class="help-block">${_('Use rebase instead of creating a merge commit when merging via web interface.')}</span>
149 </div>
149 </div>
150
150
151 </div>
151 </div>
152 </div>
152 </div>
153 % endif
153 % endif
154
154
155 % endif
155 % endif
156
156
157 % if display_globals or repo_type in ['git']:
158 <div class="panel panel-default">
159 <div class="panel-heading">
160 <h3 class="panel-title">${_('Git Settings')}</h3>
161 </div>
162 <div class="panel-body">
163 <div class="checkbox">
164 ${h.checkbox('vcs_git_lfs_enabled' + suffix, 'True', **kwargs)}
165 <label for="vcs_git_lfs_enabled${suffix}">${_('Enable lfs extension')}</label>
166 </div>
167 <div class="label">
168 % if display_globals:
169 <span class="help-block">${_('Enable lfs extensions for all repositories.')}</span>
170 % else:
171 <span class="help-block">${_('Enable lfs extensions for this repository.')}</span>
172 % endif
173 </div>
174
175 % if display_globals:
176 <div class="field">
177 <div class="input">
178 ${h.text('vcs_git_lfs_store_location' + suffix, size=59)}
179 </div>
180 </div>
181 <div class="label">
182 <span class="help-block">${_('Filesystem location where Git lfs objects should be stored.')}</span>
183 </div>
184 % endif
185 </div>
186 </div>
187 % endif
188
189
157 % if display_globals:
190 % if display_globals:
158 <div class="panel panel-default">
191 <div class="panel panel-default">
159 <div class="panel-heading">
192 <div class="panel-heading">
160 <h3 class="panel-title">${_('Global Subversion Settings')}</h3>
193 <h3 class="panel-title">${_('Global Subversion Settings')}</h3>
161 </div>
194 </div>
162 <div class="panel-body">
195 <div class="panel-body">
163 <div class="field">
196 <div class="field">
164 <div class="checkbox">
197 <div class="checkbox">
165 ${h.checkbox('vcs_svn_proxy_http_requests_enabled' + suffix, 'True', **kwargs)}
198 ${h.checkbox('vcs_svn_proxy_http_requests_enabled' + suffix, 'True', **kwargs)}
166 <label for="vcs_svn_proxy_http_requests_enabled${suffix}">${_('Proxy subversion HTTP requests')}</label>
199 <label for="vcs_svn_proxy_http_requests_enabled${suffix}">${_('Proxy subversion HTTP requests')}</label>
167 </div>
200 </div>
168 <div class="label">
201 <div class="label">
169 <span class="help-block">
202 <span class="help-block">
170 ${_('Subversion HTTP Support. Enables communication with SVN over HTTP protocol.')}
203 ${_('Subversion HTTP Support. Enables communication with SVN over HTTP protocol.')}
171 <a href="${h.url('enterprise_svn_setup')}" target="_blank">${_('SVN Protocol setup Documentation')}</a>.
204 <a href="${h.url('enterprise_svn_setup')}" target="_blank">${_('SVN Protocol setup Documentation')}</a>.
172 </span>
205 </span>
173 </div>
206 </div>
174 </div>
207 </div>
175 <div class="field">
208 <div class="field">
176 <div class="label">
209 <div class="label">
177 <label for="vcs_svn_proxy_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
210 <label for="vcs_svn_proxy_http_server_url">${_('Subversion HTTP Server URL')}</label><br/>
178 </div>
211 </div>
179 <div class="input">
212 <div class="input">
180 ${h.text('vcs_svn_proxy_http_server_url',size=59)}
213 ${h.text('vcs_svn_proxy_http_server_url',size=59)}
181 % if c.svn_proxy_generate_config:
214 % if c.svn_proxy_generate_config:
182 <span class="buttons">
215 <span class="buttons">
183 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
216 <button class="btn btn-primary" id="vcs_svn_generate_cfg">${_('Generate Apache Config')}</button>
184 </span>
217 </span>
185 % endif
218 % endif
186 </div>
219 </div>
187 </div>
220 </div>
188 </div>
221 </div>
189 </div>
222 </div>
190 % endif
223 % endif
191
224
192 % if display_globals or repo_type in ['svn']:
225 % if display_globals or repo_type in ['svn']:
193 <div class="panel panel-default">
226 <div class="panel panel-default">
194 <div class="panel-heading">
227 <div class="panel-heading">
195 <h3 class="panel-title">${_('Subversion Settings')}</h3>
228 <h3 class="panel-title">${_('Subversion Settings')}</h3>
196 </div>
229 </div>
197 <div class="panel-body">
230 <div class="panel-body">
198 <div class="field">
231 <div class="field">
199 <div class="content" >
232 <div class="content" >
200 <label>${_('Repository patterns')}</label><br/>
233 <label>${_('Repository patterns')}</label><br/>
201 </div>
234 </div>
202 </div>
235 </div>
203 <div class="label">
236 <div class="label">
204 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
237 <span class="help-block">${_('Patterns for identifying SVN branches and tags. For recursive search, use "*". Eg.: "/branches/*"')}</span>
205 </div>
238 </div>
206
239
207 <div class="field branch_patterns">
240 <div class="field branch_patterns">
208 <div class="input" >
241 <div class="input" >
209 <label>${_('Branches')}:</label><br/>
242 <label>${_('Branches')}:</label><br/>
210 </div>
243 </div>
211 % if svn_branch_patterns:
244 % if svn_branch_patterns:
212 % for branch in svn_branch_patterns:
245 % for branch in svn_branch_patterns:
213 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
246 <div class="input adjacent" id="${'id%s' % branch.ui_id}">
214 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
247 ${h.hidden('branch_ui_key' + suffix, branch.ui_key)}
215 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
248 ${h.text('branch_value_%d' % branch.ui_id + suffix, branch.ui_value, size=59, readonly="readonly", class_='disabled')}
216 % if kwargs.get('disabled') != 'disabled':
249 % if kwargs.get('disabled') != 'disabled':
217 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
250 <span class="btn btn-x" onclick="ajaxDeletePattern(${branch.ui_id},'${'id%s' % branch.ui_id}')">
218 ${_('Delete')}
251 ${_('Delete')}
219 </span>
252 </span>
220 % endif
253 % endif
221 </div>
254 </div>
222 % endfor
255 % endfor
223 %endif
256 %endif
224 </div>
257 </div>
225 % if kwargs.get('disabled') != 'disabled':
258 % if kwargs.get('disabled') != 'disabled':
226 <div class="field branch_patterns">
259 <div class="field branch_patterns">
227 <div class="input" >
260 <div class="input" >
228 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
261 ${h.text('new_svn_branch',size=59,placeholder='New branch pattern')}
229 </div>
262 </div>
230 </div>
263 </div>
231 % endif
264 % endif
232 <div class="field tag_patterns">
265 <div class="field tag_patterns">
233 <div class="input" >
266 <div class="input" >
234 <label>${_('Tags')}:</label><br/>
267 <label>${_('Tags')}:</label><br/>
235 </div>
268 </div>
236 % if svn_tag_patterns:
269 % if svn_tag_patterns:
237 % for tag in svn_tag_patterns:
270 % for tag in svn_tag_patterns:
238 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
271 <div class="input" id="${'id%s' % tag.ui_id + suffix}">
239 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
272 ${h.hidden('tag_ui_key' + suffix, tag.ui_key)}
240 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
273 ${h.text('tag_ui_value_new_%d' % tag.ui_id + suffix, tag.ui_value, size=59, readonly="readonly", class_='disabled tag_input')}
241 % if kwargs.get('disabled') != 'disabled':
274 % if kwargs.get('disabled') != 'disabled':
242 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
275 <span class="btn btn-x" onclick="ajaxDeletePattern(${tag.ui_id},'${'id%s' % tag.ui_id}')">
243 ${_('Delete')}
276 ${_('Delete')}
244 </span>
277 </span>
245 %endif
278 %endif
246 </div>
279 </div>
247 % endfor
280 % endfor
248 % endif
281 % endif
249 </div>
282 </div>
250 % if kwargs.get('disabled') != 'disabled':
283 % if kwargs.get('disabled') != 'disabled':
251 <div class="field tag_patterns">
284 <div class="field tag_patterns">
252 <div class="input" >
285 <div class="input" >
253 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
286 ${h.text('new_svn_tag' + suffix, size=59, placeholder='New tag pattern')}
254 </div>
287 </div>
255 </div>
288 </div>
256 %endif
289 %endif
257 </div>
290 </div>
258 </div>
291 </div>
259 % else:
292 % else:
260 ${h.hidden('new_svn_branch' + suffix, '')}
293 ${h.hidden('new_svn_branch' + suffix, '')}
261 ${h.hidden('new_svn_tag' + suffix, '')}
294 ${h.hidden('new_svn_tag' + suffix, '')}
262 % endif
295 % endif
263
296
264
297
265
298
266
299
267 % if display_globals or repo_type in ['hg', 'git']:
300 % if display_globals or repo_type in ['hg', 'git']:
268 <div class="panel panel-default">
301 <div class="panel panel-default">
269 <div class="panel-heading">
302 <div class="panel-heading">
270 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
303 <h3 class="panel-title">${_('Pull Request Settings')}</h3>
271 </div>
304 </div>
272 <div class="panel-body">
305 <div class="panel-body">
273 <div class="checkbox">
306 <div class="checkbox">
274 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
307 ${h.checkbox('rhodecode_pr_merge_enabled' + suffix, 'True', **kwargs)}
275 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
308 <label for="rhodecode_pr_merge_enabled${suffix}">${_('Enable server-side merge for pull requests')}</label>
276 </div>
309 </div>
277 <div class="label">
310 <div class="label">
278 <span class="help-block">${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')}</span>
311 <span class="help-block">${_('Note: when this feature is enabled, it only runs hooks defined in the rcextension package. Custom hooks added on the Admin -> Settings -> Hooks page will not be run when pull requests are automatically merged from the web interface.')}</span>
279 </div>
312 </div>
280 <div class="checkbox">
313 <div class="checkbox">
281 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
314 ${h.checkbox('rhodecode_use_outdated_comments' + suffix, 'True', **kwargs)}
282 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
315 <label for="rhodecode_use_outdated_comments${suffix}">${_('Invalidate and relocate inline comments during update')}</label>
283 </div>
316 </div>
284 <div class="label">
317 <div class="label">
285 <span class="help-block">${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')}</span>
318 <span class="help-block">${_('During the update of a pull request, the position of inline comments will be updated and outdated inline comments will be hidden.')}</span>
286 </div>
319 </div>
287 </div>
320 </div>
288 </div>
321 </div>
289 % endif
322 % endif
290
323
291 </%def>
324 </%def>
@@ -1,137 +1,142 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 pytest
21 import pytest
22 import urlparse
22 import urlparse
23 import mock
24 import simplejson as json
23
25
26 from rhodecode.lib.vcs.backends.base import Config
24 from rhodecode.tests.lib.middleware import mock_scm_app
27 from rhodecode.tests.lib.middleware import mock_scm_app
25 import rhodecode.lib.middleware.simplegit as simplegit
28 import rhodecode.lib.middleware.simplegit as simplegit
26
29
27
30
28 def get_environ(url, request_method):
31 def get_environ(url, request_method):
29 """Construct a minimum WSGI environ based on the URL."""
32 """Construct a minimum WSGI environ based on the URL."""
30 parsed_url = urlparse.urlparse(url)
33 parsed_url = urlparse.urlparse(url)
31 environ = {
34 environ = {
32 'PATH_INFO': parsed_url.path,
35 'PATH_INFO': parsed_url.path,
33 'QUERY_STRING': parsed_url.query,
36 'QUERY_STRING': parsed_url.query,
34 'REQUEST_METHOD': request_method,
37 'REQUEST_METHOD': request_method,
35 }
38 }
36
39
37 return environ
40 return environ
38
41
39
42
40 @pytest.mark.parametrize(
43 @pytest.mark.parametrize(
41 'url, expected_action, request_method',
44 'url, expected_action, request_method',
42 [
45 [
43 ('/foo/bar/info/refs?service=git-upload-pack', 'pull', 'GET'),
46 ('/foo/bar/info/refs?service=git-upload-pack', 'pull', 'GET'),
44 ('/foo/bar/info/refs?service=git-receive-pack', 'push', 'GET'),
47 ('/foo/bar/info/refs?service=git-receive-pack', 'push', 'GET'),
45 ('/foo/bar/git-upload-pack', 'pull', 'GET'),
48 ('/foo/bar/git-upload-pack', 'pull', 'GET'),
46 ('/foo/bar/git-receive-pack', 'push', 'GET'),
49 ('/foo/bar/git-receive-pack', 'push', 'GET'),
47 # Edge case: missing data for info/refs
50 # Edge case: missing data for info/refs
48 ('/foo/info/refs?service=', 'pull', 'GET'),
51 ('/foo/info/refs?service=', 'pull', 'GET'),
49 ('/foo/info/refs', 'pull', 'GET'),
52 ('/foo/info/refs', 'pull', 'GET'),
50 # Edge case: git command comes with service argument
53 # Edge case: git command comes with service argument
51 ('/foo/git-upload-pack?service=git-receive-pack', 'pull', 'GET'),
54 ('/foo/git-upload-pack?service=git-receive-pack', 'pull', 'GET'),
52 ('/foo/git-receive-pack?service=git-upload-pack', 'push', 'GET'),
55 ('/foo/git-receive-pack?service=git-upload-pack', 'push', 'GET'),
53 # Edge case: repo name conflicts with git commands
56 # Edge case: repo name conflicts with git commands
54 ('/git-receive-pack/git-upload-pack', 'pull', 'GET'),
57 ('/git-receive-pack/git-upload-pack', 'pull', 'GET'),
55 ('/git-receive-pack/git-receive-pack', 'push', 'GET'),
58 ('/git-receive-pack/git-receive-pack', 'push', 'GET'),
56 ('/git-upload-pack/git-upload-pack', 'pull', 'GET'),
59 ('/git-upload-pack/git-upload-pack', 'pull', 'GET'),
57 ('/git-upload-pack/git-receive-pack', 'push', 'GET'),
60 ('/git-upload-pack/git-receive-pack', 'push', 'GET'),
58 ('/foo/git-receive-pack', 'push', 'GET'),
61 ('/foo/git-receive-pack', 'push', 'GET'),
59 # Edge case: not a smart protocol url
62 # Edge case: not a smart protocol url
60 ('/foo/bar', 'pull', 'GET'),
63 ('/foo/bar', 'pull', 'GET'),
61 # GIT LFS cases, batch
64 # GIT LFS cases, batch
62 ('/foo/bar/info/lfs/objects/batch', 'push', 'GET'),
65 ('/foo/bar/info/lfs/objects/batch', 'push', 'GET'),
63 ('/foo/bar/info/lfs/objects/batch', 'pull', 'POST'),
66 ('/foo/bar/info/lfs/objects/batch', 'pull', 'POST'),
64 # GIT LFS oid, dl/upl
67 # GIT LFS oid, dl/upl
65 ('/foo/bar/info/lfs/abcdeabcde', 'pull', 'GET'),
68 ('/foo/bar/info/lfs/abcdeabcde', 'pull', 'GET'),
66 ('/foo/bar/info/lfs/abcdeabcde', 'push', 'PUT'),
69 ('/foo/bar/info/lfs/abcdeabcde', 'push', 'PUT'),
67 ('/foo/bar/info/lfs/abcdeabcde', 'push', 'POST'),
70 ('/foo/bar/info/lfs/abcdeabcde', 'push', 'POST'),
68 # Edge case: repo name conflicts with git commands
71 # Edge case: repo name conflicts with git commands
69 ('/info/lfs/info/lfs/objects/batch', 'push', 'GET'),
72 ('/info/lfs/info/lfs/objects/batch', 'push', 'GET'),
70 ('/info/lfs/info/lfs/objects/batch', 'pull', 'POST'),
73 ('/info/lfs/info/lfs/objects/batch', 'pull', 'POST'),
71
74
72 ])
75 ])
73 def test_get_action(url, expected_action, request_method, pylonsapp):
76 def test_get_action(url, expected_action, request_method, pylonsapp):
74 app = simplegit.SimpleGit(application=None,
77 app = simplegit.SimpleGit(application=None,
75 config={'auth_ret_code': '', 'base_path': ''},
78 config={'auth_ret_code': '', 'base_path': ''},
76 registry=None)
79 registry=None)
77 assert expected_action == app._get_action(get_environ(url, request_method))
80 assert expected_action == app._get_action(get_environ(url, request_method))
78
81
79
82
80 @pytest.mark.parametrize(
83 @pytest.mark.parametrize(
81 'url, expected_repo_name, request_method',
84 'url, expected_repo_name, request_method',
82 [
85 [
83 ('/foo/info/refs?service=git-upload-pack', 'foo', 'GET'),
86 ('/foo/info/refs?service=git-upload-pack', 'foo', 'GET'),
84 ('/foo/bar/info/refs?service=git-receive-pack', 'foo/bar', 'GET'),
87 ('/foo/bar/info/refs?service=git-receive-pack', 'foo/bar', 'GET'),
85 ('/foo/git-upload-pack', 'foo', 'GET'),
88 ('/foo/git-upload-pack', 'foo', 'GET'),
86 ('/foo/git-receive-pack', 'foo', 'GET'),
89 ('/foo/git-receive-pack', 'foo', 'GET'),
87 ('/foo/bar/git-upload-pack', 'foo/bar', 'GET'),
90 ('/foo/bar/git-upload-pack', 'foo/bar', 'GET'),
88 ('/foo/bar/git-receive-pack', 'foo/bar', 'GET'),
91 ('/foo/bar/git-receive-pack', 'foo/bar', 'GET'),
89
92
90 # GIT LFS cases, batch
93 # GIT LFS cases, batch
91 ('/foo/bar/info/lfs/objects/batch', 'foo/bar', 'GET'),
94 ('/foo/bar/info/lfs/objects/batch', 'foo/bar', 'GET'),
92 ('/example-git/info/lfs/objects/batch', 'example-git', 'POST'),
95 ('/example-git/info/lfs/objects/batch', 'example-git', 'POST'),
93 # GIT LFS oid, dl/upl
96 # GIT LFS oid, dl/upl
94 ('/foo/info/lfs/abcdeabcde', 'foo', 'GET'),
97 ('/foo/info/lfs/abcdeabcde', 'foo', 'GET'),
95 ('/foo/bar/info/lfs/abcdeabcde', 'foo/bar', 'PUT'),
98 ('/foo/bar/info/lfs/abcdeabcde', 'foo/bar', 'PUT'),
96 ('/my-git-repo/info/lfs/abcdeabcde', 'my-git-repo', 'POST'),
99 ('/my-git-repo/info/lfs/abcdeabcde', 'my-git-repo', 'POST'),
97 # Edge case: repo name conflicts with git commands
100 # Edge case: repo name conflicts with git commands
98 ('/info/lfs/info/lfs/objects/batch', 'info/lfs', 'GET'),
101 ('/info/lfs/info/lfs/objects/batch', 'info/lfs', 'GET'),
99 ('/info/lfs/info/lfs/objects/batch', 'info/lfs', 'POST'),
102 ('/info/lfs/info/lfs/objects/batch', 'info/lfs', 'POST'),
100
103
101 ])
104 ])
102 def test_get_repository_name(url, expected_repo_name, request_method, pylonsapp):
105 def test_get_repository_name(url, expected_repo_name, request_method, pylonsapp):
103 app = simplegit.SimpleGit(application=None,
106 app = simplegit.SimpleGit(application=None,
104 config={'auth_ret_code': '', 'base_path': ''},
107 config={'auth_ret_code': '', 'base_path': ''},
105 registry=None)
108 registry=None)
106 assert expected_repo_name == app._get_repository_name(
109 assert expected_repo_name == app._get_repository_name(
107 get_environ(url, request_method))
110 get_environ(url, request_method))
108
111
109
112
110 def test_get_config(pylonsapp):
113 def test_get_config(pylonsapp, user_util):
114 repo = user_util.create_repo(repo_type='git')
111 app = simplegit.SimpleGit(application=None,
115 app = simplegit.SimpleGit(application=None,
112 config={'auth_ret_code': '', 'base_path': ''},
116 config={'auth_ret_code': '', 'base_path': ''},
113 registry=None)
117 registry=None)
114 extras = {'foo': 'FOO', 'bar': 'BAR'}
118 extras = {'foo': 'FOO', 'bar': 'BAR'}
115
119
116 # We copy the extras as the method below will change the contents.
120 # We copy the extras as the method below will change the contents.
117 config = app._create_config(dict(extras), repo_name='test-repo')
121 git_config = app._create_config(dict(extras), repo_name=repo.repo_name)
122
118 expected_config = dict(extras)
123 expected_config = dict(extras)
119 expected_config.update({
124 expected_config.update({
120 'git_update_server_info': False,
125 'git_update_server_info': False,
121 'git_lfs_enabled': True,
126 'git_lfs_enabled': False,
122 'git_lfs_store_path': simplegit.default_lfs_store()
127 'git_lfs_store_path': git_config['git_lfs_store_path']
123 })
128 })
124
129
125 assert config == expected_config
130 assert git_config == expected_config
126
131
127
132
128 def test_create_wsgi_app_uses_scm_app_from_simplevcs(pylonsapp):
133 def test_create_wsgi_app_uses_scm_app_from_simplevcs(pylonsapp):
129 config = {
134 config = {
130 'auth_ret_code': '',
135 'auth_ret_code': '',
131 'base_path': '',
136 'base_path': '',
132 'vcs.scm_app_implementation':
137 'vcs.scm_app_implementation':
133 'rhodecode.tests.lib.middleware.mock_scm_app',
138 'rhodecode.tests.lib.middleware.mock_scm_app',
134 }
139 }
135 app = simplegit.SimpleGit(application=None, config=config, registry=None)
140 app = simplegit.SimpleGit(application=None, config=config, registry=None)
136 wsgi_app = app._create_wsgi_app('/tmp/test', 'test_repo', {})
141 wsgi_app = app._create_wsgi_app('/tmp/test', 'test_repo', {})
137 assert wsgi_app is mock_scm_app.mock_git_wsgi
142 assert wsgi_app is mock_scm_app.mock_git_wsgi
@@ -1,116 +1,128 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 urlparse
21 import urlparse
22
22
23 import mock
23 import mock
24 import pytest
24 import pytest
25 import simplejson as json
25 import simplejson as json
26
26
27 from rhodecode.lib.vcs.backends.base import Config
27 from rhodecode.lib.vcs.backends.base import Config
28 from rhodecode.tests.lib.middleware import mock_scm_app
28 from rhodecode.tests.lib.middleware import mock_scm_app
29 import rhodecode.lib.middleware.simplehg as simplehg
29 import rhodecode.lib.middleware.simplehg as simplehg
30
30
31
31
32 def get_environ(url):
32 def get_environ(url):
33 """Construct a minimum WSGI environ based on the URL."""
33 """Construct a minimum WSGI environ based on the URL."""
34 parsed_url = urlparse.urlparse(url)
34 parsed_url = urlparse.urlparse(url)
35 environ = {
35 environ = {
36 'PATH_INFO': parsed_url.path,
36 'PATH_INFO': parsed_url.path,
37 'QUERY_STRING': parsed_url.query,
37 'QUERY_STRING': parsed_url.query,
38 }
38 }
39
39
40 return environ
40 return environ
41
41
42
42
43 @pytest.mark.parametrize(
43 @pytest.mark.parametrize(
44 'url, expected_action',
44 'url, expected_action',
45 [
45 [
46 ('/foo/bar?cmd=unbundle&key=tip', 'push'),
46 ('/foo/bar?cmd=unbundle&key=tip', 'push'),
47 ('/foo/bar?cmd=pushkey&key=tip', 'push'),
47 ('/foo/bar?cmd=pushkey&key=tip', 'push'),
48 ('/foo/bar?cmd=listkeys&key=tip', 'pull'),
48 ('/foo/bar?cmd=listkeys&key=tip', 'pull'),
49 ('/foo/bar?cmd=changegroup&key=tip', 'pull'),
49 ('/foo/bar?cmd=changegroup&key=tip', 'pull'),
50 # Edge case: unknown argument: assume pull
50 # Edge case: unknown argument: assume pull
51 ('/foo/bar?cmd=unknown&key=tip', 'pull'),
51 ('/foo/bar?cmd=unknown&key=tip', 'pull'),
52 ('/foo/bar?cmd=&key=tip', 'pull'),
52 ('/foo/bar?cmd=&key=tip', 'pull'),
53 # Edge case: not cmd argument
53 # Edge case: not cmd argument
54 ('/foo/bar?key=tip', 'pull'),
54 ('/foo/bar?key=tip', 'pull'),
55 ])
55 ])
56 def test_get_action(url, expected_action):
56 def test_get_action(url, expected_action):
57 app = simplehg.SimpleHg(application=None,
57 app = simplehg.SimpleHg(application=None,
58 config={'auth_ret_code': '', 'base_path': ''},
58 config={'auth_ret_code': '', 'base_path': ''},
59 registry=None)
59 registry=None)
60 assert expected_action == app._get_action(get_environ(url))
60 assert expected_action == app._get_action(get_environ(url))
61
61
62
62
63 @pytest.mark.parametrize(
63 @pytest.mark.parametrize(
64 'url, expected_repo_name',
64 'url, expected_repo_name',
65 [
65 [
66 ('/foo?cmd=unbundle&key=tip', 'foo'),
66 ('/foo?cmd=unbundle&key=tip', 'foo'),
67 ('/foo/bar?cmd=pushkey&key=tip', 'foo/bar'),
67 ('/foo/bar?cmd=pushkey&key=tip', 'foo/bar'),
68 ('/foo/bar/baz?cmd=listkeys&key=tip', 'foo/bar/baz'),
68 ('/foo/bar/baz?cmd=listkeys&key=tip', 'foo/bar/baz'),
69 # Repos with trailing slashes.
69 # Repos with trailing slashes.
70 ('/foo/?cmd=unbundle&key=tip', 'foo'),
70 ('/foo/?cmd=unbundle&key=tip', 'foo'),
71 ('/foo/bar/?cmd=pushkey&key=tip', 'foo/bar'),
71 ('/foo/bar/?cmd=pushkey&key=tip', 'foo/bar'),
72 ('/foo/bar/baz/?cmd=listkeys&key=tip', 'foo/bar/baz'),
72 ('/foo/bar/baz/?cmd=listkeys&key=tip', 'foo/bar/baz'),
73 ])
73 ])
74 def test_get_repository_name(url, expected_repo_name):
74 def test_get_repository_name(url, expected_repo_name):
75 app = simplehg.SimpleHg(application=None,
75 app = simplehg.SimpleHg(application=None,
76 config={'auth_ret_code': '', 'base_path': ''},
76 config={'auth_ret_code': '', 'base_path': ''},
77 registry=None)
77 registry=None)
78 assert expected_repo_name == app._get_repository_name(get_environ(url))
78 assert expected_repo_name == app._get_repository_name(get_environ(url))
79
79
80
80
81 def test_get_config():
81 def test_get_config(pylonsapp, user_util):
82 repo = user_util.create_repo(repo_type='git')
82 app = simplehg.SimpleHg(application=None,
83 app = simplehg.SimpleHg(application=None,
83 config={'auth_ret_code': '', 'base_path': ''},
84 config={'auth_ret_code': '', 'base_path': ''},
84 registry=None)
85 registry=None)
85 extras = {'foo': 'FOO', 'bar': 'BAR'}
86 extras = {'foo': 'FOO', 'bar': 'BAR'}
86
87
87 mock_config = Config()
88 hg_config = app._create_config(extras, repo_name=repo.repo_name)
88 mock_config.set('a1', 'b1', 'c1')
89
89 mock_config.set('a2', 'b2', 'c2')
90 config = simplehg.utils.make_db_config(repo=repo.repo_name)
90 # We mock the call to make_db_config, otherwise we need to wait for the
91 config.set('rhodecode', 'RC_SCM_DATA', json.dumps(extras))
91 # pylonsaspp
92 hg_config_org = config
92 with mock.patch('rhodecode.lib.utils.make_db_config',
93 return_value=mock_config) as make_db_config_mock:
94 hg_config = app._create_config(extras, repo_name='test-repo')
95
93
96 make_db_config_mock.assert_called_once_with(repo='test-repo')
94 expected_config = [
97 assert isinstance(hg_config, list)
95 ('vcs_svn_tag', 'ff89f8c714d135d865f44b90e5413b88de19a55f', '/tags/*'),
98
96 ('web', 'push_ssl', 'False'),
99 # Remove the entries from the mock_config so to get only the extras
97 ('web', 'allow_push', '*'),
100 hg_config.remove(('a1', 'b1', 'c1'))
98 ('web', 'allow_archive', 'gz zip bz2'),
101 hg_config.remove(('a2', 'b2', 'c2'))
99 ('web', 'baseurl', '/'),
102
100 ('vcs_git_lfs', 'store_location', hg_config_org.get('vcs_git_lfs', 'store_location')),
103 assert hg_config[0][:2] == ('rhodecode', 'RC_SCM_DATA')
101 ('vcs_svn_branch', '9aac1a38c3b8a0cdc4ae0f960a5f83332bc4fa5e', '/branches/*'),
104 assert json.loads(hg_config[0][-1]) == extras
102 ('vcs_svn_branch', 'c7e6a611c87da06529fd0dd733308481d67c71a8', '/trunk'),
103 ('largefiles', 'usercache', hg_config_org.get('largefiles', 'usercache')),
104 ('hooks', 'preoutgoing.pre_pull', 'python:vcsserver.hooks.pre_pull'),
105 ('hooks', 'prechangegroup.pre_push', 'python:vcsserver.hooks.pre_push'),
106 ('hooks', 'outgoing.pull_logger', 'python:vcsserver.hooks.log_pull_action'),
107 ('hooks', 'pretxnchangegroup.pre_push', 'python:vcsserver.hooks.pre_push'),
108 ('hooks', 'changegroup.push_logger', 'python:vcsserver.hooks.log_push_action'),
109 ('hooks', 'changegroup.repo_size', 'python:vcsserver.hooks.repo_size'),
110 ('phases', 'publish', 'True'),
111 ('extensions', 'largefiles', ''),
112 ('paths', '/', hg_config_org.get('paths', '/')),
113 ('rhodecode', 'RC_SCM_DATA', '{"foo": "FOO", "bar": "BAR"}')
114 ]
115 for entry in expected_config:
116 assert entry in hg_config
105
117
106
118
107 def test_create_wsgi_app_uses_scm_app_from_simplevcs():
119 def test_create_wsgi_app_uses_scm_app_from_simplevcs():
108 config = {
120 config = {
109 'auth_ret_code': '',
121 'auth_ret_code': '',
110 'base_path': '',
122 'base_path': '',
111 'vcs.scm_app_implementation':
123 'vcs.scm_app_implementation':
112 'rhodecode.tests.lib.middleware.mock_scm_app',
124 'rhodecode.tests.lib.middleware.mock_scm_app',
113 }
125 }
114 app = simplehg.SimpleHg(application=None, config=config, registry=None)
126 app = simplehg.SimpleHg(application=None, config=config, registry=None)
115 wsgi_app = app._create_wsgi_app('/tmp/test', 'test_repo', {})
127 wsgi_app = app._create_wsgi_app('/tmp/test', 'test_repo', {})
116 assert wsgi_app is mock_scm_app.mock_hg_wsgi
128 assert wsgi_app is mock_scm_app.mock_hg_wsgi
@@ -1,1034 +1,1061 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 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 mock
21 import mock
22 import pytest
22 import pytest
23
23
24 from rhodecode.lib.utils2 import str2bool
24 from rhodecode.lib.utils2 import str2bool
25 from rhodecode.model.meta import Session
25 from rhodecode.model.meta import Session
26 from rhodecode.model.settings import VcsSettingsModel, UiSetting
26 from rhodecode.model.settings import VcsSettingsModel, UiSetting
27
27
28
28
29 HOOKS_FORM_DATA = {
29 HOOKS_FORM_DATA = {
30 'hooks_changegroup_repo_size': True,
30 'hooks_changegroup_repo_size': True,
31 'hooks_changegroup_push_logger': True,
31 'hooks_changegroup_push_logger': True,
32 'hooks_outgoing_pull_logger': True
32 'hooks_outgoing_pull_logger': True
33 }
33 }
34
34
35 SVN_FORM_DATA = {
35 SVN_FORM_DATA = {
36 'new_svn_branch': 'test-branch',
36 'new_svn_branch': 'test-branch',
37 'new_svn_tag': 'test-tag'
37 'new_svn_tag': 'test-tag'
38 }
38 }
39
39
40 GENERAL_FORM_DATA = {
40 GENERAL_FORM_DATA = {
41 'rhodecode_pr_merge_enabled': True,
41 'rhodecode_pr_merge_enabled': True,
42 'rhodecode_use_outdated_comments': True,
42 'rhodecode_use_outdated_comments': True,
43 'rhodecode_hg_use_rebase_for_merging': True,
43 'rhodecode_hg_use_rebase_for_merging': True,
44 }
44 }
45
45
46
46
47 class TestInheritGlobalSettingsProperty(object):
47 class TestInheritGlobalSettingsProperty(object):
48 def test_get_raises_exception_when_repository_not_specified(self):
48 def test_get_raises_exception_when_repository_not_specified(self):
49 model = VcsSettingsModel()
49 model = VcsSettingsModel()
50 with pytest.raises(Exception) as exc_info:
50 with pytest.raises(Exception) as exc_info:
51 model.inherit_global_settings
51 model.inherit_global_settings
52 assert exc_info.value.message == 'Repository is not specified'
52 assert exc_info.value.message == 'Repository is not specified'
53
53
54 def test_true_is_returned_when_value_is_not_found(self, repo_stub):
54 def test_true_is_returned_when_value_is_not_found(self, repo_stub):
55 model = VcsSettingsModel(repo=repo_stub.repo_name)
55 model = VcsSettingsModel(repo=repo_stub.repo_name)
56 assert model.inherit_global_settings is True
56 assert model.inherit_global_settings is True
57
57
58 def test_value_is_returned(self, repo_stub, settings_util):
58 def test_value_is_returned(self, repo_stub, settings_util):
59 model = VcsSettingsModel(repo=repo_stub.repo_name)
59 model = VcsSettingsModel(repo=repo_stub.repo_name)
60 settings_util.create_repo_rhodecode_setting(
60 settings_util.create_repo_rhodecode_setting(
61 repo_stub, VcsSettingsModel.INHERIT_SETTINGS, False, 'bool')
61 repo_stub, VcsSettingsModel.INHERIT_SETTINGS, False, 'bool')
62 assert model.inherit_global_settings is False
62 assert model.inherit_global_settings is False
63
63
64 def test_value_is_set(self, repo_stub):
64 def test_value_is_set(self, repo_stub):
65 model = VcsSettingsModel(repo=repo_stub.repo_name)
65 model = VcsSettingsModel(repo=repo_stub.repo_name)
66 model.inherit_global_settings = False
66 model.inherit_global_settings = False
67 setting = model.repo_settings.get_setting_by_name(
67 setting = model.repo_settings.get_setting_by_name(
68 VcsSettingsModel.INHERIT_SETTINGS)
68 VcsSettingsModel.INHERIT_SETTINGS)
69 try:
69 try:
70 assert setting.app_settings_type == 'bool'
70 assert setting.app_settings_type == 'bool'
71 assert setting.app_settings_value is False
71 assert setting.app_settings_value is False
72 finally:
72 finally:
73 Session().delete(setting)
73 Session().delete(setting)
74 Session().commit()
74 Session().commit()
75
75
76 def test_set_raises_exception_when_repository_not_specified(self):
76 def test_set_raises_exception_when_repository_not_specified(self):
77 model = VcsSettingsModel()
77 model = VcsSettingsModel()
78 with pytest.raises(Exception) as exc_info:
78 with pytest.raises(Exception) as exc_info:
79 model.inherit_global_settings = False
79 model.inherit_global_settings = False
80 assert exc_info.value.message == 'Repository is not specified'
80 assert exc_info.value.message == 'Repository is not specified'
81
81
82
82
83 class TestVcsSettingsModel(object):
83 class TestVcsSettingsModel(object):
84 def test_global_svn_branch_patterns(self):
84 def test_global_svn_branch_patterns(self):
85 model = VcsSettingsModel()
85 model = VcsSettingsModel()
86 expected_result = {'test': 'test'}
86 expected_result = {'test': 'test'}
87 with mock.patch.object(model, 'global_settings') as settings_mock:
87 with mock.patch.object(model, 'global_settings') as settings_mock:
88 get_settings = settings_mock.get_ui_by_section
88 get_settings = settings_mock.get_ui_by_section
89 get_settings.return_value = expected_result
89 get_settings.return_value = expected_result
90 settings_mock.return_value = expected_result
90 settings_mock.return_value = expected_result
91 result = model.get_global_svn_branch_patterns()
91 result = model.get_global_svn_branch_patterns()
92
92
93 get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION)
93 get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION)
94 assert expected_result == result
94 assert expected_result == result
95
95
96 def test_repo_svn_branch_patterns(self):
96 def test_repo_svn_branch_patterns(self):
97 model = VcsSettingsModel()
97 model = VcsSettingsModel()
98 expected_result = {'test': 'test'}
98 expected_result = {'test': 'test'}
99 with mock.patch.object(model, 'repo_settings') as settings_mock:
99 with mock.patch.object(model, 'repo_settings') as settings_mock:
100 get_settings = settings_mock.get_ui_by_section
100 get_settings = settings_mock.get_ui_by_section
101 get_settings.return_value = expected_result
101 get_settings.return_value = expected_result
102 settings_mock.return_value = expected_result
102 settings_mock.return_value = expected_result
103 result = model.get_repo_svn_branch_patterns()
103 result = model.get_repo_svn_branch_patterns()
104
104
105 get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION)
105 get_settings.assert_called_once_with(model.SVN_BRANCH_SECTION)
106 assert expected_result == result
106 assert expected_result == result
107
107
108 def test_repo_svn_branch_patterns_raises_exception_when_repo_is_not_set(
108 def test_repo_svn_branch_patterns_raises_exception_when_repo_is_not_set(
109 self):
109 self):
110 model = VcsSettingsModel()
110 model = VcsSettingsModel()
111 with pytest.raises(Exception) as exc_info:
111 with pytest.raises(Exception) as exc_info:
112 model.get_repo_svn_branch_patterns()
112 model.get_repo_svn_branch_patterns()
113 assert exc_info.value.message == 'Repository is not specified'
113 assert exc_info.value.message == 'Repository is not specified'
114
114
115 def test_global_svn_tag_patterns(self):
115 def test_global_svn_tag_patterns(self):
116 model = VcsSettingsModel()
116 model = VcsSettingsModel()
117 expected_result = {'test': 'test'}
117 expected_result = {'test': 'test'}
118 with mock.patch.object(model, 'global_settings') as settings_mock:
118 with mock.patch.object(model, 'global_settings') as settings_mock:
119 get_settings = settings_mock.get_ui_by_section
119 get_settings = settings_mock.get_ui_by_section
120 get_settings.return_value = expected_result
120 get_settings.return_value = expected_result
121 settings_mock.return_value = expected_result
121 settings_mock.return_value = expected_result
122 result = model.get_global_svn_tag_patterns()
122 result = model.get_global_svn_tag_patterns()
123
123
124 get_settings.assert_called_once_with(model.SVN_TAG_SECTION)
124 get_settings.assert_called_once_with(model.SVN_TAG_SECTION)
125 assert expected_result == result
125 assert expected_result == result
126
126
127 def test_repo_svn_tag_patterns(self):
127 def test_repo_svn_tag_patterns(self):
128 model = VcsSettingsModel()
128 model = VcsSettingsModel()
129 expected_result = {'test': 'test'}
129 expected_result = {'test': 'test'}
130 with mock.patch.object(model, 'repo_settings') as settings_mock:
130 with mock.patch.object(model, 'repo_settings') as settings_mock:
131 get_settings = settings_mock.get_ui_by_section
131 get_settings = settings_mock.get_ui_by_section
132 get_settings.return_value = expected_result
132 get_settings.return_value = expected_result
133 settings_mock.return_value = expected_result
133 settings_mock.return_value = expected_result
134 result = model.get_repo_svn_tag_patterns()
134 result = model.get_repo_svn_tag_patterns()
135
135
136 get_settings.assert_called_once_with(model.SVN_TAG_SECTION)
136 get_settings.assert_called_once_with(model.SVN_TAG_SECTION)
137 assert expected_result == result
137 assert expected_result == result
138
138
139 def test_repo_svn_tag_patterns_raises_exception_when_repo_is_not_set(self):
139 def test_repo_svn_tag_patterns_raises_exception_when_repo_is_not_set(self):
140 model = VcsSettingsModel()
140 model = VcsSettingsModel()
141 with pytest.raises(Exception) as exc_info:
141 with pytest.raises(Exception) as exc_info:
142 model.get_repo_svn_tag_patterns()
142 model.get_repo_svn_tag_patterns()
143 assert exc_info.value.message == 'Repository is not specified'
143 assert exc_info.value.message == 'Repository is not specified'
144
144
145 def test_get_global_settings(self):
145 def test_get_global_settings(self):
146 expected_result = {'test': 'test'}
146 expected_result = {'test': 'test'}
147 model = VcsSettingsModel()
147 model = VcsSettingsModel()
148 with mock.patch.object(model, '_collect_all_settings') as collect_mock:
148 with mock.patch.object(model, '_collect_all_settings') as collect_mock:
149 collect_mock.return_value = expected_result
149 collect_mock.return_value = expected_result
150 result = model.get_global_settings()
150 result = model.get_global_settings()
151
151
152 collect_mock.assert_called_once_with(global_=True)
152 collect_mock.assert_called_once_with(global_=True)
153 assert result == expected_result
153 assert result == expected_result
154
154
155 def test_get_repo_settings(self, repo_stub):
155 def test_get_repo_settings(self, repo_stub):
156 model = VcsSettingsModel(repo=repo_stub.repo_name)
156 model = VcsSettingsModel(repo=repo_stub.repo_name)
157 expected_result = {'test': 'test'}
157 expected_result = {'test': 'test'}
158 with mock.patch.object(model, '_collect_all_settings') as collect_mock:
158 with mock.patch.object(model, '_collect_all_settings') as collect_mock:
159 collect_mock.return_value = expected_result
159 collect_mock.return_value = expected_result
160 result = model.get_repo_settings()
160 result = model.get_repo_settings()
161
161
162 collect_mock.assert_called_once_with(global_=False)
162 collect_mock.assert_called_once_with(global_=False)
163 assert result == expected_result
163 assert result == expected_result
164
164
165 @pytest.mark.parametrize('settings, global_', [
165 @pytest.mark.parametrize('settings, global_', [
166 ('global_settings', True),
166 ('global_settings', True),
167 ('repo_settings', False)
167 ('repo_settings', False)
168 ])
168 ])
169 def test_collect_all_settings(self, settings, global_):
169 def test_collect_all_settings(self, settings, global_):
170 model = VcsSettingsModel()
170 model = VcsSettingsModel()
171 result_mock = self._mock_result()
171 result_mock = self._mock_result()
172
172
173 settings_patch = mock.patch.object(model, settings)
173 settings_patch = mock.patch.object(model, settings)
174 with settings_patch as settings_mock:
174 with settings_patch as settings_mock:
175 settings_mock.get_ui_by_section_and_key.return_value = result_mock
175 settings_mock.get_ui_by_section_and_key.return_value = result_mock
176 settings_mock.get_setting_by_name.return_value = result_mock
176 settings_mock.get_setting_by_name.return_value = result_mock
177 result = model._collect_all_settings(global_=global_)
177 result = model._collect_all_settings(global_=global_)
178
178
179 ui_settings = model.HG_SETTINGS + model.HOOKS_SETTINGS
179 ui_settings = model.HG_SETTINGS + model.GIT_SETTINGS + model.HOOKS_SETTINGS
180 self._assert_get_settings_calls(
180 self._assert_get_settings_calls(
181 settings_mock, ui_settings, model.GENERAL_SETTINGS)
181 settings_mock, ui_settings, model.GENERAL_SETTINGS)
182 self._assert_collect_all_settings_result(
182 self._assert_collect_all_settings_result(
183 ui_settings, model.GENERAL_SETTINGS, result)
183 ui_settings, model.GENERAL_SETTINGS, result)
184
184
185 @pytest.mark.parametrize('settings, global_', [
185 @pytest.mark.parametrize('settings, global_', [
186 ('global_settings', True),
186 ('global_settings', True),
187 ('repo_settings', False)
187 ('repo_settings', False)
188 ])
188 ])
189 def test_collect_all_settings_without_empty_value(self, settings, global_):
189 def test_collect_all_settings_without_empty_value(self, settings, global_):
190 model = VcsSettingsModel()
190 model = VcsSettingsModel()
191
191
192 settings_patch = mock.patch.object(model, settings)
192 settings_patch = mock.patch.object(model, settings)
193 with settings_patch as settings_mock:
193 with settings_patch as settings_mock:
194 settings_mock.get_ui_by_section_and_key.return_value = None
194 settings_mock.get_ui_by_section_and_key.return_value = None
195 settings_mock.get_setting_by_name.return_value = None
195 settings_mock.get_setting_by_name.return_value = None
196 result = model._collect_all_settings(global_=global_)
196 result = model._collect_all_settings(global_=global_)
197
197
198 assert result == {}
198 assert result == {}
199
199
200 def _mock_result(self):
200 def _mock_result(self):
201 result_mock = mock.Mock()
201 result_mock = mock.Mock()
202 result_mock.ui_value = 'ui_value'
202 result_mock.ui_value = 'ui_value'
203 result_mock.ui_active = True
203 result_mock.ui_active = True
204 result_mock.app_settings_value = 'setting_value'
204 result_mock.app_settings_value = 'setting_value'
205 return result_mock
205 return result_mock
206
206
207 def _assert_get_settings_calls(
207 def _assert_get_settings_calls(
208 self, settings_mock, ui_settings, general_settings):
208 self, settings_mock, ui_settings, general_settings):
209 assert (
209 assert (
210 settings_mock.get_ui_by_section_and_key.call_count ==
210 settings_mock.get_ui_by_section_and_key.call_count ==
211 len(ui_settings))
211 len(ui_settings))
212 assert (
212 assert (
213 settings_mock.get_setting_by_name.call_count ==
213 settings_mock.get_setting_by_name.call_count ==
214 len(general_settings))
214 len(general_settings))
215
215
216 for section, key in ui_settings:
216 for section, key in ui_settings:
217 expected_call = mock.call(section, key)
217 expected_call = mock.call(section, key)
218 assert (
218 assert (
219 expected_call in
219 expected_call in
220 settings_mock.get_ui_by_section_and_key.call_args_list)
220 settings_mock.get_ui_by_section_and_key.call_args_list)
221
221
222 for name in general_settings:
222 for name in general_settings:
223 expected_call = mock.call(name)
223 expected_call = mock.call(name)
224 assert (
224 assert (
225 expected_call in
225 expected_call in
226 settings_mock.get_setting_by_name.call_args_list)
226 settings_mock.get_setting_by_name.call_args_list)
227
227
228 def _assert_collect_all_settings_result(
228 def _assert_collect_all_settings_result(
229 self, ui_settings, general_settings, result):
229 self, ui_settings, general_settings, result):
230 expected_result = {}
230 expected_result = {}
231 for section, key in ui_settings:
231 for section, key in ui_settings:
232 key = '{}_{}'.format(section, key.replace('.', '_'))
232 key = '{}_{}'.format(section, key.replace('.', '_'))
233 value = True if section in ('extensions', 'hooks') else 'ui_value'
233
234 if section in ('extensions', 'hooks'):
235 value = True
236 elif key in ['vcs_git_lfs_enabled']:
237 value = True
238 else:
239 value = 'ui_value'
234 expected_result[key] = value
240 expected_result[key] = value
235
241
236 for name in general_settings:
242 for name in general_settings:
237 key = 'rhodecode_' + name
243 key = 'rhodecode_' + name
238 expected_result[key] = 'setting_value'
244 expected_result[key] = 'setting_value'
239
245
240 assert expected_result == result
246 assert expected_result == result
241
247
242
248
243 class TestCreateOrUpdateRepoHookSettings(object):
249 class TestCreateOrUpdateRepoHookSettings(object):
244 def test_create_when_no_repo_object_found(self, repo_stub):
250 def test_create_when_no_repo_object_found(self, repo_stub):
245 model = VcsSettingsModel(repo=repo_stub.repo_name)
251 model = VcsSettingsModel(repo=repo_stub.repo_name)
246
252
247 self._create_settings(model, HOOKS_FORM_DATA)
253 self._create_settings(model, HOOKS_FORM_DATA)
248
254
249 cleanup = []
255 cleanup = []
250 try:
256 try:
251 for section, key in model.HOOKS_SETTINGS:
257 for section, key in model.HOOKS_SETTINGS:
252 ui = model.repo_settings.get_ui_by_section_and_key(
258 ui = model.repo_settings.get_ui_by_section_and_key(
253 section, key)
259 section, key)
254 assert ui.ui_active is True
260 assert ui.ui_active is True
255 cleanup.append(ui)
261 cleanup.append(ui)
256 finally:
262 finally:
257 for ui in cleanup:
263 for ui in cleanup:
258 Session().delete(ui)
264 Session().delete(ui)
259 Session().commit()
265 Session().commit()
260
266
261 def test_create_raises_exception_when_data_incomplete(self, repo_stub):
267 def test_create_raises_exception_when_data_incomplete(self, repo_stub):
262 model = VcsSettingsModel(repo=repo_stub.repo_name)
268 model = VcsSettingsModel(repo=repo_stub.repo_name)
263
269
264 deleted_key = 'hooks_changegroup_repo_size'
270 deleted_key = 'hooks_changegroup_repo_size'
265 data = HOOKS_FORM_DATA.copy()
271 data = HOOKS_FORM_DATA.copy()
266 data.pop(deleted_key)
272 data.pop(deleted_key)
267
273
268 with pytest.raises(ValueError) as exc_info:
274 with pytest.raises(ValueError) as exc_info:
269 model.create_or_update_repo_hook_settings(data)
275 model.create_or_update_repo_hook_settings(data)
270 assert (
276 assert (
271 exc_info.value.message ==
277 exc_info.value.message ==
272 'The given data does not contain {} key'.format(deleted_key))
278 'The given data does not contain {} key'.format(deleted_key))
273
279
274 def test_update_when_repo_object_found(self, repo_stub, settings_util):
280 def test_update_when_repo_object_found(self, repo_stub, settings_util):
275 model = VcsSettingsModel(repo=repo_stub.repo_name)
281 model = VcsSettingsModel(repo=repo_stub.repo_name)
276 for section, key in model.HOOKS_SETTINGS:
282 for section, key in model.HOOKS_SETTINGS:
277 settings_util.create_repo_rhodecode_ui(
283 settings_util.create_repo_rhodecode_ui(
278 repo_stub, section, None, key=key, active=False)
284 repo_stub, section, None, key=key, active=False)
279 model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA)
285 model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA)
280 for section, key in model.HOOKS_SETTINGS:
286 for section, key in model.HOOKS_SETTINGS:
281 ui = model.repo_settings.get_ui_by_section_and_key(section, key)
287 ui = model.repo_settings.get_ui_by_section_and_key(section, key)
282 assert ui.ui_active is True
288 assert ui.ui_active is True
283
289
284 def _create_settings(self, model, data):
290 def _create_settings(self, model, data):
285 global_patch = mock.patch.object(model, 'global_settings')
291 global_patch = mock.patch.object(model, 'global_settings')
286 global_setting = mock.Mock()
292 global_setting = mock.Mock()
287 global_setting.ui_value = 'Test value'
293 global_setting.ui_value = 'Test value'
288 with global_patch as global_mock:
294 with global_patch as global_mock:
289 global_mock.get_ui_by_section_and_key.return_value = global_setting
295 global_mock.get_ui_by_section_and_key.return_value = global_setting
290 model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA)
296 model.create_or_update_repo_hook_settings(HOOKS_FORM_DATA)
291
297
292
298
293 class TestUpdateGlobalHookSettings(object):
299 class TestUpdateGlobalHookSettings(object):
294 def test_update_raises_exception_when_data_incomplete(self):
300 def test_update_raises_exception_when_data_incomplete(self):
295 model = VcsSettingsModel()
301 model = VcsSettingsModel()
296
302
297 deleted_key = 'hooks_changegroup_repo_size'
303 deleted_key = 'hooks_changegroup_repo_size'
298 data = HOOKS_FORM_DATA.copy()
304 data = HOOKS_FORM_DATA.copy()
299 data.pop(deleted_key)
305 data.pop(deleted_key)
300
306
301 with pytest.raises(ValueError) as exc_info:
307 with pytest.raises(ValueError) as exc_info:
302 model.update_global_hook_settings(data)
308 model.update_global_hook_settings(data)
303 assert (
309 assert (
304 exc_info.value.message ==
310 exc_info.value.message ==
305 'The given data does not contain {} key'.format(deleted_key))
311 'The given data does not contain {} key'.format(deleted_key))
306
312
307 def test_update_global_hook_settings(self, settings_util):
313 def test_update_global_hook_settings(self, settings_util):
308 model = VcsSettingsModel()
314 model = VcsSettingsModel()
309 setting_mock = mock.MagicMock()
315 setting_mock = mock.MagicMock()
310 setting_mock.ui_active = False
316 setting_mock.ui_active = False
311 get_settings_patcher = mock.patch.object(
317 get_settings_patcher = mock.patch.object(
312 model.global_settings, 'get_ui_by_section_and_key',
318 model.global_settings, 'get_ui_by_section_and_key',
313 return_value=setting_mock)
319 return_value=setting_mock)
314 session_patcher = mock.patch('rhodecode.model.settings.Session')
320 session_patcher = mock.patch('rhodecode.model.settings.Session')
315 with get_settings_patcher as get_settings_mock, session_patcher:
321 with get_settings_patcher as get_settings_mock, session_patcher:
316 model.update_global_hook_settings(HOOKS_FORM_DATA)
322 model.update_global_hook_settings(HOOKS_FORM_DATA)
317 assert setting_mock.ui_active is True
323 assert setting_mock.ui_active is True
318 assert get_settings_mock.call_count == 3
324 assert get_settings_mock.call_count == 3
319
325
320
326
321 class TestCreateOrUpdateRepoGeneralSettings(object):
327 class TestCreateOrUpdateRepoGeneralSettings(object):
322 def test_calls_create_or_update_general_settings(self, repo_stub):
328 def test_calls_create_or_update_general_settings(self, repo_stub):
323 model = VcsSettingsModel(repo=repo_stub.repo_name)
329 model = VcsSettingsModel(repo=repo_stub.repo_name)
324 create_patch = mock.patch.object(
330 create_patch = mock.patch.object(
325 model, '_create_or_update_general_settings')
331 model, '_create_or_update_general_settings')
326 with create_patch as create_mock:
332 with create_patch as create_mock:
327 model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA)
333 model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA)
328 create_mock.assert_called_once_with(
334 create_mock.assert_called_once_with(
329 model.repo_settings, GENERAL_FORM_DATA)
335 model.repo_settings, GENERAL_FORM_DATA)
330
336
331 def test_raises_exception_when_repository_is_not_specified(self):
337 def test_raises_exception_when_repository_is_not_specified(self):
332 model = VcsSettingsModel()
338 model = VcsSettingsModel()
333 with pytest.raises(Exception) as exc_info:
339 with pytest.raises(Exception) as exc_info:
334 model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA)
340 model.create_or_update_repo_pr_settings(GENERAL_FORM_DATA)
335 assert exc_info.value.message == 'Repository is not specified'
341 assert exc_info.value.message == 'Repository is not specified'
336
342
337
343
338 class TestCreateOrUpdatGlobalGeneralSettings(object):
344 class TestCreateOrUpdatGlobalGeneralSettings(object):
339 def test_calls_create_or_update_general_settings(self):
345 def test_calls_create_or_update_general_settings(self):
340 model = VcsSettingsModel()
346 model = VcsSettingsModel()
341 create_patch = mock.patch.object(
347 create_patch = mock.patch.object(
342 model, '_create_or_update_general_settings')
348 model, '_create_or_update_general_settings')
343 with create_patch as create_mock:
349 with create_patch as create_mock:
344 model.create_or_update_global_pr_settings(GENERAL_FORM_DATA)
350 model.create_or_update_global_pr_settings(GENERAL_FORM_DATA)
345 create_mock.assert_called_once_with(
351 create_mock.assert_called_once_with(
346 model.global_settings, GENERAL_FORM_DATA)
352 model.global_settings, GENERAL_FORM_DATA)
347
353
348
354
349 class TestCreateOrUpdateGeneralSettings(object):
355 class TestCreateOrUpdateGeneralSettings(object):
350 def test_create_when_no_repo_settings_found(self, repo_stub):
356 def test_create_when_no_repo_settings_found(self, repo_stub):
351 model = VcsSettingsModel(repo=repo_stub.repo_name)
357 model = VcsSettingsModel(repo=repo_stub.repo_name)
352 model._create_or_update_general_settings(
358 model._create_or_update_general_settings(
353 model.repo_settings, GENERAL_FORM_DATA)
359 model.repo_settings, GENERAL_FORM_DATA)
354
360
355 cleanup = []
361 cleanup = []
356 try:
362 try:
357 for name in model.GENERAL_SETTINGS:
363 for name in model.GENERAL_SETTINGS:
358 setting = model.repo_settings.get_setting_by_name(name)
364 setting = model.repo_settings.get_setting_by_name(name)
359 assert setting.app_settings_value is True
365 assert setting.app_settings_value is True
360 cleanup.append(setting)
366 cleanup.append(setting)
361 finally:
367 finally:
362 for setting in cleanup:
368 for setting in cleanup:
363 Session().delete(setting)
369 Session().delete(setting)
364 Session().commit()
370 Session().commit()
365
371
366 def test_create_raises_exception_when_data_incomplete(self, repo_stub):
372 def test_create_raises_exception_when_data_incomplete(self, repo_stub):
367 model = VcsSettingsModel(repo=repo_stub.repo_name)
373 model = VcsSettingsModel(repo=repo_stub.repo_name)
368
374
369 deleted_key = 'rhodecode_pr_merge_enabled'
375 deleted_key = 'rhodecode_pr_merge_enabled'
370 data = GENERAL_FORM_DATA.copy()
376 data = GENERAL_FORM_DATA.copy()
371 data.pop(deleted_key)
377 data.pop(deleted_key)
372
378
373 with pytest.raises(ValueError) as exc_info:
379 with pytest.raises(ValueError) as exc_info:
374 model._create_or_update_general_settings(model.repo_settings, data)
380 model._create_or_update_general_settings(model.repo_settings, data)
375 assert (
381 assert (
376 exc_info.value.message ==
382 exc_info.value.message ==
377 'The given data does not contain {} key'.format(deleted_key))
383 'The given data does not contain {} key'.format(deleted_key))
378
384
379 def test_update_when_repo_setting_found(self, repo_stub, settings_util):
385 def test_update_when_repo_setting_found(self, repo_stub, settings_util):
380 model = VcsSettingsModel(repo=repo_stub.repo_name)
386 model = VcsSettingsModel(repo=repo_stub.repo_name)
381 for name in model.GENERAL_SETTINGS:
387 for name in model.GENERAL_SETTINGS:
382 settings_util.create_repo_rhodecode_setting(
388 settings_util.create_repo_rhodecode_setting(
383 repo_stub, name, False, 'bool')
389 repo_stub, name, False, 'bool')
384
390
385 model._create_or_update_general_settings(
391 model._create_or_update_general_settings(
386 model.repo_settings, GENERAL_FORM_DATA)
392 model.repo_settings, GENERAL_FORM_DATA)
387
393
388 for name in model.GENERAL_SETTINGS:
394 for name in model.GENERAL_SETTINGS:
389 setting = model.repo_settings.get_setting_by_name(name)
395 setting = model.repo_settings.get_setting_by_name(name)
390 assert setting.app_settings_value is True
396 assert setting.app_settings_value is True
391
397
392
398
393 class TestCreateRepoSvnSettings(object):
399 class TestCreateRepoSvnSettings(object):
394 def test_calls_create_svn_settings(self, repo_stub):
400 def test_calls_create_svn_settings(self, repo_stub):
395 model = VcsSettingsModel(repo=repo_stub.repo_name)
401 model = VcsSettingsModel(repo=repo_stub.repo_name)
396 with mock.patch.object(model, '_create_svn_settings') as create_mock:
402 with mock.patch.object(model, '_create_svn_settings') as create_mock:
397 model.create_repo_svn_settings(SVN_FORM_DATA)
403 model.create_repo_svn_settings(SVN_FORM_DATA)
398 create_mock.assert_called_once_with(model.repo_settings, SVN_FORM_DATA)
404 create_mock.assert_called_once_with(model.repo_settings, SVN_FORM_DATA)
399
405
400 def test_raises_exception_when_repository_is_not_specified(self):
406 def test_raises_exception_when_repository_is_not_specified(self):
401 model = VcsSettingsModel()
407 model = VcsSettingsModel()
402 with pytest.raises(Exception) as exc_info:
408 with pytest.raises(Exception) as exc_info:
403 model.create_repo_svn_settings(SVN_FORM_DATA)
409 model.create_repo_svn_settings(SVN_FORM_DATA)
404 assert exc_info.value.message == 'Repository is not specified'
410 assert exc_info.value.message == 'Repository is not specified'
405
411
406
412
407 class TestCreateSvnSettings(object):
413 class TestCreateSvnSettings(object):
408 def test_create(self, repo_stub):
414 def test_create(self, repo_stub):
409 model = VcsSettingsModel(repo=repo_stub.repo_name)
415 model = VcsSettingsModel(repo=repo_stub.repo_name)
410 model._create_svn_settings(model.repo_settings, SVN_FORM_DATA)
416 model._create_svn_settings(model.repo_settings, SVN_FORM_DATA)
411 Session().commit()
417 Session().commit()
412
418
413 branch_ui = model.repo_settings.get_ui_by_section(
419 branch_ui = model.repo_settings.get_ui_by_section(
414 model.SVN_BRANCH_SECTION)
420 model.SVN_BRANCH_SECTION)
415 tag_ui = model.repo_settings.get_ui_by_section(
421 tag_ui = model.repo_settings.get_ui_by_section(
416 model.SVN_TAG_SECTION)
422 model.SVN_TAG_SECTION)
417
423
418 try:
424 try:
419 assert len(branch_ui) == 1
425 assert len(branch_ui) == 1
420 assert len(tag_ui) == 1
426 assert len(tag_ui) == 1
421 finally:
427 finally:
422 Session().delete(branch_ui[0])
428 Session().delete(branch_ui[0])
423 Session().delete(tag_ui[0])
429 Session().delete(tag_ui[0])
424 Session().commit()
430 Session().commit()
425
431
426 def test_create_tag(self, repo_stub):
432 def test_create_tag(self, repo_stub):
427 model = VcsSettingsModel(repo=repo_stub.repo_name)
433 model = VcsSettingsModel(repo=repo_stub.repo_name)
428 data = SVN_FORM_DATA.copy()
434 data = SVN_FORM_DATA.copy()
429 data.pop('new_svn_branch')
435 data.pop('new_svn_branch')
430 model._create_svn_settings(model.repo_settings, data)
436 model._create_svn_settings(model.repo_settings, data)
431 Session().commit()
437 Session().commit()
432
438
433 branch_ui = model.repo_settings.get_ui_by_section(
439 branch_ui = model.repo_settings.get_ui_by_section(
434 model.SVN_BRANCH_SECTION)
440 model.SVN_BRANCH_SECTION)
435 tag_ui = model.repo_settings.get_ui_by_section(
441 tag_ui = model.repo_settings.get_ui_by_section(
436 model.SVN_TAG_SECTION)
442 model.SVN_TAG_SECTION)
437
443
438 try:
444 try:
439 assert len(branch_ui) == 0
445 assert len(branch_ui) == 0
440 assert len(tag_ui) == 1
446 assert len(tag_ui) == 1
441 finally:
447 finally:
442 Session().delete(tag_ui[0])
448 Session().delete(tag_ui[0])
443 Session().commit()
449 Session().commit()
444
450
445 def test_create_nothing_when_no_svn_settings_specified(self, repo_stub):
451 def test_create_nothing_when_no_svn_settings_specified(self, repo_stub):
446 model = VcsSettingsModel(repo=repo_stub.repo_name)
452 model = VcsSettingsModel(repo=repo_stub.repo_name)
447 model._create_svn_settings(model.repo_settings, {})
453 model._create_svn_settings(model.repo_settings, {})
448 Session().commit()
454 Session().commit()
449
455
450 branch_ui = model.repo_settings.get_ui_by_section(
456 branch_ui = model.repo_settings.get_ui_by_section(
451 model.SVN_BRANCH_SECTION)
457 model.SVN_BRANCH_SECTION)
452 tag_ui = model.repo_settings.get_ui_by_section(
458 tag_ui = model.repo_settings.get_ui_by_section(
453 model.SVN_TAG_SECTION)
459 model.SVN_TAG_SECTION)
454
460
455 assert len(branch_ui) == 0
461 assert len(branch_ui) == 0
456 assert len(tag_ui) == 0
462 assert len(tag_ui) == 0
457
463
458 def test_create_nothing_when_empty_settings_specified(self, repo_stub):
464 def test_create_nothing_when_empty_settings_specified(self, repo_stub):
459 model = VcsSettingsModel(repo=repo_stub.repo_name)
465 model = VcsSettingsModel(repo=repo_stub.repo_name)
460 data = {
466 data = {
461 'new_svn_branch': '',
467 'new_svn_branch': '',
462 'new_svn_tag': ''
468 'new_svn_tag': ''
463 }
469 }
464 model._create_svn_settings(model.repo_settings, data)
470 model._create_svn_settings(model.repo_settings, data)
465 Session().commit()
471 Session().commit()
466
472
467 branch_ui = model.repo_settings.get_ui_by_section(
473 branch_ui = model.repo_settings.get_ui_by_section(
468 model.SVN_BRANCH_SECTION)
474 model.SVN_BRANCH_SECTION)
469 tag_ui = model.repo_settings.get_ui_by_section(
475 tag_ui = model.repo_settings.get_ui_by_section(
470 model.SVN_TAG_SECTION)
476 model.SVN_TAG_SECTION)
471
477
472 assert len(branch_ui) == 0
478 assert len(branch_ui) == 0
473 assert len(tag_ui) == 0
479 assert len(tag_ui) == 0
474
480
475
481
476 class TestCreateOrUpdateUi(object):
482 class TestCreateOrUpdateUi(object):
477 def test_create(self, repo_stub):
483 def test_create(self, repo_stub):
478 model = VcsSettingsModel(repo=repo_stub.repo_name)
484 model = VcsSettingsModel(repo=repo_stub.repo_name)
479 model._create_or_update_ui(
485 model._create_or_update_ui(
480 model.repo_settings, 'test-section', 'test-key', active=False,
486 model.repo_settings, 'test-section', 'test-key', active=False,
481 value='False')
487 value='False')
482 Session().commit()
488 Session().commit()
483
489
484 created_ui = model.repo_settings.get_ui_by_section_and_key(
490 created_ui = model.repo_settings.get_ui_by_section_and_key(
485 'test-section', 'test-key')
491 'test-section', 'test-key')
486
492
487 try:
493 try:
488 assert created_ui.ui_active is False
494 assert created_ui.ui_active is False
489 assert str2bool(created_ui.ui_value) is False
495 assert str2bool(created_ui.ui_value) is False
490 finally:
496 finally:
491 Session().delete(created_ui)
497 Session().delete(created_ui)
492 Session().commit()
498 Session().commit()
493
499
494 def test_update(self, repo_stub, settings_util):
500 def test_update(self, repo_stub, settings_util):
495 model = VcsSettingsModel(repo=repo_stub.repo_name)
501 model = VcsSettingsModel(repo=repo_stub.repo_name)
496
502
497 largefiles, phases = model.HG_SETTINGS
503 largefiles, phases = model.HG_SETTINGS
498 section = 'test-section'
504 section = 'test-section'
499 key = 'test-key'
505 key = 'test-key'
500 settings_util.create_repo_rhodecode_ui(
506 settings_util.create_repo_rhodecode_ui(
501 repo_stub, section, 'True', key=key, active=True)
507 repo_stub, section, 'True', key=key, active=True)
502
508
503 model._create_or_update_ui(
509 model._create_or_update_ui(
504 model.repo_settings, section, key, active=False, value='False')
510 model.repo_settings, section, key, active=False, value='False')
505 Session().commit()
511 Session().commit()
506
512
507 created_ui = model.repo_settings.get_ui_by_section_and_key(
513 created_ui = model.repo_settings.get_ui_by_section_and_key(
508 section, key)
514 section, key)
509 assert created_ui.ui_active is False
515 assert created_ui.ui_active is False
510 assert str2bool(created_ui.ui_value) is False
516 assert str2bool(created_ui.ui_value) is False
511
517
512
518
513 class TestCreateOrUpdateRepoHgSettings(object):
519 class TestCreateOrUpdateRepoHgSettings(object):
514 FORM_DATA = {
520 FORM_DATA = {
515 'extensions_largefiles': False,
521 'extensions_largefiles': False,
516 'phases_publish': False
522 'phases_publish': False
517 }
523 }
518
524
519 def test_creates_repo_hg_settings_when_data_is_correct(self, repo_stub):
525 def test_creates_repo_hg_settings_when_data_is_correct(self, repo_stub):
520 model = VcsSettingsModel(repo=repo_stub.repo_name)
526 model = VcsSettingsModel(repo=repo_stub.repo_name)
521 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
527 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
522 model.create_or_update_repo_hg_settings(self.FORM_DATA)
528 model.create_or_update_repo_hg_settings(self.FORM_DATA)
523 expected_calls = [
529 expected_calls = [
524 mock.call(model.repo_settings, 'extensions', 'largefiles',
530 mock.call(model.repo_settings, 'extensions', 'largefiles',
525 active=False, value=''),
531 active=False, value=''),
526 mock.call(model.repo_settings, 'phases', 'publish', value='False'),
532 mock.call(model.repo_settings, 'phases', 'publish', value='False'),
527 ]
533 ]
528 assert expected_calls == create_mock.call_args_list
534 assert expected_calls == create_mock.call_args_list
529
535
530 @pytest.mark.parametrize('field_to_remove', FORM_DATA.keys())
536 @pytest.mark.parametrize('field_to_remove', FORM_DATA.keys())
531 def test_key_is_not_found(self, repo_stub, field_to_remove):
537 def test_key_is_not_found(self, repo_stub, field_to_remove):
532 model = VcsSettingsModel(repo=repo_stub.repo_name)
538 model = VcsSettingsModel(repo=repo_stub.repo_name)
533 data = self.FORM_DATA.copy()
539 data = self.FORM_DATA.copy()
534 data.pop(field_to_remove)
540 data.pop(field_to_remove)
535 with pytest.raises(ValueError) as exc_info:
541 with pytest.raises(ValueError) as exc_info:
536 model.create_or_update_repo_hg_settings(data)
542 model.create_or_update_repo_hg_settings(data)
537 expected_message = 'The given data does not contain {} key'.format(
543 expected_message = 'The given data does not contain {} key'.format(
538 field_to_remove)
544 field_to_remove)
539 assert exc_info.value.message == expected_message
545 assert exc_info.value.message == expected_message
540
546
541 def test_create_raises_exception_when_repository_not_specified(self):
547 def test_create_raises_exception_when_repository_not_specified(self):
542 model = VcsSettingsModel()
548 model = VcsSettingsModel()
543 with pytest.raises(Exception) as exc_info:
549 with pytest.raises(Exception) as exc_info:
544 model.create_or_update_repo_hg_settings(self.FORM_DATA)
550 model.create_or_update_repo_hg_settings(self.FORM_DATA)
545 assert exc_info.value.message == 'Repository is not specified'
551 assert exc_info.value.message == 'Repository is not specified'
546
552
547
553
548 class TestUpdateGlobalSslSetting(object):
554 class TestUpdateGlobalSslSetting(object):
549 def test_updates_global_hg_settings(self):
555 def test_updates_global_hg_settings(self):
550 model = VcsSettingsModel()
556 model = VcsSettingsModel()
551 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
557 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
552 model.update_global_ssl_setting('False')
558 model.update_global_ssl_setting('False')
553 create_mock.assert_called_once_with(
559 create_mock.assert_called_once_with(
554 model.global_settings, 'web', 'push_ssl', value='False')
560 model.global_settings, 'web', 'push_ssl', value='False')
555
561
556
562
557 class TestUpdateGlobalPathSetting(object):
563 class TestUpdateGlobalPathSetting(object):
558 def test_updates_global_path_settings(self):
564 def test_updates_global_path_settings(self):
559 model = VcsSettingsModel()
565 model = VcsSettingsModel()
560 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
566 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
561 model.update_global_path_setting('False')
567 model.update_global_path_setting('False')
562 create_mock.assert_called_once_with(
568 create_mock.assert_called_once_with(
563 model.global_settings, 'paths', '/', value='False')
569 model.global_settings, 'paths', '/', value='False')
564
570
565
571
566 class TestCreateOrUpdateGlobalHgSettings(object):
572 class TestCreateOrUpdateGlobalHgSettings(object):
567 FORM_DATA = {
573 FORM_DATA = {
568 'extensions_largefiles': False,
574 'extensions_largefiles': False,
569 'largefiles_usercache': '/example/largefiles-store',
575 'largefiles_usercache': '/example/largefiles-store',
570 'phases_publish': False,
576 'phases_publish': False,
571 'extensions_hgsubversion': False
577 'extensions_hgsubversion': False
572 }
578 }
573
579
574 def test_creates_repo_hg_settings_when_data_is_correct(self):
580 def test_creates_repo_hg_settings_when_data_is_correct(self):
575 model = VcsSettingsModel()
581 model = VcsSettingsModel()
576 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
582 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
577 model.create_or_update_global_hg_settings(self.FORM_DATA)
583 model.create_or_update_global_hg_settings(self.FORM_DATA)
578 expected_calls = [
584 expected_calls = [
579 mock.call(model.global_settings, 'extensions', 'largefiles',
585 mock.call(model.global_settings, 'extensions', 'largefiles',
580 active=False, value=''),
586 active=False, value=''),
581 mock.call(model.global_settings, 'largefiles', 'usercache',
587 mock.call(model.global_settings, 'largefiles', 'usercache',
582 value='/example/largefiles-store'),
588 value='/example/largefiles-store'),
583 mock.call(model.global_settings, 'phases', 'publish',
589 mock.call(model.global_settings, 'phases', 'publish',
584 value='False'),
590 value='False'),
585 mock.call(model.global_settings, 'extensions', 'hgsubversion',
591 mock.call(model.global_settings, 'extensions', 'hgsubversion',
586 active=False)
592 active=False)
587 ]
593 ]
588 assert expected_calls == create_mock.call_args_list
594 assert expected_calls == create_mock.call_args_list
589
595
590 @pytest.mark.parametrize('field_to_remove', FORM_DATA.keys())
596 @pytest.mark.parametrize('field_to_remove', FORM_DATA.keys())
591 def test_key_is_not_found(self, repo_stub, field_to_remove):
597 def test_key_is_not_found(self, repo_stub, field_to_remove):
592 model = VcsSettingsModel(repo=repo_stub.repo_name)
598 model = VcsSettingsModel(repo=repo_stub.repo_name)
593 data = self.FORM_DATA.copy()
599 data = self.FORM_DATA.copy()
594 data.pop(field_to_remove)
600 data.pop(field_to_remove)
595 with pytest.raises(Exception) as exc_info:
601 with pytest.raises(Exception) as exc_info:
596 model.create_or_update_global_hg_settings(data)
602 model.create_or_update_global_hg_settings(data)
597 expected_message = 'The given data does not contain {} key'.format(
603 expected_message = 'The given data does not contain {} key'.format(
598 field_to_remove)
604 field_to_remove)
599 assert exc_info.value.message == expected_message
605 assert exc_info.value.message == expected_message
600
606
601
607
608 class TestCreateOrUpdateGlobalGitSettings(object):
609 FORM_DATA = {
610 'vcs_git_lfs_enabled': False,
611 'vcs_git_lfs_store_location': '/example/lfs-store',
612 }
613
614 def test_creates_repo_hg_settings_when_data_is_correct(self):
615 model = VcsSettingsModel()
616 with mock.patch.object(model, '_create_or_update_ui') as create_mock:
617 model.create_or_update_global_git_settings(self.FORM_DATA)
618 expected_calls = [
619 mock.call(model.global_settings, 'vcs_git_lfs', 'enabled',
620 active=False, value=False),
621 mock.call(model.global_settings, 'vcs_git_lfs', 'store_location',
622 value='/example/lfs-store'),
623 ]
624 assert expected_calls == create_mock.call_args_list
625
626
602 class TestDeleteRepoSvnPattern(object):
627 class TestDeleteRepoSvnPattern(object):
603 def test_success_when_repo_is_set(self, backend_svn):
628 def test_success_when_repo_is_set(self, backend_svn):
604 repo_name = backend_svn.repo_name
629 repo_name = backend_svn.repo_name
605 model = VcsSettingsModel(repo=repo_name)
630 model = VcsSettingsModel(repo=repo_name)
606 delete_ui_patch = mock.patch.object(model.repo_settings, 'delete_ui')
631 delete_ui_patch = mock.patch.object(model.repo_settings, 'delete_ui')
607 with delete_ui_patch as delete_ui_mock:
632 with delete_ui_patch as delete_ui_mock:
608 model.delete_repo_svn_pattern(123)
633 model.delete_repo_svn_pattern(123)
609 delete_ui_mock.assert_called_once_with(123)
634 delete_ui_mock.assert_called_once_with(123)
610
635
611 def test_raises_exception_when_repository_is_not_specified(self):
636 def test_raises_exception_when_repository_is_not_specified(self):
612 model = VcsSettingsModel()
637 model = VcsSettingsModel()
613 with pytest.raises(Exception) as exc_info:
638 with pytest.raises(Exception) as exc_info:
614 model.delete_repo_svn_pattern(123)
639 model.delete_repo_svn_pattern(123)
615 assert exc_info.value.message == 'Repository is not specified'
640 assert exc_info.value.message == 'Repository is not specified'
616
641
617
642
618 class TestDeleteGlobalSvnPattern(object):
643 class TestDeleteGlobalSvnPattern(object):
619 def test_delete_global_svn_pattern_calls_delete_ui(self):
644 def test_delete_global_svn_pattern_calls_delete_ui(self):
620 model = VcsSettingsModel()
645 model = VcsSettingsModel()
621 delete_ui_patch = mock.patch.object(model.global_settings, 'delete_ui')
646 delete_ui_patch = mock.patch.object(model.global_settings, 'delete_ui')
622 with delete_ui_patch as delete_ui_mock:
647 with delete_ui_patch as delete_ui_mock:
623 model.delete_global_svn_pattern(123)
648 model.delete_global_svn_pattern(123)
624 delete_ui_mock.assert_called_once_with(123)
649 delete_ui_mock.assert_called_once_with(123)
625
650
626
651
627 class TestFilterUiSettings(object):
652 class TestFilterUiSettings(object):
628 def test_settings_are_filtered(self):
653 def test_settings_are_filtered(self):
629 model = VcsSettingsModel()
654 model = VcsSettingsModel()
630 repo_settings = [
655 repo_settings = [
631 UiSetting('extensions', 'largefiles', '', True),
656 UiSetting('extensions', 'largefiles', '', True),
632 UiSetting('phases', 'publish', 'True', True),
657 UiSetting('phases', 'publish', 'True', True),
633 UiSetting('hooks', 'changegroup.repo_size', 'hook', True),
658 UiSetting('hooks', 'changegroup.repo_size', 'hook', True),
634 UiSetting('hooks', 'changegroup.push_logger', 'hook', True),
659 UiSetting('hooks', 'changegroup.push_logger', 'hook', True),
635 UiSetting('hooks', 'outgoing.pull_logger', 'hook', True),
660 UiSetting('hooks', 'outgoing.pull_logger', 'hook', True),
636 UiSetting(
661 UiSetting(
637 'vcs_svn_branch', '84223c972204fa545ca1b22dac7bef5b68d7442d',
662 'vcs_svn_branch', '84223c972204fa545ca1b22dac7bef5b68d7442d',
638 'test_branch', True),
663 'test_branch', True),
639 UiSetting(
664 UiSetting(
640 'vcs_svn_tag', '84229c972204fa545ca1b22dac7bef5b68d7442d',
665 'vcs_svn_tag', '84229c972204fa545ca1b22dac7bef5b68d7442d',
641 'test_tag', True),
666 'test_tag', True),
642 ]
667 ]
643 non_repo_settings = [
668 non_repo_settings = [
644 UiSetting('largefiles', 'usercache', '/example/largefiles-store', True),
669 UiSetting('largefiles', 'usercache', '/example/largefiles-store', True),
645 UiSetting('test', 'outgoing.pull_logger', 'hook', True),
670 UiSetting('test', 'outgoing.pull_logger', 'hook', True),
646 UiSetting('hooks', 'test2', 'hook', True),
671 UiSetting('hooks', 'test2', 'hook', True),
647 UiSetting(
672 UiSetting(
648 'vcs_svn_repo', '84229c972204fa545ca1b22dac7bef5b68d7442d',
673 'vcs_svn_repo', '84229c972204fa545ca1b22dac7bef5b68d7442d',
649 'test_tag', True),
674 'test_tag', True),
650 ]
675 ]
651 settings = repo_settings + non_repo_settings
676 settings = repo_settings + non_repo_settings
652 filtered_settings = model._filter_ui_settings(settings)
677 filtered_settings = model._filter_ui_settings(settings)
653 assert sorted(filtered_settings) == sorted(repo_settings)
678 assert sorted(filtered_settings) == sorted(repo_settings)
654
679
655
680
656 class TestFilterGeneralSettings(object):
681 class TestFilterGeneralSettings(object):
657 def test_settings_are_filtered(self):
682 def test_settings_are_filtered(self):
658 model = VcsSettingsModel()
683 model = VcsSettingsModel()
659 settings = {
684 settings = {
660 'rhodecode_abcde': 'value1',
685 'rhodecode_abcde': 'value1',
661 'rhodecode_vwxyz': 'value2',
686 'rhodecode_vwxyz': 'value2',
662 }
687 }
663 general_settings = {
688 general_settings = {
664 'rhodecode_{}'.format(key): 'value'
689 'rhodecode_{}'.format(key): 'value'
665 for key in VcsSettingsModel.GENERAL_SETTINGS
690 for key in VcsSettingsModel.GENERAL_SETTINGS
666 }
691 }
667 settings.update(general_settings)
692 settings.update(general_settings)
668
693
669 filtered_settings = model._filter_general_settings(general_settings)
694 filtered_settings = model._filter_general_settings(general_settings)
670 assert sorted(filtered_settings) == sorted(general_settings)
695 assert sorted(filtered_settings) == sorted(general_settings)
671
696
672
697
673 class TestGetRepoUiSettings(object):
698 class TestGetRepoUiSettings(object):
674 def test_global_uis_are_returned_when_no_repo_uis_found(
699 def test_global_uis_are_returned_when_no_repo_uis_found(
675 self, repo_stub):
700 self, repo_stub):
676 model = VcsSettingsModel(repo=repo_stub.repo_name)
701 model = VcsSettingsModel(repo=repo_stub.repo_name)
677 result = model.get_repo_ui_settings()
702 result = model.get_repo_ui_settings()
678 svn_sections = (
703 svn_sections = (
679 VcsSettingsModel.SVN_TAG_SECTION,
704 VcsSettingsModel.SVN_TAG_SECTION,
680 VcsSettingsModel.SVN_BRANCH_SECTION)
705 VcsSettingsModel.SVN_BRANCH_SECTION)
681 expected_result = [
706 expected_result = [
682 s for s in model.global_settings.get_ui()
707 s for s in model.global_settings.get_ui()
683 if s.section not in svn_sections]
708 if s.section not in svn_sections]
684 assert sorted(result) == sorted(expected_result)
709 assert sorted(result) == sorted(expected_result)
685
710
686 def test_repo_uis_are_overriding_global_uis(
711 def test_repo_uis_are_overriding_global_uis(
687 self, repo_stub, settings_util):
712 self, repo_stub, settings_util):
688 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
713 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
689 settings_util.create_repo_rhodecode_ui(
714 settings_util.create_repo_rhodecode_ui(
690 repo_stub, section, 'repo', key=key, active=False)
715 repo_stub, section, 'repo', key=key, active=False)
691 model = VcsSettingsModel(repo=repo_stub.repo_name)
716 model = VcsSettingsModel(repo=repo_stub.repo_name)
692 result = model.get_repo_ui_settings()
717 result = model.get_repo_ui_settings()
693 for setting in result:
718 for setting in result:
694 locator = (setting.section, setting.key)
719 locator = (setting.section, setting.key)
695 if locator in VcsSettingsModel.HOOKS_SETTINGS:
720 if locator in VcsSettingsModel.HOOKS_SETTINGS:
696 assert setting.value == 'repo'
721 assert setting.value == 'repo'
697
722
698 assert setting.active is False
723 assert setting.active is False
699
724
700 def test_global_svn_patterns_are_not_in_list(
725 def test_global_svn_patterns_are_not_in_list(
701 self, repo_stub, settings_util):
726 self, repo_stub, settings_util):
702 svn_sections = (
727 svn_sections = (
703 VcsSettingsModel.SVN_TAG_SECTION,
728 VcsSettingsModel.SVN_TAG_SECTION,
704 VcsSettingsModel.SVN_BRANCH_SECTION)
729 VcsSettingsModel.SVN_BRANCH_SECTION)
705 for section in svn_sections:
730 for section in svn_sections:
706 settings_util.create_rhodecode_ui(
731 settings_util.create_rhodecode_ui(
707 section, 'repo', key='deadbeef' + section, active=False)
732 section, 'repo', key='deadbeef' + section, active=False)
708 model = VcsSettingsModel(repo=repo_stub.repo_name)
733 model = VcsSettingsModel(repo=repo_stub.repo_name)
709 result = model.get_repo_ui_settings()
734 result = model.get_repo_ui_settings()
710 for setting in result:
735 for setting in result:
711 assert setting.section not in svn_sections
736 assert setting.section not in svn_sections
712
737
713 def test_repo_uis_filtered_by_section_are_returned(
738 def test_repo_uis_filtered_by_section_are_returned(
714 self, repo_stub, settings_util):
739 self, repo_stub, settings_util):
715 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
740 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
716 settings_util.create_repo_rhodecode_ui(
741 settings_util.create_repo_rhodecode_ui(
717 repo_stub, section, 'repo', key=key, active=False)
742 repo_stub, section, 'repo', key=key, active=False)
718 model = VcsSettingsModel(repo=repo_stub.repo_name)
743 model = VcsSettingsModel(repo=repo_stub.repo_name)
719 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
744 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
720 result = model.get_repo_ui_settings(section=section)
745 result = model.get_repo_ui_settings(section=section)
721 for setting in result:
746 for setting in result:
722 assert setting.section == section
747 assert setting.section == section
723
748
724 def test_repo_uis_filtered_by_key_are_returned(
749 def test_repo_uis_filtered_by_key_are_returned(
725 self, repo_stub, settings_util):
750 self, repo_stub, settings_util):
726 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
751 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
727 settings_util.create_repo_rhodecode_ui(
752 settings_util.create_repo_rhodecode_ui(
728 repo_stub, section, 'repo', key=key, active=False)
753 repo_stub, section, 'repo', key=key, active=False)
729 model = VcsSettingsModel(repo=repo_stub.repo_name)
754 model = VcsSettingsModel(repo=repo_stub.repo_name)
730 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
755 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
731 result = model.get_repo_ui_settings(key=key)
756 result = model.get_repo_ui_settings(key=key)
732 for setting in result:
757 for setting in result:
733 assert setting.key == key
758 assert setting.key == key
734
759
735 def test_raises_exception_when_repository_is_not_specified(self):
760 def test_raises_exception_when_repository_is_not_specified(self):
736 model = VcsSettingsModel()
761 model = VcsSettingsModel()
737 with pytest.raises(Exception) as exc_info:
762 with pytest.raises(Exception) as exc_info:
738 model.get_repo_ui_settings()
763 model.get_repo_ui_settings()
739 assert exc_info.value.message == 'Repository is not specified'
764 assert exc_info.value.message == 'Repository is not specified'
740
765
741
766
742 class TestGetRepoGeneralSettings(object):
767 class TestGetRepoGeneralSettings(object):
743 def test_global_settings_are_returned_when_no_repo_settings_found(
768 def test_global_settings_are_returned_when_no_repo_settings_found(
744 self, repo_stub):
769 self, repo_stub):
745 model = VcsSettingsModel(repo=repo_stub.repo_name)
770 model = VcsSettingsModel(repo=repo_stub.repo_name)
746 result = model.get_repo_general_settings()
771 result = model.get_repo_general_settings()
747 expected_result = model.global_settings.get_all_settings()
772 expected_result = model.global_settings.get_all_settings()
748 assert sorted(result) == sorted(expected_result)
773 assert sorted(result) == sorted(expected_result)
749
774
750 def test_repo_uis_are_overriding_global_uis(
775 def test_repo_uis_are_overriding_global_uis(
751 self, repo_stub, settings_util):
776 self, repo_stub, settings_util):
752 for key in VcsSettingsModel.GENERAL_SETTINGS:
777 for key in VcsSettingsModel.GENERAL_SETTINGS:
753 settings_util.create_repo_rhodecode_setting(
778 settings_util.create_repo_rhodecode_setting(
754 repo_stub, key, 'abcde', type_='unicode')
779 repo_stub, key, 'abcde', type_='unicode')
755 model = VcsSettingsModel(repo=repo_stub.repo_name)
780 model = VcsSettingsModel(repo=repo_stub.repo_name)
756 result = model.get_repo_ui_settings()
781 result = model.get_repo_ui_settings()
757 for key in result:
782 for key in result:
758 if key in VcsSettingsModel.GENERAL_SETTINGS:
783 if key in VcsSettingsModel.GENERAL_SETTINGS:
759 assert result[key] == 'abcde'
784 assert result[key] == 'abcde'
760
785
761 def test_raises_exception_when_repository_is_not_specified(self):
786 def test_raises_exception_when_repository_is_not_specified(self):
762 model = VcsSettingsModel()
787 model = VcsSettingsModel()
763 with pytest.raises(Exception) as exc_info:
788 with pytest.raises(Exception) as exc_info:
764 model.get_repo_general_settings()
789 model.get_repo_general_settings()
765 assert exc_info.value.message == 'Repository is not specified'
790 assert exc_info.value.message == 'Repository is not specified'
766
791
767
792
768 class TestGetGlobalGeneralSettings(object):
793 class TestGetGlobalGeneralSettings(object):
769 def test_global_settings_are_returned(self, repo_stub):
794 def test_global_settings_are_returned(self, repo_stub):
770 model = VcsSettingsModel()
795 model = VcsSettingsModel()
771 result = model.get_global_general_settings()
796 result = model.get_global_general_settings()
772 expected_result = model.global_settings.get_all_settings()
797 expected_result = model.global_settings.get_all_settings()
773 assert sorted(result) == sorted(expected_result)
798 assert sorted(result) == sorted(expected_result)
774
799
775 def test_repo_uis_are_not_overriding_global_uis(
800 def test_repo_uis_are_not_overriding_global_uis(
776 self, repo_stub, settings_util):
801 self, repo_stub, settings_util):
777 for key in VcsSettingsModel.GENERAL_SETTINGS:
802 for key in VcsSettingsModel.GENERAL_SETTINGS:
778 settings_util.create_repo_rhodecode_setting(
803 settings_util.create_repo_rhodecode_setting(
779 repo_stub, key, 'abcde', type_='unicode')
804 repo_stub, key, 'abcde', type_='unicode')
780 model = VcsSettingsModel(repo=repo_stub.repo_name)
805 model = VcsSettingsModel(repo=repo_stub.repo_name)
781 result = model.get_global_general_settings()
806 result = model.get_global_general_settings()
782 expected_result = model.global_settings.get_all_settings()
807 expected_result = model.global_settings.get_all_settings()
783 assert sorted(result) == sorted(expected_result)
808 assert sorted(result) == sorted(expected_result)
784
809
785
810
786 class TestGetGlobalUiSettings(object):
811 class TestGetGlobalUiSettings(object):
787 def test_global_uis_are_returned(self, repo_stub):
812 def test_global_uis_are_returned(self, repo_stub):
788 model = VcsSettingsModel()
813 model = VcsSettingsModel()
789 result = model.get_global_ui_settings()
814 result = model.get_global_ui_settings()
790 expected_result = model.global_settings.get_ui()
815 expected_result = model.global_settings.get_ui()
791 assert sorted(result) == sorted(expected_result)
816 assert sorted(result) == sorted(expected_result)
792
817
793 def test_repo_uis_are_not_overriding_global_uis(
818 def test_repo_uis_are_not_overriding_global_uis(
794 self, repo_stub, settings_util):
819 self, repo_stub, settings_util):
795 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
820 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
796 settings_util.create_repo_rhodecode_ui(
821 settings_util.create_repo_rhodecode_ui(
797 repo_stub, section, 'repo', key=key, active=False)
822 repo_stub, section, 'repo', key=key, active=False)
798 model = VcsSettingsModel(repo=repo_stub.repo_name)
823 model = VcsSettingsModel(repo=repo_stub.repo_name)
799 result = model.get_global_ui_settings()
824 result = model.get_global_ui_settings()
800 expected_result = model.global_settings.get_ui()
825 expected_result = model.global_settings.get_ui()
801 assert sorted(result) == sorted(expected_result)
826 assert sorted(result) == sorted(expected_result)
802
827
803 def test_ui_settings_filtered_by_section(
828 def test_ui_settings_filtered_by_section(
804 self, repo_stub, settings_util):
829 self, repo_stub, settings_util):
805 model = VcsSettingsModel(repo=repo_stub.repo_name)
830 model = VcsSettingsModel(repo=repo_stub.repo_name)
806 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
831 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
807 result = model.get_global_ui_settings(section=section)
832 result = model.get_global_ui_settings(section=section)
808 expected_result = model.global_settings.get_ui(section=section)
833 expected_result = model.global_settings.get_ui(section=section)
809 assert sorted(result) == sorted(expected_result)
834 assert sorted(result) == sorted(expected_result)
810
835
811 def test_ui_settings_filtered_by_key(
836 def test_ui_settings_filtered_by_key(
812 self, repo_stub, settings_util):
837 self, repo_stub, settings_util):
813 model = VcsSettingsModel(repo=repo_stub.repo_name)
838 model = VcsSettingsModel(repo=repo_stub.repo_name)
814 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
839 section, key = VcsSettingsModel.HOOKS_SETTINGS[0]
815 result = model.get_global_ui_settings(key=key)
840 result = model.get_global_ui_settings(key=key)
816 expected_result = model.global_settings.get_ui(key=key)
841 expected_result = model.global_settings.get_ui(key=key)
817 assert sorted(result) == sorted(expected_result)
842 assert sorted(result) == sorted(expected_result)
818
843
819
844
820 class TestGetGeneralSettings(object):
845 class TestGetGeneralSettings(object):
821 def test_global_settings_are_returned_when_inherited_is_true(
846 def test_global_settings_are_returned_when_inherited_is_true(
822 self, repo_stub, settings_util):
847 self, repo_stub, settings_util):
823 model = VcsSettingsModel(repo=repo_stub.repo_name)
848 model = VcsSettingsModel(repo=repo_stub.repo_name)
824 model.inherit_global_settings = True
849 model.inherit_global_settings = True
825 for key in VcsSettingsModel.GENERAL_SETTINGS:
850 for key in VcsSettingsModel.GENERAL_SETTINGS:
826 settings_util.create_repo_rhodecode_setting(
851 settings_util.create_repo_rhodecode_setting(
827 repo_stub, key, 'abcde', type_='unicode')
852 repo_stub, key, 'abcde', type_='unicode')
828 result = model.get_general_settings()
853 result = model.get_general_settings()
829 expected_result = model.get_global_general_settings()
854 expected_result = model.get_global_general_settings()
830 assert sorted(result) == sorted(expected_result)
855 assert sorted(result) == sorted(expected_result)
831
856
832 def test_repo_settings_are_returned_when_inherited_is_false(
857 def test_repo_settings_are_returned_when_inherited_is_false(
833 self, repo_stub, settings_util):
858 self, repo_stub, settings_util):
834 model = VcsSettingsModel(repo=repo_stub.repo_name)
859 model = VcsSettingsModel(repo=repo_stub.repo_name)
835 model.inherit_global_settings = False
860 model.inherit_global_settings = False
836 for key in VcsSettingsModel.GENERAL_SETTINGS:
861 for key in VcsSettingsModel.GENERAL_SETTINGS:
837 settings_util.create_repo_rhodecode_setting(
862 settings_util.create_repo_rhodecode_setting(
838 repo_stub, key, 'abcde', type_='unicode')
863 repo_stub, key, 'abcde', type_='unicode')
839 result = model.get_general_settings()
864 result = model.get_general_settings()
840 expected_result = model.get_repo_general_settings()
865 expected_result = model.get_repo_general_settings()
841 assert sorted(result) == sorted(expected_result)
866 assert sorted(result) == sorted(expected_result)
842
867
843 def test_global_settings_are_returned_when_no_repository_specified(self):
868 def test_global_settings_are_returned_when_no_repository_specified(self):
844 model = VcsSettingsModel()
869 model = VcsSettingsModel()
845 result = model.get_general_settings()
870 result = model.get_general_settings()
846 expected_result = model.get_global_general_settings()
871 expected_result = model.get_global_general_settings()
847 assert sorted(result) == sorted(expected_result)
872 assert sorted(result) == sorted(expected_result)
848
873
849
874
850 class TestGetUiSettings(object):
875 class TestGetUiSettings(object):
851 def test_global_settings_are_returned_when_inherited_is_true(
876 def test_global_settings_are_returned_when_inherited_is_true(
852 self, repo_stub, settings_util):
877 self, repo_stub, settings_util):
853 model = VcsSettingsModel(repo=repo_stub.repo_name)
878 model = VcsSettingsModel(repo=repo_stub.repo_name)
854 model.inherit_global_settings = True
879 model.inherit_global_settings = True
855 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
880 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
856 settings_util.create_repo_rhodecode_ui(
881 settings_util.create_repo_rhodecode_ui(
857 repo_stub, section, 'repo', key=key, active=True)
882 repo_stub, section, 'repo', key=key, active=True)
858 result = model.get_ui_settings()
883 result = model.get_ui_settings()
859 expected_result = model.get_global_ui_settings()
884 expected_result = model.get_global_ui_settings()
860 assert sorted(result) == sorted(expected_result)
885 assert sorted(result) == sorted(expected_result)
861
886
862 def test_repo_settings_are_returned_when_inherited_is_false(
887 def test_repo_settings_are_returned_when_inherited_is_false(
863 self, repo_stub, settings_util):
888 self, repo_stub, settings_util):
864 model = VcsSettingsModel(repo=repo_stub.repo_name)
889 model = VcsSettingsModel(repo=repo_stub.repo_name)
865 model.inherit_global_settings = False
890 model.inherit_global_settings = False
866 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
891 for section, key in VcsSettingsModel.HOOKS_SETTINGS:
867 settings_util.create_repo_rhodecode_ui(
892 settings_util.create_repo_rhodecode_ui(
868 repo_stub, section, 'repo', key=key, active=True)
893 repo_stub, section, 'repo', key=key, active=True)
869 result = model.get_ui_settings()
894 result = model.get_ui_settings()
870 expected_result = model.get_repo_ui_settings()
895 expected_result = model.get_repo_ui_settings()
871 assert sorted(result) == sorted(expected_result)
896 assert sorted(result) == sorted(expected_result)
872
897
873 def test_repo_settings_filtered_by_section_and_key(self, repo_stub):
898 def test_repo_settings_filtered_by_section_and_key(self, repo_stub):
874 model = VcsSettingsModel(repo=repo_stub.repo_name)
899 model = VcsSettingsModel(repo=repo_stub.repo_name)
875 model.inherit_global_settings = False
900 model.inherit_global_settings = False
876 args = ('section', 'key')
901 args = ('section', 'key')
877 with mock.patch.object(model, 'get_repo_ui_settings') as settings_mock:
902 with mock.patch.object(model, 'get_repo_ui_settings') as settings_mock:
878 model.get_ui_settings(*args)
903 model.get_ui_settings(*args)
879 settings_mock.assert_called_once_with(*args)
904 settings_mock.assert_called_once_with(*args)
880
905
881 def test_global_settings_filtered_by_section_and_key(self):
906 def test_global_settings_filtered_by_section_and_key(self):
882 model = VcsSettingsModel()
907 model = VcsSettingsModel()
883 args = ('section', 'key')
908 args = ('section', 'key')
884 with mock.patch.object(model, 'get_global_ui_settings') as (
909 with mock.patch.object(model, 'get_global_ui_settings') as (
885 settings_mock):
910 settings_mock):
886 model.get_ui_settings(*args)
911 model.get_ui_settings(*args)
887 settings_mock.assert_called_once_with(*args)
912 settings_mock.assert_called_once_with(*args)
888
913
889 def test_global_settings_are_returned_when_no_repository_specified(self):
914 def test_global_settings_are_returned_when_no_repository_specified(self):
890 model = VcsSettingsModel()
915 model = VcsSettingsModel()
891 result = model.get_ui_settings()
916 result = model.get_ui_settings()
892 expected_result = model.get_global_ui_settings()
917 expected_result = model.get_global_ui_settings()
893 assert sorted(result) == sorted(expected_result)
918 assert sorted(result) == sorted(expected_result)
894
919
895
920
896 class TestGetSvnPatterns(object):
921 class TestGetSvnPatterns(object):
897 def test_repo_settings_filtered_by_section_and_key(self, repo_stub):
922 def test_repo_settings_filtered_by_section_and_key(self, repo_stub):
898 model = VcsSettingsModel(repo=repo_stub.repo_name)
923 model = VcsSettingsModel(repo=repo_stub.repo_name)
899 args = ('section', )
924 args = ('section', )
900 with mock.patch.object(model, 'get_repo_ui_settings') as settings_mock:
925 with mock.patch.object(model, 'get_repo_ui_settings') as settings_mock:
901 model.get_svn_patterns(*args)
926 model.get_svn_patterns(*args)
902 settings_mock.assert_called_once_with(*args)
927 settings_mock.assert_called_once_with(*args)
903
928
904 def test_global_settings_filtered_by_section_and_key(self):
929 def test_global_settings_filtered_by_section_and_key(self):
905 model = VcsSettingsModel()
930 model = VcsSettingsModel()
906 args = ('section', )
931 args = ('section', )
907 with mock.patch.object(model, 'get_global_ui_settings') as (
932 with mock.patch.object(model, 'get_global_ui_settings') as (
908 settings_mock):
933 settings_mock):
909 model.get_svn_patterns(*args)
934 model.get_svn_patterns(*args)
910 settings_mock.assert_called_once_with(*args)
935 settings_mock.assert_called_once_with(*args)
911
936
912
937
913 class TestGetReposLocation(object):
938 class TestGetReposLocation(object):
914 def test_returns_repos_location(self, repo_stub):
939 def test_returns_repos_location(self, repo_stub):
915 model = VcsSettingsModel()
940 model = VcsSettingsModel()
916
941
917 result_mock = mock.Mock()
942 result_mock = mock.Mock()
918 result_mock.ui_value = '/tmp'
943 result_mock.ui_value = '/tmp'
919
944
920 with mock.patch.object(model, 'global_settings') as settings_mock:
945 with mock.patch.object(model, 'global_settings') as settings_mock:
921 settings_mock.get_ui_by_key.return_value = result_mock
946 settings_mock.get_ui_by_key.return_value = result_mock
922 result = model.get_repos_location()
947 result = model.get_repos_location()
923
948
924 settings_mock.get_ui_by_key.assert_called_once_with('/')
949 settings_mock.get_ui_by_key.assert_called_once_with('/')
925 assert result == '/tmp'
950 assert result == '/tmp'
926
951
927
952
928 class TestCreateOrUpdateRepoSettings(object):
953 class TestCreateOrUpdateRepoSettings(object):
929 FORM_DATA = {
954 FORM_DATA = {
930 'inherit_global_settings': False,
955 'inherit_global_settings': False,
931 'hooks_changegroup_repo_size': False,
956 'hooks_changegroup_repo_size': False,
932 'hooks_changegroup_push_logger': False,
957 'hooks_changegroup_push_logger': False,
933 'hooks_outgoing_pull_logger': False,
958 'hooks_outgoing_pull_logger': False,
934 'extensions_largefiles': False,
959 'extensions_largefiles': False,
935 'largefiles_usercache': '/example/largefiles-store',
960 'largefiles_usercache': '/example/largefiles-store',
961 'vcs_git_lfs_enabled': False,
962 'vcs_git_lfs_store_location': '/',
936 'phases_publish': 'False',
963 'phases_publish': 'False',
937 'rhodecode_pr_merge_enabled': False,
964 'rhodecode_pr_merge_enabled': False,
938 'rhodecode_use_outdated_comments': False,
965 'rhodecode_use_outdated_comments': False,
939 'new_svn_branch': '',
966 'new_svn_branch': '',
940 'new_svn_tag': ''
967 'new_svn_tag': ''
941 }
968 }
942
969
943 def test_get_raises_exception_when_repository_not_specified(self):
970 def test_get_raises_exception_when_repository_not_specified(self):
944 model = VcsSettingsModel()
971 model = VcsSettingsModel()
945 with pytest.raises(Exception) as exc_info:
972 with pytest.raises(Exception) as exc_info:
946 model.create_or_update_repo_settings(data=self.FORM_DATA)
973 model.create_or_update_repo_settings(data=self.FORM_DATA)
947 assert exc_info.value.message == 'Repository is not specified'
974 assert exc_info.value.message == 'Repository is not specified'
948
975
949 def test_only_svn_settings_are_updated_when_type_is_svn(self, backend_svn):
976 def test_only_svn_settings_are_updated_when_type_is_svn(self, backend_svn):
950 repo = backend_svn.create_repo()
977 repo = backend_svn.create_repo()
951 model = VcsSettingsModel(repo=repo)
978 model = VcsSettingsModel(repo=repo)
952 with self._patch_model(model) as mocks:
979 with self._patch_model(model) as mocks:
953 model.create_or_update_repo_settings(
980 model.create_or_update_repo_settings(
954 data=self.FORM_DATA, inherit_global_settings=False)
981 data=self.FORM_DATA, inherit_global_settings=False)
955 mocks['create_repo_svn_settings'].assert_called_once_with(
982 mocks['create_repo_svn_settings'].assert_called_once_with(
956 self.FORM_DATA)
983 self.FORM_DATA)
957 non_called_methods = (
984 non_called_methods = (
958 'create_or_update_repo_hook_settings',
985 'create_or_update_repo_hook_settings',
959 'create_or_update_repo_pr_settings',
986 'create_or_update_repo_pr_settings',
960 'create_or_update_repo_hg_settings')
987 'create_or_update_repo_hg_settings')
961 for method in non_called_methods:
988 for method in non_called_methods:
962 assert mocks[method].call_count == 0
989 assert mocks[method].call_count == 0
963
990
964 def test_non_svn_settings_are_updated_when_type_is_hg(self, backend_hg):
991 def test_non_svn_settings_are_updated_when_type_is_hg(self, backend_hg):
965 repo = backend_hg.create_repo()
992 repo = backend_hg.create_repo()
966 model = VcsSettingsModel(repo=repo)
993 model = VcsSettingsModel(repo=repo)
967 with self._patch_model(model) as mocks:
994 with self._patch_model(model) as mocks:
968 model.create_or_update_repo_settings(
995 model.create_or_update_repo_settings(
969 data=self.FORM_DATA, inherit_global_settings=False)
996 data=self.FORM_DATA, inherit_global_settings=False)
970
997
971 assert mocks['create_repo_svn_settings'].call_count == 0
998 assert mocks['create_repo_svn_settings'].call_count == 0
972 called_methods = (
999 called_methods = (
973 'create_or_update_repo_hook_settings',
1000 'create_or_update_repo_hook_settings',
974 'create_or_update_repo_pr_settings',
1001 'create_or_update_repo_pr_settings',
975 'create_or_update_repo_hg_settings')
1002 'create_or_update_repo_hg_settings')
976 for method in called_methods:
1003 for method in called_methods:
977 mocks[method].assert_called_once_with(self.FORM_DATA)
1004 mocks[method].assert_called_once_with(self.FORM_DATA)
978
1005
979 def test_non_svn_and_hg_settings_are_updated_when_type_is_git(
1006 def test_non_svn_and_hg_settings_are_updated_when_type_is_git(
980 self, backend_git):
1007 self, backend_git):
981 repo = backend_git.create_repo()
1008 repo = backend_git.create_repo()
982 model = VcsSettingsModel(repo=repo)
1009 model = VcsSettingsModel(repo=repo)
983 with self._patch_model(model) as mocks:
1010 with self._patch_model(model) as mocks:
984 model.create_or_update_repo_settings(
1011 model.create_or_update_repo_settings(
985 data=self.FORM_DATA, inherit_global_settings=False)
1012 data=self.FORM_DATA, inherit_global_settings=False)
986
1013
987 assert mocks['create_repo_svn_settings'].call_count == 0
1014 assert mocks['create_repo_svn_settings'].call_count == 0
988 called_methods = (
1015 called_methods = (
989 'create_or_update_repo_hook_settings',
1016 'create_or_update_repo_hook_settings',
990 'create_or_update_repo_pr_settings')
1017 'create_or_update_repo_pr_settings')
991 non_called_methods = (
1018 non_called_methods = (
992 'create_repo_svn_settings',
1019 'create_repo_svn_settings',
993 'create_or_update_repo_hg_settings'
1020 'create_or_update_repo_hg_settings'
994 )
1021 )
995 for method in called_methods:
1022 for method in called_methods:
996 mocks[method].assert_called_once_with(self.FORM_DATA)
1023 mocks[method].assert_called_once_with(self.FORM_DATA)
997 for method in non_called_methods:
1024 for method in non_called_methods:
998 assert mocks[method].call_count == 0
1025 assert mocks[method].call_count == 0
999
1026
1000 def test_no_methods_are_called_when_settings_are_inherited(
1027 def test_no_methods_are_called_when_settings_are_inherited(
1001 self, backend):
1028 self, backend):
1002 repo = backend.create_repo()
1029 repo = backend.create_repo()
1003 model = VcsSettingsModel(repo=repo)
1030 model = VcsSettingsModel(repo=repo)
1004 with self._patch_model(model) as mocks:
1031 with self._patch_model(model) as mocks:
1005 model.create_or_update_repo_settings(
1032 model.create_or_update_repo_settings(
1006 data=self.FORM_DATA, inherit_global_settings=True)
1033 data=self.FORM_DATA, inherit_global_settings=True)
1007 for method_name in mocks:
1034 for method_name in mocks:
1008 assert mocks[method_name].call_count == 0
1035 assert mocks[method_name].call_count == 0
1009
1036
1010 def test_cache_is_marked_for_invalidation(self, repo_stub):
1037 def test_cache_is_marked_for_invalidation(self, repo_stub):
1011 model = VcsSettingsModel(repo=repo_stub)
1038 model = VcsSettingsModel(repo=repo_stub)
1012 invalidation_patcher = mock.patch(
1039 invalidation_patcher = mock.patch(
1013 'rhodecode.controllers.admin.repos.ScmModel.mark_for_invalidation')
1040 'rhodecode.controllers.admin.repos.ScmModel.mark_for_invalidation')
1014 with invalidation_patcher as invalidation_mock:
1041 with invalidation_patcher as invalidation_mock:
1015 model.create_or_update_repo_settings(
1042 model.create_or_update_repo_settings(
1016 data=self.FORM_DATA, inherit_global_settings=True)
1043 data=self.FORM_DATA, inherit_global_settings=True)
1017 invalidation_mock.assert_called_once_with(
1044 invalidation_mock.assert_called_once_with(
1018 repo_stub.repo_name, delete=True)
1045 repo_stub.repo_name, delete=True)
1019
1046
1020 def test_inherit_flag_is_saved(self, repo_stub):
1047 def test_inherit_flag_is_saved(self, repo_stub):
1021 model = VcsSettingsModel(repo=repo_stub)
1048 model = VcsSettingsModel(repo=repo_stub)
1022 model.inherit_global_settings = True
1049 model.inherit_global_settings = True
1023 with self._patch_model(model):
1050 with self._patch_model(model):
1024 model.create_or_update_repo_settings(
1051 model.create_or_update_repo_settings(
1025 data=self.FORM_DATA, inherit_global_settings=False)
1052 data=self.FORM_DATA, inherit_global_settings=False)
1026 assert model.inherit_global_settings is False
1053 assert model.inherit_global_settings is False
1027
1054
1028 def _patch_model(self, model):
1055 def _patch_model(self, model):
1029 return mock.patch.multiple(
1056 return mock.patch.multiple(
1030 model,
1057 model,
1031 create_repo_svn_settings=mock.DEFAULT,
1058 create_repo_svn_settings=mock.DEFAULT,
1032 create_or_update_repo_hook_settings=mock.DEFAULT,
1059 create_or_update_repo_hook_settings=mock.DEFAULT,
1033 create_or_update_repo_pr_settings=mock.DEFAULT,
1060 create_or_update_repo_pr_settings=mock.DEFAULT,
1034 create_or_update_repo_hg_settings=mock.DEFAULT)
1061 create_or_update_repo_hg_settings=mock.DEFAULT)
General Comments 0
You need to be logged in to leave comments. Login now