##// END OF EJS Templates
feat: system-upgrade improved message on new version check page
super-admin -
r5429:e153339b default
parent child Browse files
Show More
@@ -1,678 +1,678 b''
1
1
2 # Copyright (C) 2010-2023 RhodeCode GmbH
2 # Copyright (C) 2010-2023 RhodeCode GmbH
3 #
3 #
4 # This program is free software: you can redistribute it and/or modify
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License, version 3
5 # it under the terms of the GNU Affero General Public License, version 3
6 # (only), as published by the Free Software Foundation.
6 # (only), as published by the Free Software Foundation.
7 #
7 #
8 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
11 # GNU General Public License for more details.
12 #
12 #
13 # You should have received a copy of the GNU Affero General Public License
13 # You should have received a copy of the GNU Affero General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 #
15 #
16 # This program is dual-licensed. If you wish to learn more about the
16 # This program is dual-licensed. If you wish to learn more about the
17 # RhodeCode Enterprise Edition, including its added features, Support services,
17 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
18 # and proprietary license terms, please see https://rhodecode.com/licenses/
19
19
20 import mock
20 import mock
21 import pytest
21 import pytest
22
22
23 import rhodecode
23 import rhodecode
24 from rhodecode.apps._base import ADMIN_PREFIX
24 from rhodecode.apps._base import ADMIN_PREFIX
25 from rhodecode.lib.hash_utils import md5_safe
25 from rhodecode.lib.hash_utils import md5_safe
26 from rhodecode.model.db import RhodeCodeUi
26 from rhodecode.model.db import RhodeCodeUi
27 from rhodecode.model.meta import Session
27 from rhodecode.model.meta import Session
28 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
28 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
29 from rhodecode.tests import assert_session_flash
29 from rhodecode.tests import assert_session_flash
30 from rhodecode.tests.routes import route_path
30 from rhodecode.tests.routes import route_path
31
31
32
32
33 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
33 UPDATE_DATA_QUALNAME = 'rhodecode.model.update.UpdateModel.get_update_data'
34
34
35
35
36 @pytest.mark.usefixtures('autologin_user', 'app')
36 @pytest.mark.usefixtures('autologin_user', 'app')
37 class TestAdminSettingsController(object):
37 class TestAdminSettingsController(object):
38
38
39 @pytest.mark.parametrize('urlname', [
39 @pytest.mark.parametrize('urlname', [
40 'admin_settings_vcs',
40 'admin_settings_vcs',
41 'admin_settings_mapping',
41 'admin_settings_mapping',
42 'admin_settings_global',
42 'admin_settings_global',
43 'admin_settings_visual',
43 'admin_settings_visual',
44 'admin_settings_email',
44 'admin_settings_email',
45 'admin_settings_hooks',
45 'admin_settings_hooks',
46 'admin_settings_search',
46 'admin_settings_search',
47 ])
47 ])
48 def test_simple_get(self, urlname):
48 def test_simple_get(self, urlname):
49 self.app.get(route_path(urlname))
49 self.app.get(route_path(urlname))
50
50
51 def test_create_custom_hook(self, csrf_token):
51 def test_create_custom_hook(self, csrf_token):
52 response = self.app.post(
52 response = self.app.post(
53 route_path('admin_settings_hooks_update'),
53 route_path('admin_settings_hooks_update'),
54 params={
54 params={
55 'new_hook_ui_key': 'test_hooks_1',
55 'new_hook_ui_key': 'test_hooks_1',
56 'new_hook_ui_value': 'cd /tmp',
56 'new_hook_ui_value': 'cd /tmp',
57 'csrf_token': csrf_token})
57 'csrf_token': csrf_token})
58
58
59 response = response.follow()
59 response = response.follow()
60 response.mustcontain('test_hooks_1')
60 response.mustcontain('test_hooks_1')
61 response.mustcontain('cd /tmp')
61 response.mustcontain('cd /tmp')
62
62
63 def test_create_custom_hook_delete(self, csrf_token):
63 def test_create_custom_hook_delete(self, csrf_token):
64 response = self.app.post(
64 response = self.app.post(
65 route_path('admin_settings_hooks_update'),
65 route_path('admin_settings_hooks_update'),
66 params={
66 params={
67 'new_hook_ui_key': 'test_hooks_2',
67 'new_hook_ui_key': 'test_hooks_2',
68 'new_hook_ui_value': 'cd /tmp2',
68 'new_hook_ui_value': 'cd /tmp2',
69 'csrf_token': csrf_token})
69 'csrf_token': csrf_token})
70
70
71 response = response.follow()
71 response = response.follow()
72 response.mustcontain('test_hooks_2')
72 response.mustcontain('test_hooks_2')
73 response.mustcontain('cd /tmp2')
73 response.mustcontain('cd /tmp2')
74
74
75 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
75 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
76
76
77 # delete
77 # delete
78 self.app.post(
78 self.app.post(
79 route_path('admin_settings_hooks_delete'),
79 route_path('admin_settings_hooks_delete'),
80 params={'hook_id': hook_id, 'csrf_token': csrf_token})
80 params={'hook_id': hook_id, 'csrf_token': csrf_token})
81 response = self.app.get(route_path('admin_settings_hooks'))
81 response = self.app.get(route_path('admin_settings_hooks'))
82 response.mustcontain(no=['test_hooks_2'])
82 response.mustcontain(no=['test_hooks_2'])
83 response.mustcontain(no=['cd /tmp2'])
83 response.mustcontain(no=['cd /tmp2'])
84
84
85
85
86 @pytest.mark.usefixtures('autologin_user', 'app')
86 @pytest.mark.usefixtures('autologin_user', 'app')
87 class TestAdminSettingsGlobal(object):
87 class TestAdminSettingsGlobal(object):
88
88
89 def test_pre_post_code_code_active(self, csrf_token):
89 def test_pre_post_code_code_active(self, csrf_token):
90 pre_code = 'rc-pre-code-187652122'
90 pre_code = 'rc-pre-code-187652122'
91 post_code = 'rc-postcode-98165231'
91 post_code = 'rc-postcode-98165231'
92
92
93 response = self.post_and_verify_settings({
93 response = self.post_and_verify_settings({
94 'rhodecode_pre_code': pre_code,
94 'rhodecode_pre_code': pre_code,
95 'rhodecode_post_code': post_code,
95 'rhodecode_post_code': post_code,
96 'csrf_token': csrf_token,
96 'csrf_token': csrf_token,
97 })
97 })
98
98
99 response = response.follow()
99 response = response.follow()
100 response.mustcontain(pre_code, post_code)
100 response.mustcontain(pre_code, post_code)
101
101
102 def test_pre_post_code_code_inactive(self, csrf_token):
102 def test_pre_post_code_code_inactive(self, csrf_token):
103 pre_code = 'rc-pre-code-187652122'
103 pre_code = 'rc-pre-code-187652122'
104 post_code = 'rc-postcode-98165231'
104 post_code = 'rc-postcode-98165231'
105 response = self.post_and_verify_settings({
105 response = self.post_and_verify_settings({
106 'rhodecode_pre_code': '',
106 'rhodecode_pre_code': '',
107 'rhodecode_post_code': '',
107 'rhodecode_post_code': '',
108 'csrf_token': csrf_token,
108 'csrf_token': csrf_token,
109 })
109 })
110
110
111 response = response.follow()
111 response = response.follow()
112 response.mustcontain(no=[pre_code, post_code])
112 response.mustcontain(no=[pre_code, post_code])
113
113
114 def test_captcha_activate(self, csrf_token):
114 def test_captcha_activate(self, csrf_token):
115 self.post_and_verify_settings({
115 self.post_and_verify_settings({
116 'rhodecode_captcha_private_key': '1234567890',
116 'rhodecode_captcha_private_key': '1234567890',
117 'rhodecode_captcha_public_key': '1234567890',
117 'rhodecode_captcha_public_key': '1234567890',
118 'csrf_token': csrf_token,
118 'csrf_token': csrf_token,
119 })
119 })
120
120
121 response = self.app.get(ADMIN_PREFIX + '/register')
121 response = self.app.get(ADMIN_PREFIX + '/register')
122 response.mustcontain('captcha')
122 response.mustcontain('captcha')
123
123
124 def test_captcha_deactivate(self, csrf_token):
124 def test_captcha_deactivate(self, csrf_token):
125 self.post_and_verify_settings({
125 self.post_and_verify_settings({
126 'rhodecode_captcha_private_key': '',
126 'rhodecode_captcha_private_key': '',
127 'rhodecode_captcha_public_key': '1234567890',
127 'rhodecode_captcha_public_key': '1234567890',
128 'csrf_token': csrf_token,
128 'csrf_token': csrf_token,
129 })
129 })
130
130
131 response = self.app.get(ADMIN_PREFIX + '/register')
131 response = self.app.get(ADMIN_PREFIX + '/register')
132 response.mustcontain(no=['captcha'])
132 response.mustcontain(no=['captcha'])
133
133
134 def test_title_change(self, csrf_token):
134 def test_title_change(self, csrf_token):
135 old_title = 'RhodeCode'
135 old_title = 'RhodeCode'
136
136
137 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
137 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
138 response = self.post_and_verify_settings({
138 response = self.post_and_verify_settings({
139 'rhodecode_title': new_title,
139 'rhodecode_title': new_title,
140 'csrf_token': csrf_token,
140 'csrf_token': csrf_token,
141 })
141 })
142
142
143 response = response.follow()
143 response = response.follow()
144 response.mustcontain(new_title)
144 response.mustcontain(new_title)
145
145
146 def post_and_verify_settings(self, settings):
146 def post_and_verify_settings(self, settings):
147 old_title = 'RhodeCode'
147 old_title = 'RhodeCode'
148 old_realm = 'RhodeCode authentication'
148 old_realm = 'RhodeCode authentication'
149 params = {
149 params = {
150 'rhodecode_title': old_title,
150 'rhodecode_title': old_title,
151 'rhodecode_realm': old_realm,
151 'rhodecode_realm': old_realm,
152 'rhodecode_pre_code': '',
152 'rhodecode_pre_code': '',
153 'rhodecode_post_code': '',
153 'rhodecode_post_code': '',
154 'rhodecode_captcha_private_key': '',
154 'rhodecode_captcha_private_key': '',
155 'rhodecode_captcha_public_key': '',
155 'rhodecode_captcha_public_key': '',
156 'rhodecode_create_personal_repo_group': False,
156 'rhodecode_create_personal_repo_group': False,
157 'rhodecode_personal_repo_group_pattern': '${username}',
157 'rhodecode_personal_repo_group_pattern': '${username}',
158 }
158 }
159 params.update(settings)
159 params.update(settings)
160 response = self.app.post(
160 response = self.app.post(
161 route_path('admin_settings_global_update'), params=params)
161 route_path('admin_settings_global_update'), params=params)
162
162
163 assert_session_flash(response, 'Updated application settings')
163 assert_session_flash(response, 'Updated application settings')
164
164
165 app_settings = SettingsModel().get_all_settings()
165 app_settings = SettingsModel().get_all_settings()
166 del settings['csrf_token']
166 del settings['csrf_token']
167 for key, value in settings.items():
167 for key, value in settings.items():
168 assert app_settings[key] == value
168 assert app_settings[key] == value
169
169
170 return response
170 return response
171
171
172
172
173 @pytest.mark.usefixtures('autologin_user', 'app')
173 @pytest.mark.usefixtures('autologin_user', 'app')
174 class TestAdminSettingsVcs(object):
174 class TestAdminSettingsVcs(object):
175
175
176 def test_contains_svn_default_patterns(self):
176 def test_contains_svn_default_patterns(self):
177 response = self.app.get(route_path('admin_settings_vcs'))
177 response = self.app.get(route_path('admin_settings_vcs'))
178 expected_patterns = [
178 expected_patterns = [
179 '/trunk',
179 '/trunk',
180 '/branches/*',
180 '/branches/*',
181 '/tags/*',
181 '/tags/*',
182 ]
182 ]
183 for pattern in expected_patterns:
183 for pattern in expected_patterns:
184 response.mustcontain(pattern)
184 response.mustcontain(pattern)
185
185
186 def test_add_new_svn_branch_and_tag_pattern(
186 def test_add_new_svn_branch_and_tag_pattern(
187 self, backend_svn, form_defaults, disable_sql_cache,
187 self, backend_svn, form_defaults, disable_sql_cache,
188 csrf_token):
188 csrf_token):
189 form_defaults.update({
189 form_defaults.update({
190 'new_svn_branch': '/exp/branches/*',
190 'new_svn_branch': '/exp/branches/*',
191 'new_svn_tag': '/important_tags/*',
191 'new_svn_tag': '/important_tags/*',
192 'csrf_token': csrf_token,
192 'csrf_token': csrf_token,
193 })
193 })
194
194
195 response = self.app.post(
195 response = self.app.post(
196 route_path('admin_settings_vcs_update'),
196 route_path('admin_settings_vcs_update'),
197 params=form_defaults, status=302)
197 params=form_defaults, status=302)
198 response = response.follow()
198 response = response.follow()
199
199
200 # Expect to find the new values on the page
200 # Expect to find the new values on the page
201 response.mustcontain('/exp/branches/*')
201 response.mustcontain('/exp/branches/*')
202 response.mustcontain('/important_tags/*')
202 response.mustcontain('/important_tags/*')
203
203
204 # Expect that those patterns are used to match branches and tags now
204 # Expect that those patterns are used to match branches and tags now
205 repo = backend_svn['svn-simple-layout'].scm_instance()
205 repo = backend_svn['svn-simple-layout'].scm_instance()
206 assert 'exp/branches/exp-sphinx-docs' in repo.branches
206 assert 'exp/branches/exp-sphinx-docs' in repo.branches
207 assert 'important_tags/v0.5' in repo.tags
207 assert 'important_tags/v0.5' in repo.tags
208
208
209 def test_add_same_svn_value_twice_shows_an_error_message(
209 def test_add_same_svn_value_twice_shows_an_error_message(
210 self, form_defaults, csrf_token, settings_util):
210 self, form_defaults, csrf_token, settings_util):
211 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
211 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
212 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
212 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
213
213
214 response = self.app.post(
214 response = self.app.post(
215 route_path('admin_settings_vcs_update'),
215 route_path('admin_settings_vcs_update'),
216 params={
216 params={
217 'paths_root_path': form_defaults['paths_root_path'],
217 'paths_root_path': form_defaults['paths_root_path'],
218 'new_svn_branch': '/test',
218 'new_svn_branch': '/test',
219 'new_svn_tag': '/test',
219 'new_svn_tag': '/test',
220 'csrf_token': csrf_token,
220 'csrf_token': csrf_token,
221 },
221 },
222 status=200)
222 status=200)
223
223
224 response.mustcontain("Pattern already exists")
224 response.mustcontain("Pattern already exists")
225 response.mustcontain("Some form inputs contain invalid data.")
225 response.mustcontain("Some form inputs contain invalid data.")
226
226
227 @pytest.mark.parametrize('section', [
227 @pytest.mark.parametrize('section', [
228 'vcs_svn_branch',
228 'vcs_svn_branch',
229 'vcs_svn_tag',
229 'vcs_svn_tag',
230 ])
230 ])
231 def test_delete_svn_patterns(
231 def test_delete_svn_patterns(
232 self, section, csrf_token, settings_util):
232 self, section, csrf_token, settings_util):
233 setting = settings_util.create_rhodecode_ui(
233 setting = settings_util.create_rhodecode_ui(
234 section, '/test_delete', cleanup=False)
234 section, '/test_delete', cleanup=False)
235
235
236 self.app.post(
236 self.app.post(
237 route_path('admin_settings_vcs_svn_pattern_delete'),
237 route_path('admin_settings_vcs_svn_pattern_delete'),
238 params={
238 params={
239 'delete_svn_pattern': setting.ui_id,
239 'delete_svn_pattern': setting.ui_id,
240 'csrf_token': csrf_token},
240 'csrf_token': csrf_token},
241 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
241 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
242
242
243 @pytest.mark.parametrize('section', [
243 @pytest.mark.parametrize('section', [
244 'vcs_svn_branch',
244 'vcs_svn_branch',
245 'vcs_svn_tag',
245 'vcs_svn_tag',
246 ])
246 ])
247 def test_delete_svn_patterns_raises_404_when_no_xhr(
247 def test_delete_svn_patterns_raises_404_when_no_xhr(
248 self, section, csrf_token, settings_util):
248 self, section, csrf_token, settings_util):
249 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
249 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
250
250
251 self.app.post(
251 self.app.post(
252 route_path('admin_settings_vcs_svn_pattern_delete'),
252 route_path('admin_settings_vcs_svn_pattern_delete'),
253 params={
253 params={
254 'delete_svn_pattern': setting.ui_id,
254 'delete_svn_pattern': setting.ui_id,
255 'csrf_token': csrf_token},
255 'csrf_token': csrf_token},
256 status=404)
256 status=404)
257
257
258 def test_extensions_hgevolve(self, form_defaults, csrf_token):
258 def test_extensions_hgevolve(self, form_defaults, csrf_token):
259 form_defaults.update({
259 form_defaults.update({
260 'csrf_token': csrf_token,
260 'csrf_token': csrf_token,
261 'extensions_evolve': 'True',
261 'extensions_evolve': 'True',
262 })
262 })
263 response = self.app.post(
263 response = self.app.post(
264 route_path('admin_settings_vcs_update'),
264 route_path('admin_settings_vcs_update'),
265 params=form_defaults,
265 params=form_defaults,
266 status=302)
266 status=302)
267
267
268 response = response.follow()
268 response = response.follow()
269 extensions_input = (
269 extensions_input = (
270 '<input id="extensions_evolve" '
270 '<input id="extensions_evolve" '
271 'name="extensions_evolve" type="checkbox" '
271 'name="extensions_evolve" type="checkbox" '
272 'value="True" checked="checked" />')
272 'value="True" checked="checked" />')
273 response.mustcontain(extensions_input)
273 response.mustcontain(extensions_input)
274
274
275 def test_has_a_section_for_pull_request_settings(self):
275 def test_has_a_section_for_pull_request_settings(self):
276 response = self.app.get(route_path('admin_settings_vcs'))
276 response = self.app.get(route_path('admin_settings_vcs'))
277 response.mustcontain('Pull Request Settings')
277 response.mustcontain('Pull Request Settings')
278
278
279 def test_has_an_input_for_invalidation_of_inline_comments(self):
279 def test_has_an_input_for_invalidation_of_inline_comments(self):
280 response = self.app.get(route_path('admin_settings_vcs'))
280 response = self.app.get(route_path('admin_settings_vcs'))
281 assert_response = response.assert_response()
281 assert_response = response.assert_response()
282 assert_response.one_element_exists(
282 assert_response.one_element_exists(
283 '[name=rhodecode_use_outdated_comments]')
283 '[name=rhodecode_use_outdated_comments]')
284
284
285 @pytest.mark.parametrize('new_value', [True, False])
285 @pytest.mark.parametrize('new_value', [True, False])
286 def test_allows_to_change_invalidation_of_inline_comments(
286 def test_allows_to_change_invalidation_of_inline_comments(
287 self, form_defaults, csrf_token, new_value):
287 self, form_defaults, csrf_token, new_value):
288 setting_key = 'use_outdated_comments'
288 setting_key = 'use_outdated_comments'
289 setting = SettingsModel().create_or_update_setting(
289 setting = SettingsModel().create_or_update_setting(
290 setting_key, not new_value, 'bool')
290 setting_key, not new_value, 'bool')
291 Session().add(setting)
291 Session().add(setting)
292 Session().commit()
292 Session().commit()
293
293
294 form_defaults.update({
294 form_defaults.update({
295 'csrf_token': csrf_token,
295 'csrf_token': csrf_token,
296 'rhodecode_use_outdated_comments': str(new_value),
296 'rhodecode_use_outdated_comments': str(new_value),
297 })
297 })
298 response = self.app.post(
298 response = self.app.post(
299 route_path('admin_settings_vcs_update'),
299 route_path('admin_settings_vcs_update'),
300 params=form_defaults,
300 params=form_defaults,
301 status=302)
301 status=302)
302 response = response.follow()
302 response = response.follow()
303 setting = SettingsModel().get_setting_by_name(setting_key)
303 setting = SettingsModel().get_setting_by_name(setting_key)
304 assert setting.app_settings_value is new_value
304 assert setting.app_settings_value is new_value
305
305
306 @pytest.mark.parametrize('new_value', [True, False])
306 @pytest.mark.parametrize('new_value', [True, False])
307 def test_allows_to_change_hg_rebase_merge_strategy(
307 def test_allows_to_change_hg_rebase_merge_strategy(
308 self, form_defaults, csrf_token, new_value):
308 self, form_defaults, csrf_token, new_value):
309 setting_key = 'hg_use_rebase_for_merging'
309 setting_key = 'hg_use_rebase_for_merging'
310
310
311 form_defaults.update({
311 form_defaults.update({
312 'csrf_token': csrf_token,
312 'csrf_token': csrf_token,
313 'rhodecode_' + setting_key: str(new_value),
313 'rhodecode_' + setting_key: str(new_value),
314 })
314 })
315
315
316 with mock.patch.dict(
316 with mock.patch.dict(
317 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
317 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
318 self.app.post(
318 self.app.post(
319 route_path('admin_settings_vcs_update'),
319 route_path('admin_settings_vcs_update'),
320 params=form_defaults,
320 params=form_defaults,
321 status=302)
321 status=302)
322
322
323 setting = SettingsModel().get_setting_by_name(setting_key)
323 setting = SettingsModel().get_setting_by_name(setting_key)
324 assert setting.app_settings_value is new_value
324 assert setting.app_settings_value is new_value
325
325
326 @pytest.fixture()
326 @pytest.fixture()
327 def disable_sql_cache(self, request):
327 def disable_sql_cache(self, request):
328 # patch _do_orm_execute so it returns None similar like if we don't use a cached query
328 # patch _do_orm_execute so it returns None similar like if we don't use a cached query
329 patcher = mock.patch(
329 patcher = mock.patch(
330 'rhodecode.lib.caching_query.ORMCache._do_orm_execute', return_value=None)
330 'rhodecode.lib.caching_query.ORMCache._do_orm_execute', return_value=None)
331 request.addfinalizer(patcher.stop)
331 request.addfinalizer(patcher.stop)
332 patcher.start()
332 patcher.start()
333
333
334 @pytest.fixture()
334 @pytest.fixture()
335 def form_defaults(self):
335 def form_defaults(self):
336 from rhodecode.apps.admin.views.settings import AdminSettingsView
336 from rhodecode.apps.admin.views.settings import AdminSettingsView
337 return AdminSettingsView._form_defaults()
337 return AdminSettingsView._form_defaults()
338
338
339 # TODO: johbo: What we really want is to checkpoint before a test run and
339 # TODO: johbo: What we really want is to checkpoint before a test run and
340 # reset the session afterwards.
340 # reset the session afterwards.
341 @pytest.fixture(scope='class', autouse=True)
341 @pytest.fixture(scope='class', autouse=True)
342 def cleanup_settings(self, request, baseapp):
342 def cleanup_settings(self, request, baseapp):
343 ui_id = RhodeCodeUi.ui_id
343 ui_id = RhodeCodeUi.ui_id
344 original_ids = [r.ui_id for r in RhodeCodeUi.query().with_entities(ui_id)]
344 original_ids = [r.ui_id for r in RhodeCodeUi.query().with_entities(ui_id)]
345
345
346 @request.addfinalizer
346 @request.addfinalizer
347 def cleanup():
347 def cleanup():
348 RhodeCodeUi.query().filter(
348 RhodeCodeUi.query().filter(
349 ui_id.notin_(original_ids)).delete(False)
349 ui_id.notin_(original_ids)).delete(False)
350
350
351
351
352 @pytest.mark.usefixtures('autologin_user', 'app')
352 @pytest.mark.usefixtures('autologin_user', 'app')
353 class TestLabsSettings(object):
353 class TestLabsSettings(object):
354 def test_get_settings_page_disabled(self):
354 def test_get_settings_page_disabled(self):
355 with mock.patch.dict(
355 with mock.patch.dict(
356 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
356 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
357
357
358 response = self.app.get(
358 response = self.app.get(
359 route_path('admin_settings_labs'), status=302)
359 route_path('admin_settings_labs'), status=302)
360
360
361 assert response.location.endswith(route_path('admin_settings'))
361 assert response.location.endswith(route_path('admin_settings'))
362
362
363 def test_get_settings_page_enabled(self):
363 def test_get_settings_page_enabled(self):
364 from rhodecode.apps.admin.views import settings
364 from rhodecode.apps.admin.views import settings
365 lab_settings = [
365 lab_settings = [
366 settings.LabSetting(
366 settings.LabSetting(
367 key='rhodecode_bool',
367 key='rhodecode_bool',
368 type='bool',
368 type='bool',
369 group='bool group',
369 group='bool group',
370 label='bool label',
370 label='bool label',
371 help='bool help'
371 help='bool help'
372 ),
372 ),
373 settings.LabSetting(
373 settings.LabSetting(
374 key='rhodecode_text',
374 key='rhodecode_text',
375 type='unicode',
375 type='unicode',
376 group='text group',
376 group='text group',
377 label='text label',
377 label='text label',
378 help='text help'
378 help='text help'
379 ),
379 ),
380 ]
380 ]
381 with mock.patch.dict(rhodecode.CONFIG,
381 with mock.patch.dict(rhodecode.CONFIG,
382 {'labs_settings_active': 'true'}):
382 {'labs_settings_active': 'true'}):
383 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
383 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
384 response = self.app.get(route_path('admin_settings_labs'))
384 response = self.app.get(route_path('admin_settings_labs'))
385
385
386 assert '<label>bool group:</label>' in response
386 assert '<label>bool group:</label>' in response
387 assert '<label for="rhodecode_bool">bool label</label>' in response
387 assert '<label for="rhodecode_bool">bool label</label>' in response
388 assert '<p class="help-block">bool help</p>' in response
388 assert '<p class="help-block">bool help</p>' in response
389 assert 'name="rhodecode_bool" type="checkbox"' in response
389 assert 'name="rhodecode_bool" type="checkbox"' in response
390
390
391 assert '<label>text group:</label>' in response
391 assert '<label>text group:</label>' in response
392 assert '<label for="rhodecode_text">text label</label>' in response
392 assert '<label for="rhodecode_text">text label</label>' in response
393 assert '<p class="help-block">text help</p>' in response
393 assert '<p class="help-block">text help</p>' in response
394 assert 'name="rhodecode_text" size="60" type="text"' in response
394 assert 'name="rhodecode_text" size="60" type="text"' in response
395
395
396
396
397 @pytest.mark.usefixtures('app')
397 @pytest.mark.usefixtures('app')
398 class TestOpenSourceLicenses(object):
398 class TestOpenSourceLicenses(object):
399
399
400 def test_records_are_displayed(self, autologin_user):
400 def test_records_are_displayed(self, autologin_user):
401 sample_licenses = [
401 sample_licenses = [
402 {
402 {
403 "license": [
403 "license": [
404 {
404 {
405 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
405 "fullName": "BSD 4-clause \"Original\" or \"Old\" License",
406 "shortName": "bsdOriginal",
406 "shortName": "bsdOriginal",
407 "spdxId": "BSD-4-Clause",
407 "spdxId": "BSD-4-Clause",
408 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
408 "url": "http://spdx.org/licenses/BSD-4-Clause.html"
409 }
409 }
410 ],
410 ],
411 "name": "python2.7-coverage-3.7.1"
411 "name": "python2.7-coverage-3.7.1"
412 },
412 },
413 {
413 {
414 "license": [
414 "license": [
415 {
415 {
416 "fullName": "MIT License",
416 "fullName": "MIT License",
417 "shortName": "mit",
417 "shortName": "mit",
418 "spdxId": "MIT",
418 "spdxId": "MIT",
419 "url": "http://spdx.org/licenses/MIT.html"
419 "url": "http://spdx.org/licenses/MIT.html"
420 }
420 }
421 ],
421 ],
422 "name": "python2.7-bootstrapped-pip-9.0.1"
422 "name": "python2.7-bootstrapped-pip-9.0.1"
423 },
423 },
424 ]
424 ]
425 read_licenses_patch = mock.patch(
425 read_licenses_patch = mock.patch(
426 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
426 'rhodecode.apps.admin.views.open_source_licenses.read_opensource_licenses',
427 return_value=sample_licenses)
427 return_value=sample_licenses)
428 with read_licenses_patch:
428 with read_licenses_patch:
429 response = self.app.get(
429 response = self.app.get(
430 route_path('admin_settings_open_source'), status=200)
430 route_path('admin_settings_open_source'), status=200)
431
431
432 assert_response = response.assert_response()
432 assert_response = response.assert_response()
433 assert_response.element_contains(
433 assert_response.element_contains(
434 '.panel-heading', 'Licenses of Third Party Packages')
434 '.panel-heading', 'Licenses of Third Party Packages')
435 for license_data in sample_licenses:
435 for license_data in sample_licenses:
436 response.mustcontain(license_data["license"][0]["spdxId"])
436 response.mustcontain(license_data["license"][0]["spdxId"])
437 assert_response.element_contains('.panel-body', license_data["name"])
437 assert_response.element_contains('.panel-body', license_data["name"])
438
438
439 def test_records_can_be_read(self, autologin_user):
439 def test_records_can_be_read(self, autologin_user):
440 response = self.app.get(
440 response = self.app.get(
441 route_path('admin_settings_open_source'), status=200)
441 route_path('admin_settings_open_source'), status=200)
442 assert_response = response.assert_response()
442 assert_response = response.assert_response()
443 assert_response.element_contains(
443 assert_response.element_contains(
444 '.panel-heading', 'Licenses of Third Party Packages')
444 '.panel-heading', 'Licenses of Third Party Packages')
445
445
446 def test_forbidden_when_normal_user(self, autologin_regular_user):
446 def test_forbidden_when_normal_user(self, autologin_regular_user):
447 self.app.get(
447 self.app.get(
448 route_path('admin_settings_open_source'), status=404)
448 route_path('admin_settings_open_source'), status=404)
449
449
450
450
451 @pytest.mark.usefixtures('app')
451 @pytest.mark.usefixtures('app')
452 class TestUserSessions(object):
452 class TestUserSessions(object):
453
453
454 def test_forbidden_when_normal_user(self, autologin_regular_user):
454 def test_forbidden_when_normal_user(self, autologin_regular_user):
455 self.app.get(route_path('admin_settings_sessions'), status=404)
455 self.app.get(route_path('admin_settings_sessions'), status=404)
456
456
457 def test_show_sessions_page(self, autologin_user):
457 def test_show_sessions_page(self, autologin_user):
458 response = self.app.get(route_path('admin_settings_sessions'), status=200)
458 response = self.app.get(route_path('admin_settings_sessions'), status=200)
459 response.mustcontain('file')
459 response.mustcontain('file')
460
460
461 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
461 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
462
462
463 post_data = {
463 post_data = {
464 'csrf_token': csrf_token,
464 'csrf_token': csrf_token,
465 'expire_days': '60'
465 'expire_days': '60'
466 }
466 }
467 response = self.app.post(
467 response = self.app.post(
468 route_path('admin_settings_sessions_cleanup'), params=post_data,
468 route_path('admin_settings_sessions_cleanup'), params=post_data,
469 status=302)
469 status=302)
470 assert_session_flash(response, 'Cleaned up old sessions')
470 assert_session_flash(response, 'Cleaned up old sessions')
471
471
472
472
473 @pytest.mark.usefixtures('app')
473 @pytest.mark.usefixtures('app')
474 class TestAdminSystemInfo(object):
474 class TestAdminSystemInfo(object):
475
475
476 def test_forbidden_when_normal_user(self, autologin_regular_user):
476 def test_forbidden_when_normal_user(self, autologin_regular_user):
477 self.app.get(route_path('admin_settings_system'), status=404)
477 self.app.get(route_path('admin_settings_system'), status=404)
478
478
479 def test_system_info_page(self, autologin_user):
479 def test_system_info_page(self, autologin_user):
480 response = self.app.get(route_path('admin_settings_system'))
480 response = self.app.get(route_path('admin_settings_system'))
481 response.mustcontain('RhodeCode Community Edition, version {}'.format(
481 response.mustcontain('RhodeCode Community Edition, version {}'.format(
482 rhodecode.__version__))
482 rhodecode.__version__))
483
483
484 def test_system_update_new_version(self, autologin_user):
484 def test_system_update_new_version(self, autologin_user):
485 update_data = {
485 update_data = {
486 'versions': [
486 'versions': [
487 {
487 {
488 'version': '100.3.1415926535',
488 'version': '100.0.0',
489 'general': 'The latest version we are ever going to ship'
489 'general': 'The latest version we are ever going to ship'
490 },
490 },
491 {
491 {
492 'version': '0.0.0',
492 'version': '0.0.0',
493 'general': 'The first version we ever shipped'
493 'general': 'The first version we ever shipped'
494 }
494 }
495 ]
495 ]
496 }
496 }
497 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
497 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
498 response = self.app.get(route_path('admin_settings_system_update'))
498 response = self.app.get(route_path('admin_settings_system_update'))
499 response.mustcontain('A <b>new version</b> is available')
499 response.mustcontain('A <b>new version</b> is available')
500
500
501 def test_system_update_nothing_new(self, autologin_user):
501 def test_system_update_nothing_new(self, autologin_user):
502 update_data = {
502 update_data = {
503 'versions': [
503 'versions': [
504 {
504 {
505 'version': '0.0.0',
505 'version': '4.0.0',
506 'general': 'The first version we ever shipped'
506 'general': 'The first version we ever shipped'
507 }
507 }
508 ]
508 ]
509 }
509 }
510 text = f"Your current version, {rhodecode.__version__}, is up-to-date as it is equal to or newer than the latest available version, 4.0.0."
510 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
511 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
511 response = self.app.get(route_path('admin_settings_system_update'))
512 response = self.app.get(route_path('admin_settings_system_update'))
512 response.mustcontain(
513 response.mustcontain(text)
513 'This instance is already running the <b>latest</b> stable version')
514
514
515 def test_system_update_bad_response(self, autologin_user):
515 def test_system_update_bad_response(self, autologin_user):
516 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
516 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
517 response = self.app.get(route_path('admin_settings_system_update'))
517 response = self.app.get(route_path('admin_settings_system_update'))
518 response.mustcontain(
518 response.mustcontain(
519 'Bad data sent from update server')
519 'Bad data sent from update server')
520
520
521
521
522 @pytest.mark.usefixtures("app")
522 @pytest.mark.usefixtures("app")
523 class TestAdminSettingsIssueTracker(object):
523 class TestAdminSettingsIssueTracker(object):
524 RC_PREFIX = 'rhodecode_'
524 RC_PREFIX = 'rhodecode_'
525 SHORT_PATTERN_KEY = 'issuetracker_pat_'
525 SHORT_PATTERN_KEY = 'issuetracker_pat_'
526 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
526 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
527 DESC_KEY = RC_PREFIX + 'issuetracker_desc_'
527 DESC_KEY = RC_PREFIX + 'issuetracker_desc_'
528
528
529 def test_issuetracker_index(self, autologin_user):
529 def test_issuetracker_index(self, autologin_user):
530 response = self.app.get(route_path('admin_settings_issuetracker'))
530 response = self.app.get(route_path('admin_settings_issuetracker'))
531 assert response.status_code == 200
531 assert response.status_code == 200
532
532
533 def test_add_empty_issuetracker_pattern(
533 def test_add_empty_issuetracker_pattern(
534 self, request, autologin_user, csrf_token):
534 self, request, autologin_user, csrf_token):
535 post_url = route_path('admin_settings_issuetracker_update')
535 post_url = route_path('admin_settings_issuetracker_update')
536 post_data = {
536 post_data = {
537 'csrf_token': csrf_token
537 'csrf_token': csrf_token
538 }
538 }
539 self.app.post(post_url, post_data, status=302)
539 self.app.post(post_url, post_data, status=302)
540
540
541 def test_add_issuetracker_pattern(
541 def test_add_issuetracker_pattern(
542 self, request, autologin_user, csrf_token):
542 self, request, autologin_user, csrf_token):
543 pattern = 'issuetracker_pat'
543 pattern = 'issuetracker_pat'
544 another_pattern = pattern+'1'
544 another_pattern = pattern+'1'
545 post_url = route_path('admin_settings_issuetracker_update')
545 post_url = route_path('admin_settings_issuetracker_update')
546 post_data = {
546 post_data = {
547 'new_pattern_pattern_0': pattern,
547 'new_pattern_pattern_0': pattern,
548 'new_pattern_url_0': 'http://url',
548 'new_pattern_url_0': 'http://url',
549 'new_pattern_prefix_0': 'prefix',
549 'new_pattern_prefix_0': 'prefix',
550 'new_pattern_description_0': 'description',
550 'new_pattern_description_0': 'description',
551 'new_pattern_pattern_1': another_pattern,
551 'new_pattern_pattern_1': another_pattern,
552 'new_pattern_url_1': 'https://url1',
552 'new_pattern_url_1': 'https://url1',
553 'new_pattern_prefix_1': 'prefix1',
553 'new_pattern_prefix_1': 'prefix1',
554 'new_pattern_description_1': 'description1',
554 'new_pattern_description_1': 'description1',
555 'csrf_token': csrf_token
555 'csrf_token': csrf_token
556 }
556 }
557 self.app.post(post_url, post_data, status=302)
557 self.app.post(post_url, post_data, status=302)
558 settings = SettingsModel().get_all_settings()
558 settings = SettingsModel().get_all_settings()
559 self.uid = md5_safe(pattern)
559 self.uid = md5_safe(pattern)
560 assert settings[self.PATTERN_KEY+self.uid] == pattern
560 assert settings[self.PATTERN_KEY+self.uid] == pattern
561 self.another_uid = md5_safe(another_pattern)
561 self.another_uid = md5_safe(another_pattern)
562 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
562 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
563
563
564 @request.addfinalizer
564 @request.addfinalizer
565 def cleanup():
565 def cleanup():
566 defaults = SettingsModel().get_all_settings()
566 defaults = SettingsModel().get_all_settings()
567
567
568 entries = [name for name in defaults if (
568 entries = [name for name in defaults if (
569 (self.uid in name) or (self.another_uid in name))]
569 (self.uid in name) or (self.another_uid in name))]
570 start = len(self.RC_PREFIX)
570 start = len(self.RC_PREFIX)
571 for del_key in entries:
571 for del_key in entries:
572 # TODO: anderson: get_by_name needs name without prefix
572 # TODO: anderson: get_by_name needs name without prefix
573 entry = SettingsModel().get_setting_by_name(del_key[start:])
573 entry = SettingsModel().get_setting_by_name(del_key[start:])
574 Session().delete(entry)
574 Session().delete(entry)
575
575
576 Session().commit()
576 Session().commit()
577
577
578 def test_edit_issuetracker_pattern(
578 def test_edit_issuetracker_pattern(
579 self, autologin_user, backend, csrf_token, request):
579 self, autologin_user, backend, csrf_token, request):
580
580
581 old_pattern = 'issuetracker_pat1'
581 old_pattern = 'issuetracker_pat1'
582 old_uid = md5_safe(old_pattern)
582 old_uid = md5_safe(old_pattern)
583
583
584 post_url = route_path('admin_settings_issuetracker_update')
584 post_url = route_path('admin_settings_issuetracker_update')
585 post_data = {
585 post_data = {
586 'new_pattern_pattern_0': old_pattern,
586 'new_pattern_pattern_0': old_pattern,
587 'new_pattern_url_0': 'http://url',
587 'new_pattern_url_0': 'http://url',
588 'new_pattern_prefix_0': 'prefix',
588 'new_pattern_prefix_0': 'prefix',
589 'new_pattern_description_0': 'description',
589 'new_pattern_description_0': 'description',
590
590
591 'csrf_token': csrf_token
591 'csrf_token': csrf_token
592 }
592 }
593 self.app.post(post_url, post_data, status=302)
593 self.app.post(post_url, post_data, status=302)
594
594
595 new_pattern = 'issuetracker_pat1_edited'
595 new_pattern = 'issuetracker_pat1_edited'
596 self.new_uid = md5_safe(new_pattern)
596 self.new_uid = md5_safe(new_pattern)
597
597
598 post_url = route_path('admin_settings_issuetracker_update')
598 post_url = route_path('admin_settings_issuetracker_update')
599 post_data = {
599 post_data = {
600 'new_pattern_pattern_{}'.format(old_uid): new_pattern,
600 'new_pattern_pattern_{}'.format(old_uid): new_pattern,
601 'new_pattern_url_{}'.format(old_uid): 'https://url_edited',
601 'new_pattern_url_{}'.format(old_uid): 'https://url_edited',
602 'new_pattern_prefix_{}'.format(old_uid): 'prefix_edited',
602 'new_pattern_prefix_{}'.format(old_uid): 'prefix_edited',
603 'new_pattern_description_{}'.format(old_uid): 'description_edited',
603 'new_pattern_description_{}'.format(old_uid): 'description_edited',
604 'uid': old_uid,
604 'uid': old_uid,
605 'csrf_token': csrf_token
605 'csrf_token': csrf_token
606 }
606 }
607 self.app.post(post_url, post_data, status=302)
607 self.app.post(post_url, post_data, status=302)
608
608
609 settings = SettingsModel().get_all_settings()
609 settings = SettingsModel().get_all_settings()
610 assert settings[self.PATTERN_KEY+self.new_uid] == new_pattern
610 assert settings[self.PATTERN_KEY+self.new_uid] == new_pattern
611 assert settings[self.DESC_KEY + self.new_uid] == 'description_edited'
611 assert settings[self.DESC_KEY + self.new_uid] == 'description_edited'
612 assert self.PATTERN_KEY+old_uid not in settings
612 assert self.PATTERN_KEY+old_uid not in settings
613
613
614 @request.addfinalizer
614 @request.addfinalizer
615 def cleanup():
615 def cleanup():
616 IssueTrackerSettingsModel().delete_entries(old_uid)
616 IssueTrackerSettingsModel().delete_entries(old_uid)
617 IssueTrackerSettingsModel().delete_entries(self.new_uid)
617 IssueTrackerSettingsModel().delete_entries(self.new_uid)
618
618
619 def test_replace_issuetracker_pattern_description(
619 def test_replace_issuetracker_pattern_description(
620 self, autologin_user, csrf_token, request, settings_util):
620 self, autologin_user, csrf_token, request, settings_util):
621 prefix = 'issuetracker'
621 prefix = 'issuetracker'
622 pattern = 'issuetracker_pat'
622 pattern = 'issuetracker_pat'
623 self.uid = md5_safe(pattern)
623 self.uid = md5_safe(pattern)
624 pattern_key = '_'.join([prefix, 'pat', self.uid])
624 pattern_key = '_'.join([prefix, 'pat', self.uid])
625 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
625 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
626 desc_key = '_'.join([prefix, 'desc', self.uid])
626 desc_key = '_'.join([prefix, 'desc', self.uid])
627 rc_desc_key = '_'.join(['rhodecode', desc_key])
627 rc_desc_key = '_'.join(['rhodecode', desc_key])
628 new_description = 'new_description'
628 new_description = 'new_description'
629
629
630 settings_util.create_rhodecode_setting(
630 settings_util.create_rhodecode_setting(
631 pattern_key, pattern, 'unicode', cleanup=False)
631 pattern_key, pattern, 'unicode', cleanup=False)
632 settings_util.create_rhodecode_setting(
632 settings_util.create_rhodecode_setting(
633 desc_key, 'old description', 'unicode', cleanup=False)
633 desc_key, 'old description', 'unicode', cleanup=False)
634
634
635 post_url = route_path('admin_settings_issuetracker_update')
635 post_url = route_path('admin_settings_issuetracker_update')
636 post_data = {
636 post_data = {
637 'new_pattern_pattern_0': pattern,
637 'new_pattern_pattern_0': pattern,
638 'new_pattern_url_0': 'https://url',
638 'new_pattern_url_0': 'https://url',
639 'new_pattern_prefix_0': 'prefix',
639 'new_pattern_prefix_0': 'prefix',
640 'new_pattern_description_0': new_description,
640 'new_pattern_description_0': new_description,
641 'uid': self.uid,
641 'uid': self.uid,
642 'csrf_token': csrf_token
642 'csrf_token': csrf_token
643 }
643 }
644 self.app.post(post_url, post_data, status=302)
644 self.app.post(post_url, post_data, status=302)
645 settings = SettingsModel().get_all_settings()
645 settings = SettingsModel().get_all_settings()
646 assert settings[rc_pattern_key] == pattern
646 assert settings[rc_pattern_key] == pattern
647 assert settings[rc_desc_key] == new_description
647 assert settings[rc_desc_key] == new_description
648
648
649 @request.addfinalizer
649 @request.addfinalizer
650 def cleanup():
650 def cleanup():
651 IssueTrackerSettingsModel().delete_entries(self.uid)
651 IssueTrackerSettingsModel().delete_entries(self.uid)
652
652
653 def test_delete_issuetracker_pattern(
653 def test_delete_issuetracker_pattern(
654 self, autologin_user, backend, csrf_token, settings_util, xhr_header):
654 self, autologin_user, backend, csrf_token, settings_util, xhr_header):
655
655
656 old_pattern = 'issuetracker_pat_deleted'
656 old_pattern = 'issuetracker_pat_deleted'
657 old_uid = md5_safe(old_pattern)
657 old_uid = md5_safe(old_pattern)
658
658
659 post_url = route_path('admin_settings_issuetracker_update')
659 post_url = route_path('admin_settings_issuetracker_update')
660 post_data = {
660 post_data = {
661 'new_pattern_pattern_0': old_pattern,
661 'new_pattern_pattern_0': old_pattern,
662 'new_pattern_url_0': 'http://url',
662 'new_pattern_url_0': 'http://url',
663 'new_pattern_prefix_0': 'prefix',
663 'new_pattern_prefix_0': 'prefix',
664 'new_pattern_description_0': 'description',
664 'new_pattern_description_0': 'description',
665
665
666 'csrf_token': csrf_token
666 'csrf_token': csrf_token
667 }
667 }
668 self.app.post(post_url, post_data, status=302)
668 self.app.post(post_url, post_data, status=302)
669
669
670 post_url = route_path('admin_settings_issuetracker_delete')
670 post_url = route_path('admin_settings_issuetracker_delete')
671 post_data = {
671 post_data = {
672 'uid': old_uid,
672 'uid': old_uid,
673 'csrf_token': csrf_token
673 'csrf_token': csrf_token
674 }
674 }
675 self.app.post(post_url, post_data, extra_environ=xhr_header, status=200)
675 self.app.post(post_url, post_data, extra_environ=xhr_header, status=200)
676 settings = SettingsModel().get_all_settings()
676 settings = SettingsModel().get_all_settings()
677 assert self.PATTERN_KEY+old_uid not in settings
677 assert self.PATTERN_KEY+old_uid not in settings
678 assert self.DESC_KEY + old_uid not in settings
678 assert self.DESC_KEY + old_uid not in settings
@@ -1,89 +1,89 b''
1
1
2 <div id="update_notice" style="display: none; margin: 0px 0px 30px 0px">
2 <div id="update_notice" style="display: none; margin: 0px 0px 30px 0px">
3 <div>${_('Checking for updates...')}</div>
3 <div>${_('Checking for updates...')}</div>
4 </div>
4 </div>
5
5
6
6
7 <div class="panel panel-default">
7 <div class="panel panel-default">
8 <div class="panel-heading">
8 <div class="panel-heading">
9 <h3 class="panel-title">${_('System Info')}</h3>
9 <h3 class="panel-title">${_('System Info')}</h3>
10 % if c.allowed_to_snapshot:
10 % if c.allowed_to_snapshot:
11 <a href="${h.route_path('admin_settings_system', _query={'snapshot':1})}" class="panel-edit">${_('create summary snapshot')}</a>
11 <a href="${h.route_path('admin_settings_system', _query={'snapshot':1})}" class="panel-edit">${_('create summary snapshot')}</a>
12 % endif
12 % endif
13 </div>
13 </div>
14 <div class="panel-body">
14 <div class="panel-body">
15 <dl class="dl-horizontal settings dt-400">
15 <dl class="dl-horizontal settings dt-400">
16 % for dt, dd, warn in c.data_items:
16 % for dt, dd, warn in c.data_items:
17 <dt>${dt}${':' if dt else '---'}</dt>
17 <dt>${dt}${':' if dt else '---'}</dt>
18 <dd>${dd}${'' if dt else '---'}
18 <dd>${dd}${'' if dt else '---'}
19 % if warn and warn['message']:
19 % if warn and warn['message']:
20 <div class="alert-${warn['type']}">
20 <div class="alert-${warn['type']}">
21 <strong>${warn['message']}</strong>
21 <strong>${warn['message']}</strong>
22 </div>
22 </div>
23 % endif
23 % endif
24 </dd>
24 </dd>
25 % endfor
25 % endfor
26 </dl>
26 </dl>
27 </div>
27 </div>
28 </div>
28 </div>
29
29
30 <div class="panel panel-default">
30 <div class="panel panel-default">
31 <div class="panel-heading">
31 <div class="panel-heading">
32 <h3 class="panel-title">${_('VCS Server')}</h3>
32 <h3 class="panel-title">${_('VCS Server')}</h3>
33 </div>
33 </div>
34 <div class="panel-body">
34 <div class="panel-body">
35 <dl class="dl-horizontal settings dt-400">
35 <dl class="dl-horizontal settings dt-400">
36 % for dt, dd in c.vcsserver_data_items:
36 % for dt, dd in c.vcsserver_data_items:
37 <dt>${dt}${':' if dt else '---'}</dt>
37 <dt>${dt}${':' if dt else '---'}</dt>
38 <dd>${dd}${'' if dt else '---'}</dd>
38 <dd>${dd}${'' if dt else '---'}</dd>
39 % endfor
39 % endfor
40 </dl>
40 </dl>
41 </div>
41 </div>
42 </div>
42 </div>
43
43
44 <div class="panel panel-default">
44 <div class="panel panel-default">
45 <div class="panel-heading">
45 <div class="panel-heading">
46 <h3 class="panel-title">${_('Python Packages')}</h3>
46 <h3 class="panel-title">${_('Python Packages')}</h3>
47 </div>
47 </div>
48 <div class="panel-body">
48 <div class="panel-body">
49 <table>
49 <table>
50 <th></th>
50 <th></th>
51 <th></th>
51 <th></th>
52 <th></th>
52 <th></th>
53 % for name, package_data in c.py_modules['human_value']:
53 % for name, package_data in c.py_modules['human_value']:
54 <tr>
54 <tr>
55 <td>${name.lower()}</td>
55 <td>${name.lower()}</td>
56 <td>${package_data['version']}</td>
56 <td>${package_data['version']}</td>
57 <td>(${package_data['location']})</td>
57 <td>(${package_data['location']})</td>
58 </tr>
58 </tr>
59 % endfor
59 % endfor
60 </table>
60 </table>
61
61
62 </div>
62 </div>
63 </div>
63 </div>
64
64
65 <div class="panel panel-default">
65 <div class="panel panel-default">
66 <div class="panel-heading">
66 <div class="panel-heading">
67 <h3 class="panel-title">${_('Env Variables')}</h3>
67 <h3 class="panel-title">${_('Env Variables')}</h3>
68 </div>
68 </div>
69 <div class="panel-body">
69 <div class="panel-body">
70 <table>
70 <table>
71 <th></th>
71 <th></th>
72 <th></th>
72 <th></th>
73 % for env_key, env_val in c.env_data:
73 % for env_key, env_val in c.env_data:
74 <tr>
74 <tr>
75 <td style="vertical-align: top">${env_key}</td>
75 <td style="vertical-align: top">${env_key}</td>
76 <td>${env_val}</td>
76 <td>${env_val}</td>
77 </tr>
77 </tr>
78 % endfor
78 % endfor
79 </table>
79 </table>
80
80
81 </div>
81 </div>
82 </div>
82 </div>
83
83
84 <script>
84 <script>
85 $('#check_for_update').click(function(e){
85 $('#check_for_update').click(function(e){
86 $('#update_notice').show();
86 $('#update_notice').show();
87 $('#update_notice').load("${h.route_path('admin_settings_system_update')}");
87 $('#update_notice').load("${h.route_path('admin_settings_system_update', _query={'ver': request.GET.get('ver')})}");
88 })
88 })
89 </script>
89 </script>
@@ -1,25 +1,30 b''
1 ## upgrade block rendered afte on-click check
1 ## upgrade block rendered afte on-click check
2
2
3 <div class="alert ${'alert-warning' if c.should_upgrade else 'alert-success'}">
3 <div class="alert ${'alert-warning' if c.should_upgrade else 'alert-success'}">
4 <p>
4
5 %if c.should_upgrade:
5 %if c.should_upgrade:
6 A <b>new version</b> is available:
6 <span style="font-size: 130%">A <b>new version</b> is available !</span>
7 <br/>
8 <br/>
9
7 %if c.latest_data.get('title'):
10 %if c.latest_data.get('title'):
8 <b>${h.literal(c.latest_data['title'])}</b>
11 RhodeCode <b>${c.latest_ver}</b> - ${h.literal(c.latest_data['title'])}
9 %else:
12 %else:
10 <b>${c.latest_ver}</b>
13 RhodeCode <b>${c.latest_ver}</b>
11 %endif
14 %endif
12 %else:
15 %else:
13 This instance is already running the <b>latest</b> stable version ${c.latest_ver}.
16 Your current version, ${c.cur_ver}, is up-to-date as it is equal to or newer than the latest available version, ${c.latest_ver}.
14 %endif
17 %endif
15 </p>
18
16
19
17 % if c.should_upgrade and c.important_notices:
20 % if c.should_upgrade and c.important_notices:
18 <div>Important notes for this release:</div>
21 <br/>
19 <ul>
22 <br/>
23 <div>Summary:</div>
24 <br/>
20 % for notice in c.important_notices:
25 % for notice in c.important_notices:
21 <li>- ${notice}</li>
26 - ${notice}<br/>
22 % endfor
27 % endfor
23 </ul>
24 % endif
28 % endif
29
25 </div>
30 </div>
General Comments 0
You need to be logged in to leave comments. Login now