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