##// END OF EJS Templates
settings: fixed found problem on new admin pyramid views, and made all test pass for them.
marcink -
r1313:8df63e5b default
parent child Browse files
Show More
@@ -1,101 +1,101 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-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 collections
21 import collections
22 import logging
22 import logging
23
23
24 from pylons import tmpl_context as c
24 from pylons import tmpl_context as c
25 from pyramid.view import view_config
25 from pyramid.view import view_config
26 from pyramid.httpexceptions import HTTPFound
26 from pyramid.httpexceptions import HTTPFound
27
27
28 from rhodecode.translation import _
28 from rhodecode.translation import _
29
29
30 from rhodecode.admin.views.base import AdminSettingsView
30 from rhodecode.admin.views.base import AdminSettingsView
31 from rhodecode.lib.auth import (
31 from rhodecode.lib.auth import (
32 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
32 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
33 from rhodecode.lib.utils2 import safe_int
33 from rhodecode.lib.utils2 import safe_int
34 from rhodecode.lib import system_info
34 from rhodecode.lib import system_info
35 from rhodecode.lib import user_sessions
35 from rhodecode.lib import user_sessions
36
36
37
37
38 from rhodecode.admin.navigation import navigation_list
38 from rhodecode.admin.navigation import navigation_list
39
39
40
40
41 log = logging.getLogger(__name__)
41 log = logging.getLogger(__name__)
42
42
43
43
44 class AdminSessionSettingsView(AdminSettingsView):
44 class AdminSessionSettingsView(AdminSettingsView):
45
45
46 @LoginRequired()
46 @LoginRequired()
47 @HasPermissionAllDecorator('hg.admin')
47 @HasPermissionAllDecorator('hg.admin')
48 @view_config(
48 @view_config(
49 route_name='admin_settings_sessions', request_method='GET',
49 route_name='admin_settings_sessions', request_method='GET',
50 renderer='rhodecode:templates/admin/settings/settings.mako')
50 renderer='rhodecode:templates/admin/settings/settings.mako')
51 def settings_sessions(self):
51 def settings_sessions(self):
52 c.active = 'sessions'
52 c.active = 'sessions'
53 c.navlist = navigation_list(self.request)
53 c.navlist = navigation_list(self.request)
54
54
55 c.cleanup_older_days = 60
55 c.cleanup_older_days = 60
56 older_than_seconds = 24 * 60 * 60 * 24 * c.cleanup_older_days
56 older_than_seconds = 24 * 60 * 60 * 24 * c.cleanup_older_days
57
57
58 config = system_info.rhodecode_config().get_value()['value']['config']
58 config = system_info.rhodecode_config().get_value()['value']['config']
59 c.session_model = user_sessions.get_session_handler(
59 c.session_model = user_sessions.get_session_handler(
60 config.get('beaker.session.type', 'memory'))(config)
60 config.get('beaker.session.type', 'memory'))(config)
61
61
62 c.session_conf = c.session_model.config
62 c.session_conf = c.session_model.config
63 c.session_count = c.session_model.get_count()
63 c.session_count = c.session_model.get_count()
64 c.session_expired_count = c.session_model.get_expired_count(
64 c.session_expired_count = c.session_model.get_expired_count(
65 older_than_seconds)
65 older_than_seconds)
66
66
67 return {}
67 return {}
68
68
69 @LoginRequired()
69 @LoginRequired()
70 @CSRFRequired()
70 @CSRFRequired()
71 @HasPermissionAllDecorator('hg.admin')
71 @HasPermissionAllDecorator('hg.admin')
72 @view_config(
72 @view_config(
73 route_name='admin_settings_sessions_cleanup', request_method='POST')
73 route_name='admin_settings_sessions_cleanup', request_method='POST')
74 def settings_sessions_cleanup(self):
74 def settings_sessions_cleanup(self):
75
75
76 expire_days = safe_int(self.request.params.get('expire_days'))
76 expire_days = safe_int(self.request.params.get('expire_days'))
77
77
78 if expire_days is None:
78 if expire_days is None:
79 expire_days = 60
79 expire_days = 60
80
80
81 older_than_seconds = 24 * 60 * 60 * 24 * expire_days
81 older_than_seconds = 24 * 60 * 60 * 24 * expire_days
82
82
83 config = system_info.rhodecode_config().get_value()['value']['config']
83 config = system_info.rhodecode_config().get_value()['value']['config']
84 session_model = user_sessions.get_session_handler(
84 session_model = user_sessions.get_session_handler(
85 config.get('beaker.session.type', 'memory'))(config)
85 config.get('beaker.session.type', 'memory'))(config)
86
86
87 try:
87 try:
88 session_model.clean_sessions(
88 session_model.clean_sessions(
89 older_than_seconds=older_than_seconds)
89 older_than_seconds=older_than_seconds)
90 self.request.session.flash(
90 self.request.session.flash(
91 _('Cleaned up old sessions'), queue='success')
91 _('Cleaned up old sessions'), queue='success')
92 except user_sessions.CleanupCommand as msg:
92 except user_sessions.CleanupCommand as msg:
93 self.request.session.flash(msg, category='warning')
93 self.request.session.flash(msg.message, queue='warning')
94 except Exception as e:
94 except Exception as e:
95 log.exception('Failed session cleanup')
95 log.exception('Failed session cleanup')
96 self.request.session.flash(
96 self.request.session.flash(
97 _('Failed to cleanup up old sessions'), queue='error')
97 _('Failed to cleanup up old sessions'), queue='error')
98
98
99 redirect_to = self.request.resource_path(
99 redirect_to = self.request.resource_path(
100 self.context, route_name='admin_settings_sessions')
100 self.context, route_name='admin_settings_sessions')
101 return HTTPFound(redirect_to)
101 return HTTPFound(redirect_to)
@@ -1,200 +1,202 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-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 logging
21 import logging
22 import urllib2
22 import urllib2
23 import packaging.version
23 import packaging.version
24
24
25 from pylons import tmpl_context as c
25 from pylons import tmpl_context as c
26 from pyramid.view import view_config
26 from pyramid.view import view_config
27
27
28 import rhodecode
28 import rhodecode
29 from rhodecode.lib import helpers as h
29 from rhodecode.lib import helpers as h
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
31 from rhodecode.lib.utils2 import str2bool
31 from rhodecode.lib.utils2 import str2bool
32 from rhodecode.lib import system_info
32 from rhodecode.lib import system_info
33 from rhodecode.lib.ext_json import json
33 from rhodecode.lib.ext_json import json
34
34
35 from rhodecode.admin.views.base import AdminSettingsView
35 from rhodecode.admin.views.base import AdminSettingsView
36 from rhodecode.admin.navigation import navigation_list
36 from rhodecode.admin.navigation import navigation_list
37 from rhodecode.model.settings import SettingsModel
37 from rhodecode.model.settings import SettingsModel
38
38
39 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
40
40
41
41
42 class AdminSystemInfoSettingsView(AdminSettingsView):
42 class AdminSystemInfoSettingsView(AdminSettingsView):
43
43
44 @staticmethod
44 @staticmethod
45 def get_update_data(update_url):
45 def get_update_data(update_url):
46 """Return the JSON update data."""
46 """Return the JSON update data."""
47 ver = rhodecode.__version__
47 ver = rhodecode.__version__
48 log.debug('Checking for upgrade on `%s` server', update_url)
48 log.debug('Checking for upgrade on `%s` server', update_url)
49 opener = urllib2.build_opener()
49 opener = urllib2.build_opener()
50 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
50 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
51 response = opener.open(update_url)
51 response = opener.open(update_url)
52 response_data = response.read()
52 response_data = response.read()
53 data = json.loads(response_data)
53 data = json.loads(response_data)
54
54
55 return data
55 return data
56
56
57 def get_update_url(self):
57 def get_update_url(self):
58 settings = SettingsModel().get_all_settings()
58 settings = SettingsModel().get_all_settings()
59 return settings.get('rhodecode_update_url')
59 return settings.get('rhodecode_update_url')
60
60
61 @LoginRequired()
61 @LoginRequired()
62 @HasPermissionAllDecorator('hg.admin')
62 @HasPermissionAllDecorator('hg.admin')
63 @view_config(
63 @view_config(
64 route_name='admin_settings_system', request_method='GET',
64 route_name='admin_settings_system', request_method='GET',
65 renderer='rhodecode:templates/admin/settings/settings.mako')
65 renderer='rhodecode:templates/admin/settings/settings.mako')
66 def settings_sessions(self):
66 def settings_system_info(self):
67 _ = self.request.translate
67 _ = self.request.translate
68
68
69 c.active = 'system'
69 c.active = 'system'
70 c.navlist = navigation_list(self.request)
70 c.navlist = navigation_list(self.request)
71
71
72 # TODO(marcink), figure out how to allow only selected users to do this
72 # TODO(marcink), figure out how to allow only selected users to do this
73 c.allowed_to_snapshot = self._rhodecode_user.admin
73 c.allowed_to_snapshot = self._rhodecode_user.admin
74
74
75 snapshot = str2bool(self.request.params.get('snapshot'))
75 snapshot = str2bool(self.request.params.get('snapshot'))
76
76
77 c.rhodecode_update_url = self.get_update_url()
77 c.rhodecode_update_url = self.get_update_url()
78 server_info = system_info.get_system_info(self.request.environ)
78 server_info = system_info.get_system_info(self.request.environ)
79
79
80 for key, val in server_info.items():
80 for key, val in server_info.items():
81 setattr(c, key, val)
81 setattr(c, key, val)
82
82
83 def val(name, subkey='human_value'):
83 def val(name, subkey='human_value'):
84 return server_info[name][subkey]
84 return server_info[name][subkey]
85
85
86 def state(name):
86 def state(name):
87 return server_info[name]['state']
87 return server_info[name]['state']
88
88
89 def val2(name):
89 def val2(name):
90 val = server_info[name]['human_value']
90 val = server_info[name]['human_value']
91 state = server_info[name]['state']
91 state = server_info[name]['state']
92 return val, state
92 return val, state
93
93
94 update_info_msg = _('Note: please make sure this server can '
94 update_info_msg = _('Note: please make sure this server can '
95 'access `${url}` for the update link to work',
95 'access `${url}` for the update link to work',
96 mapping=dict(url=c.rhodecode_update_url))
96 mapping=dict(url=c.rhodecode_update_url))
97 c.data_items = [
97 c.data_items = [
98 # update info
98 # update info
99 (_('Update info'), h.literal(
99 (_('Update info'), h.literal(
100 '<span class="link" id="check_for_update" >%s.</span>' % (
100 '<span class="link" id="check_for_update" >%s.</span>' % (
101 _('Check for updates')) +
101 _('Check for updates')) +
102 '<br/> <span >%s.</span>' % (update_info_msg)
102 '<br/> <span >%s.</span>' % (update_info_msg)
103 ), ''),
103 ), ''),
104
104
105 # RhodeCode specific
105 # RhodeCode specific
106 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
106 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
107 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
107 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
108 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
108 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
109 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
109 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
110 ('', '', ''), # spacer
110 ('', '', ''), # spacer
111
111
112 # Database
112 # Database
113 (_('Database'), val('database')['url'], state('database')),
113 (_('Database'), val('database')['url'], state('database')),
114 (_('Database version'), val('database')['version'], state('database')),
114 (_('Database version'), val('database')['version'], state('database')),
115 ('', '', ''), # spacer
115 ('', '', ''), # spacer
116
116
117 # Platform/Python
117 # Platform/Python
118 (_('Platform'), val('platform')['name'], state('platform')),
118 (_('Platform'), val('platform')['name'], state('platform')),
119 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
119 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
120 (_('Python version'), val('python')['version'], state('python')),
120 (_('Python version'), val('python')['version'], state('python')),
121 (_('Python path'), val('python')['executable'], state('python')),
121 (_('Python path'), val('python')['executable'], state('python')),
122 ('', '', ''), # spacer
122 ('', '', ''), # spacer
123
123
124 # Systems stats
124 # Systems stats
125 (_('CPU'), val('cpu'), state('cpu')),
125 (_('CPU'), val('cpu'), state('cpu')),
126 (_('Load'), val('load')['text'], state('load')),
126 (_('Load'), val('load')['text'], state('load')),
127 (_('Memory'), val('memory')['text'], state('memory')),
127 (_('Memory'), val('memory')['text'], state('memory')),
128 (_('Uptime'), val('uptime')['text'], state('uptime')),
128 (_('Uptime'), val('uptime')['text'], state('uptime')),
129 ('', '', ''), # spacer
129 ('', '', ''), # spacer
130
130
131 # Repo storage
131 # Repo storage
132 (_('Storage location'), val('storage')['path'], state('storage')),
132 (_('Storage location'), val('storage')['path'], state('storage')),
133 (_('Storage info'), val('storage')['text'], state('storage')),
133 (_('Storage info'), val('storage')['text'], state('storage')),
134 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
134 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
135
135
136 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
136 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
137 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
137 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
138
138
139 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
139 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
140 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
140 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
141
141
142 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
142 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
143 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
143 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
144
144
145 (_('Search info'), val('search')['text'], state('search')),
145 (_('Search info'), val('search')['text'], state('search')),
146 (_('Search location'), val('search')['location'], state('search')),
146 (_('Search location'), val('search')['location'], state('search')),
147 ('', '', ''), # spacer
147 ('', '', ''), # spacer
148
148
149 # VCS specific
149 # VCS specific
150 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
150 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
151 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
151 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
152 (_('GIT'), val('git'), state('git')),
152 (_('GIT'), val('git'), state('git')),
153 (_('HG'), val('hg'), state('hg')),
153 (_('HG'), val('hg'), state('hg')),
154 (_('SVN'), val('svn'), state('svn')),
154 (_('SVN'), val('svn'), state('svn')),
155
155
156 ]
156 ]
157
157
158 if snapshot:
158 if snapshot:
159 if c.allowed_to_snapshot:
159 if c.allowed_to_snapshot:
160 c.data_items.pop(0) # remove server info
160 c.data_items.pop(0) # remove server info
161 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
161 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
162 else:
162 else:
163 self.request.session.flash(
163 self.request.session.flash(
164 'You are not allowed to do this', queue='warning')
164 'You are not allowed to do this', queue='warning')
165 return {}
165 return {}
166
166
167 @LoginRequired()
167 @LoginRequired()
168 @HasPermissionAllDecorator('hg.admin')
168 @HasPermissionAllDecorator('hg.admin')
169 @view_config(
169 @view_config(
170 route_name='admin_settings_system_update', request_method='GET',
170 route_name='admin_settings_system_update', request_method='GET',
171 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
171 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
172 def settings_sessions_cleanup(self):
172 def settings_system_info_check_update(self):
173 _ = self.request.translate
173 _ = self.request.translate
174
174
175 update_url = self.get_update_url()
175 update_url = self.get_update_url()
176
176
177 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
177 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
178 try:
178 try:
179 data = self.get_update_data(update_url)
179 data = self.get_update_data(update_url)
180 except urllib2.URLError as e:
180 except urllib2.URLError as e:
181 log.exception("Exception contacting upgrade server")
181 log.exception("Exception contacting upgrade server")
182 self.request.override_renderer = 'string'
182 return _err('Failed to contact upgrade server: %r' % e)
183 return _err('Failed to contact upgrade server: %r' % e)
183 except ValueError as e:
184 except ValueError as e:
184 log.exception("Bad data sent from update server")
185 log.exception("Bad data sent from update server")
186 self.request.override_renderer = 'string'
185 return _err('Bad data sent from update server')
187 return _err('Bad data sent from update server')
186
188
187 latest = data['versions'][0]
189 latest = data['versions'][0]
188
190
189 c.update_url = update_url
191 c.update_url = update_url
190 c.latest_data = latest
192 c.latest_data = latest
191 c.latest_ver = latest['version']
193 c.latest_ver = latest['version']
192 c.cur_ver = rhodecode.__version__
194 c.cur_ver = rhodecode.__version__
193 c.should_upgrade = False
195 c.should_upgrade = False
194
196
195 if (packaging.version.Version(c.latest_ver) >
197 if (packaging.version.Version(c.latest_ver) >
196 packaging.version.Version(c.cur_ver)):
198 packaging.version.Version(c.cur_ver)):
197 c.should_upgrade = True
199 c.should_upgrade = True
198 c.important_notices = latest['general']
200 c.important_notices = latest['general']
199
201
200 return {}
202 return {}
@@ -1,621 +1,665 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 import rhodecode
24 import rhodecode
25 from rhodecode.config.routing import ADMIN_PREFIX
25 from rhodecode.config.routing import ADMIN_PREFIX
26 from rhodecode.lib.utils2 import md5
26 from rhodecode.lib.utils2 import md5
27 from rhodecode.model.db import RhodeCodeUi
27 from rhodecode.model.db import RhodeCodeUi
28 from rhodecode.model.meta import Session
28 from rhodecode.model.meta import Session
29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
29 from rhodecode.model.settings import SettingsModel, IssueTrackerSettingsModel
30 from rhodecode.tests import url, assert_session_flash
30 from rhodecode.tests import url, assert_session_flash
31 from rhodecode.tests.utils import AssertResponse
31 from rhodecode.tests.utils import AssertResponse
32
32
33
33
34 UPDATE_DATA_QUALNAME = (
34 UPDATE_DATA_QUALNAME = (
35 'rhodecode.controllers.admin.settings.SettingsController.get_update_data')
35 'rhodecode.admin.views.system_info.AdminSystemInfoSettingsView.get_update_data')
36
36
37
37
38 @pytest.mark.usefixtures('autologin_user', 'app')
38 @pytest.mark.usefixtures('autologin_user', 'app')
39 class TestAdminSettingsController:
39 class TestAdminSettingsController(object):
40
40
41 @pytest.mark.parametrize('urlname', [
41 @pytest.mark.parametrize('urlname', [
42 'admin_settings_vcs',
42 'admin_settings_vcs',
43 'admin_settings_mapping',
43 'admin_settings_mapping',
44 'admin_settings_global',
44 'admin_settings_global',
45 'admin_settings_visual',
45 'admin_settings_visual',
46 'admin_settings_email',
46 'admin_settings_email',
47 'admin_settings_hooks',
47 'admin_settings_hooks',
48 'admin_settings_search',
48 'admin_settings_search',
49 'admin_settings_system',
50 ])
49 ])
51 def test_simple_get(self, urlname, app):
50 def test_simple_get(self, urlname, app):
52 app.get(url(urlname))
51 app.get(url(urlname))
53
52
54 def test_create_custom_hook(self, csrf_token):
53 def test_create_custom_hook(self, csrf_token):
55 response = self.app.post(
54 response = self.app.post(
56 url('admin_settings_hooks'),
55 url('admin_settings_hooks'),
57 params={
56 params={
58 'new_hook_ui_key': 'test_hooks_1',
57 'new_hook_ui_key': 'test_hooks_1',
59 'new_hook_ui_value': 'cd /tmp',
58 'new_hook_ui_value': 'cd /tmp',
60 'csrf_token': csrf_token})
59 'csrf_token': csrf_token})
61
60
62 response = response.follow()
61 response = response.follow()
63 response.mustcontain('test_hooks_1')
62 response.mustcontain('test_hooks_1')
64 response.mustcontain('cd /tmp')
63 response.mustcontain('cd /tmp')
65
64
66 def test_create_custom_hook_delete(self, csrf_token):
65 def test_create_custom_hook_delete(self, csrf_token):
67 response = self.app.post(
66 response = self.app.post(
68 url('admin_settings_hooks'),
67 url('admin_settings_hooks'),
69 params={
68 params={
70 'new_hook_ui_key': 'test_hooks_2',
69 'new_hook_ui_key': 'test_hooks_2',
71 'new_hook_ui_value': 'cd /tmp2',
70 'new_hook_ui_value': 'cd /tmp2',
72 'csrf_token': csrf_token})
71 'csrf_token': csrf_token})
73
72
74 response = response.follow()
73 response = response.follow()
75 response.mustcontain('test_hooks_2')
74 response.mustcontain('test_hooks_2')
76 response.mustcontain('cd /tmp2')
75 response.mustcontain('cd /tmp2')
77
76
78 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
77 hook_id = SettingsModel().get_ui_by_key('test_hooks_2').ui_id
79
78
80 # delete
79 # delete
81 self.app.post(
80 self.app.post(
82 url('admin_settings_hooks'),
81 url('admin_settings_hooks'),
83 params={'hook_id': hook_id, 'csrf_token': csrf_token})
82 params={'hook_id': hook_id, 'csrf_token': csrf_token})
84 response = self.app.get(url('admin_settings_hooks'))
83 response = self.app.get(url('admin_settings_hooks'))
85 response.mustcontain(no=['test_hooks_2'])
84 response.mustcontain(no=['test_hooks_2'])
86 response.mustcontain(no=['cd /tmp2'])
85 response.mustcontain(no=['cd /tmp2'])
87
86
88 def test_system_update_new_version(self):
89 update_data = {
90 'versions': [
91 {
92 'version': '100.3.1415926535',
93 'general': 'The latest version we are ever going to ship'
94 },
95 {
96 'version': '0.0.0',
97 'general': 'The first version we ever shipped'
98 }
99 ]
100 }
101 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
102 response = self.app.get(url('admin_settings_system_update'))
103 response.mustcontain('A <b>new version</b> is available')
104
105 def test_system_update_nothing_new(self):
106 update_data = {
107 'versions': [
108 {
109 'version': '0.0.0',
110 'general': 'The first version we ever shipped'
111 }
112 ]
113 }
114 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
115 response = self.app.get(url('admin_settings_system_update'))
116 response.mustcontain(
117 'You already have the <b>latest</b> stable version.')
118
119 def test_system_update_bad_response(self):
120 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
121 response = self.app.get(url('admin_settings_system_update'))
122 response.mustcontain(
123 'Bad data sent from update server')
124
125
87
126 @pytest.mark.usefixtures('autologin_user', 'app')
88 @pytest.mark.usefixtures('autologin_user', 'app')
127 class TestAdminSettingsGlobal:
89 class TestAdminSettingsGlobal(object):
128
90
129 def test_pre_post_code_code_active(self, csrf_token):
91 def test_pre_post_code_code_active(self, csrf_token):
130 pre_code = 'rc-pre-code-187652122'
92 pre_code = 'rc-pre-code-187652122'
131 post_code = 'rc-postcode-98165231'
93 post_code = 'rc-postcode-98165231'
132
94
133 response = self.post_and_verify_settings({
95 response = self.post_and_verify_settings({
134 'rhodecode_pre_code': pre_code,
96 'rhodecode_pre_code': pre_code,
135 'rhodecode_post_code': post_code,
97 'rhodecode_post_code': post_code,
136 'csrf_token': csrf_token,
98 'csrf_token': csrf_token,
137 })
99 })
138
100
139 response = response.follow()
101 response = response.follow()
140 response.mustcontain(pre_code, post_code)
102 response.mustcontain(pre_code, post_code)
141
103
142 def test_pre_post_code_code_inactive(self, csrf_token):
104 def test_pre_post_code_code_inactive(self, csrf_token):
143 pre_code = 'rc-pre-code-187652122'
105 pre_code = 'rc-pre-code-187652122'
144 post_code = 'rc-postcode-98165231'
106 post_code = 'rc-postcode-98165231'
145 response = self.post_and_verify_settings({
107 response = self.post_and_verify_settings({
146 'rhodecode_pre_code': '',
108 'rhodecode_pre_code': '',
147 'rhodecode_post_code': '',
109 'rhodecode_post_code': '',
148 'csrf_token': csrf_token,
110 'csrf_token': csrf_token,
149 })
111 })
150
112
151 response = response.follow()
113 response = response.follow()
152 response.mustcontain(no=[pre_code, post_code])
114 response.mustcontain(no=[pre_code, post_code])
153
115
154 def test_captcha_activate(self, csrf_token):
116 def test_captcha_activate(self, csrf_token):
155 self.post_and_verify_settings({
117 self.post_and_verify_settings({
156 'rhodecode_captcha_private_key': '1234567890',
118 'rhodecode_captcha_private_key': '1234567890',
157 'rhodecode_captcha_public_key': '1234567890',
119 'rhodecode_captcha_public_key': '1234567890',
158 'csrf_token': csrf_token,
120 'csrf_token': csrf_token,
159 })
121 })
160
122
161 response = self.app.get(ADMIN_PREFIX + '/register')
123 response = self.app.get(ADMIN_PREFIX + '/register')
162 response.mustcontain('captcha')
124 response.mustcontain('captcha')
163
125
164 def test_captcha_deactivate(self, csrf_token):
126 def test_captcha_deactivate(self, csrf_token):
165 self.post_and_verify_settings({
127 self.post_and_verify_settings({
166 'rhodecode_captcha_private_key': '',
128 'rhodecode_captcha_private_key': '',
167 'rhodecode_captcha_public_key': '1234567890',
129 'rhodecode_captcha_public_key': '1234567890',
168 'csrf_token': csrf_token,
130 'csrf_token': csrf_token,
169 })
131 })
170
132
171 response = self.app.get(ADMIN_PREFIX + '/register')
133 response = self.app.get(ADMIN_PREFIX + '/register')
172 response.mustcontain(no=['captcha'])
134 response.mustcontain(no=['captcha'])
173
135
174 def test_title_change(self, csrf_token):
136 def test_title_change(self, csrf_token):
175 old_title = 'RhodeCode'
137 old_title = 'RhodeCode'
176 new_title = old_title + '_changed'
138 new_title = old_title + '_changed'
177
139
178 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
140 for new_title in ['Changed', 'Ε»Γ³Ε‚wik', old_title]:
179 response = self.post_and_verify_settings({
141 response = self.post_and_verify_settings({
180 'rhodecode_title': new_title,
142 'rhodecode_title': new_title,
181 'csrf_token': csrf_token,
143 'csrf_token': csrf_token,
182 })
144 })
183
145
184 response = response.follow()
146 response = response.follow()
185 response.mustcontain(
147 response.mustcontain(
186 """<div class="branding">- %s</div>""" % new_title)
148 """<div class="branding">- %s</div>""" % new_title)
187
149
188 def post_and_verify_settings(self, settings):
150 def post_and_verify_settings(self, settings):
189 old_title = 'RhodeCode'
151 old_title = 'RhodeCode'
190 old_realm = 'RhodeCode authentication'
152 old_realm = 'RhodeCode authentication'
191 params = {
153 params = {
192 'rhodecode_title': old_title,
154 'rhodecode_title': old_title,
193 'rhodecode_realm': old_realm,
155 'rhodecode_realm': old_realm,
194 'rhodecode_pre_code': '',
156 'rhodecode_pre_code': '',
195 'rhodecode_post_code': '',
157 'rhodecode_post_code': '',
196 'rhodecode_captcha_private_key': '',
158 'rhodecode_captcha_private_key': '',
197 'rhodecode_captcha_public_key': '',
159 'rhodecode_captcha_public_key': '',
198 'rhodecode_create_personal_repo_group': False,
160 'rhodecode_create_personal_repo_group': False,
199 'rhodecode_personal_repo_group_pattern': '${username}',
161 'rhodecode_personal_repo_group_pattern': '${username}',
200 }
162 }
201 params.update(settings)
163 params.update(settings)
202 response = self.app.post(url('admin_settings_global'), params=params)
164 response = self.app.post(url('admin_settings_global'), params=params)
203
165
204 assert_session_flash(response, 'Updated application settings')
166 assert_session_flash(response, 'Updated application settings')
205 app_settings = SettingsModel().get_all_settings()
167 app_settings = SettingsModel().get_all_settings()
206 del settings['csrf_token']
168 del settings['csrf_token']
207 for key, value in settings.iteritems():
169 for key, value in settings.iteritems():
208 assert app_settings[key] == value.decode('utf-8')
170 assert app_settings[key] == value.decode('utf-8')
209
171
210 return response
172 return response
211
173
212
174
213 @pytest.mark.usefixtures('autologin_user', 'app')
175 @pytest.mark.usefixtures('autologin_user', 'app')
214 class TestAdminSettingsVcs:
176 class TestAdminSettingsVcs(object):
215
177
216 def test_contains_svn_default_patterns(self, app):
178 def test_contains_svn_default_patterns(self, app):
217 response = app.get(url('admin_settings_vcs'))
179 response = app.get(url('admin_settings_vcs'))
218 expected_patterns = [
180 expected_patterns = [
219 '/trunk',
181 '/trunk',
220 '/branches/*',
182 '/branches/*',
221 '/tags/*',
183 '/tags/*',
222 ]
184 ]
223 for pattern in expected_patterns:
185 for pattern in expected_patterns:
224 response.mustcontain(pattern)
186 response.mustcontain(pattern)
225
187
226 def test_add_new_svn_branch_and_tag_pattern(
188 def test_add_new_svn_branch_and_tag_pattern(
227 self, app, backend_svn, form_defaults, disable_sql_cache,
189 self, app, backend_svn, form_defaults, disable_sql_cache,
228 csrf_token):
190 csrf_token):
229 form_defaults.update({
191 form_defaults.update({
230 'new_svn_branch': '/exp/branches/*',
192 'new_svn_branch': '/exp/branches/*',
231 'new_svn_tag': '/important_tags/*',
193 'new_svn_tag': '/important_tags/*',
232 'csrf_token': csrf_token,
194 'csrf_token': csrf_token,
233 })
195 })
234
196
235 response = app.post(
197 response = app.post(
236 url('admin_settings_vcs'), params=form_defaults, status=302)
198 url('admin_settings_vcs'), params=form_defaults, status=302)
237 response = response.follow()
199 response = response.follow()
238
200
239 # Expect to find the new values on the page
201 # Expect to find the new values on the page
240 response.mustcontain('/exp/branches/*')
202 response.mustcontain('/exp/branches/*')
241 response.mustcontain('/important_tags/*')
203 response.mustcontain('/important_tags/*')
242
204
243 # Expect that those patterns are used to match branches and tags now
205 # Expect that those patterns are used to match branches and tags now
244 repo = backend_svn['svn-simple-layout'].scm_instance()
206 repo = backend_svn['svn-simple-layout'].scm_instance()
245 assert 'exp/branches/exp-sphinx-docs' in repo.branches
207 assert 'exp/branches/exp-sphinx-docs' in repo.branches
246 assert 'important_tags/v0.5' in repo.tags
208 assert 'important_tags/v0.5' in repo.tags
247
209
248 def test_add_same_svn_value_twice_shows_an_error_message(
210 def test_add_same_svn_value_twice_shows_an_error_message(
249 self, app, form_defaults, csrf_token, settings_util):
211 self, app, form_defaults, csrf_token, settings_util):
250 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
212 settings_util.create_rhodecode_ui('vcs_svn_branch', '/test')
251 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
213 settings_util.create_rhodecode_ui('vcs_svn_tag', '/test')
252
214
253 response = app.post(
215 response = app.post(
254 url('admin_settings_vcs'),
216 url('admin_settings_vcs'),
255 params={
217 params={
256 'paths_root_path': form_defaults['paths_root_path'],
218 'paths_root_path': form_defaults['paths_root_path'],
257 'new_svn_branch': '/test',
219 'new_svn_branch': '/test',
258 'new_svn_tag': '/test',
220 'new_svn_tag': '/test',
259 'csrf_token': csrf_token,
221 'csrf_token': csrf_token,
260 },
222 },
261 status=200)
223 status=200)
262
224
263 response.mustcontain("Pattern already exists")
225 response.mustcontain("Pattern already exists")
264 response.mustcontain("Some form inputs contain invalid data.")
226 response.mustcontain("Some form inputs contain invalid data.")
265
227
266 @pytest.mark.parametrize('section', [
228 @pytest.mark.parametrize('section', [
267 'vcs_svn_branch',
229 'vcs_svn_branch',
268 'vcs_svn_tag',
230 'vcs_svn_tag',
269 ])
231 ])
270 def test_delete_svn_patterns(
232 def test_delete_svn_patterns(
271 self, section, app, csrf_token, settings_util):
233 self, section, app, csrf_token, settings_util):
272 setting = settings_util.create_rhodecode_ui(
234 setting = settings_util.create_rhodecode_ui(
273 section, '/test_delete', cleanup=False)
235 section, '/test_delete', cleanup=False)
274
236
275 app.post(
237 app.post(
276 url('admin_settings_vcs'),
238 url('admin_settings_vcs'),
277 params={
239 params={
278 '_method': 'delete',
240 '_method': 'delete',
279 'delete_svn_pattern': setting.ui_id,
241 'delete_svn_pattern': setting.ui_id,
280 'csrf_token': csrf_token},
242 'csrf_token': csrf_token},
281 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
243 headers={'X-REQUESTED-WITH': 'XMLHttpRequest'})
282
244
283 @pytest.mark.parametrize('section', [
245 @pytest.mark.parametrize('section', [
284 'vcs_svn_branch',
246 'vcs_svn_branch',
285 'vcs_svn_tag',
247 'vcs_svn_tag',
286 ])
248 ])
287 def test_delete_svn_patterns_raises_400_when_no_xhr(
249 def test_delete_svn_patterns_raises_400_when_no_xhr(
288 self, section, app, csrf_token, settings_util):
250 self, section, app, csrf_token, settings_util):
289 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
251 setting = settings_util.create_rhodecode_ui(section, '/test_delete')
290
252
291 app.post(
253 app.post(
292 url('admin_settings_vcs'),
254 url('admin_settings_vcs'),
293 params={
255 params={
294 '_method': 'delete',
256 '_method': 'delete',
295 'delete_svn_pattern': setting.ui_id,
257 'delete_svn_pattern': setting.ui_id,
296 'csrf_token': csrf_token},
258 'csrf_token': csrf_token},
297 status=400)
259 status=400)
298
260
299 def test_extensions_hgsubversion(self, app, form_defaults, csrf_token):
261 def test_extensions_hgsubversion(self, app, form_defaults, csrf_token):
300 form_defaults.update({
262 form_defaults.update({
301 'csrf_token': csrf_token,
263 'csrf_token': csrf_token,
302 'extensions_hgsubversion': 'True',
264 'extensions_hgsubversion': 'True',
303 })
265 })
304 response = app.post(
266 response = app.post(
305 url('admin_settings_vcs'),
267 url('admin_settings_vcs'),
306 params=form_defaults,
268 params=form_defaults,
307 status=302)
269 status=302)
308
270
309 response = response.follow()
271 response = response.follow()
310 extensions_input = (
272 extensions_input = (
311 '<input id="extensions_hgsubversion" '
273 '<input id="extensions_hgsubversion" '
312 'name="extensions_hgsubversion" type="checkbox" '
274 'name="extensions_hgsubversion" type="checkbox" '
313 'value="True" checked="checked" />')
275 'value="True" checked="checked" />')
314 response.mustcontain(extensions_input)
276 response.mustcontain(extensions_input)
315
277
316 def test_has_a_section_for_pull_request_settings(self, app):
278 def test_has_a_section_for_pull_request_settings(self, app):
317 response = app.get(url('admin_settings_vcs'))
279 response = app.get(url('admin_settings_vcs'))
318 response.mustcontain('Pull Request Settings')
280 response.mustcontain('Pull Request Settings')
319
281
320 def test_has_an_input_for_invalidation_of_inline_comments(
282 def test_has_an_input_for_invalidation_of_inline_comments(
321 self, app):
283 self, app):
322 response = app.get(url('admin_settings_vcs'))
284 response = app.get(url('admin_settings_vcs'))
323 assert_response = AssertResponse(response)
285 assert_response = AssertResponse(response)
324 assert_response.one_element_exists(
286 assert_response.one_element_exists(
325 '[name=rhodecode_use_outdated_comments]')
287 '[name=rhodecode_use_outdated_comments]')
326
288
327 @pytest.mark.parametrize('new_value', [True, False])
289 @pytest.mark.parametrize('new_value', [True, False])
328 def test_allows_to_change_invalidation_of_inline_comments(
290 def test_allows_to_change_invalidation_of_inline_comments(
329 self, app, form_defaults, csrf_token, new_value):
291 self, app, form_defaults, csrf_token, new_value):
330 setting_key = 'use_outdated_comments'
292 setting_key = 'use_outdated_comments'
331 setting = SettingsModel().create_or_update_setting(
293 setting = SettingsModel().create_or_update_setting(
332 setting_key, not new_value, 'bool')
294 setting_key, not new_value, 'bool')
333 Session().add(setting)
295 Session().add(setting)
334 Session().commit()
296 Session().commit()
335
297
336 form_defaults.update({
298 form_defaults.update({
337 'csrf_token': csrf_token,
299 'csrf_token': csrf_token,
338 'rhodecode_use_outdated_comments': str(new_value),
300 'rhodecode_use_outdated_comments': str(new_value),
339 })
301 })
340 response = app.post(
302 response = app.post(
341 url('admin_settings_vcs'),
303 url('admin_settings_vcs'),
342 params=form_defaults,
304 params=form_defaults,
343 status=302)
305 status=302)
344 response = response.follow()
306 response = response.follow()
345 setting = SettingsModel().get_setting_by_name(setting_key)
307 setting = SettingsModel().get_setting_by_name(setting_key)
346 assert setting.app_settings_value is new_value
308 assert setting.app_settings_value is new_value
347
309
348 def test_has_a_section_for_labs_settings_if_enabled(self, app):
310 def test_has_a_section_for_labs_settings_if_enabled(self, app):
349 with mock.patch.dict(
311 with mock.patch.dict(
350 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
312 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
351 response = self.app.get(url('admin_settings_vcs'))
313 response = self.app.get(url('admin_settings_vcs'))
352 response.mustcontain('Labs Settings')
314 response.mustcontain('Labs Settings')
353
315
354 def test_has_not_a_section_for_labs_settings_if_disables(self, app):
316 def test_has_not_a_section_for_labs_settings_if_disables(self, app):
355 with mock.patch.dict(
317 with mock.patch.dict(
356 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
318 rhodecode.CONFIG, {'labs_settings_active': 'false'}):
357 response = self.app.get(url('admin_settings_vcs'))
319 response = self.app.get(url('admin_settings_vcs'))
358 response.mustcontain(no='Labs Settings')
320 response.mustcontain(no='Labs Settings')
359
321
360 @pytest.mark.parametrize('new_value', [True, False])
322 @pytest.mark.parametrize('new_value', [True, False])
361 def test_allows_to_change_hg_rebase_merge_strategy(
323 def test_allows_to_change_hg_rebase_merge_strategy(
362 self, app, form_defaults, csrf_token, new_value):
324 self, app, form_defaults, csrf_token, new_value):
363 setting_key = 'hg_use_rebase_for_merging'
325 setting_key = 'hg_use_rebase_for_merging'
364
326
365 form_defaults.update({
327 form_defaults.update({
366 'csrf_token': csrf_token,
328 'csrf_token': csrf_token,
367 'rhodecode_' + setting_key: str(new_value),
329 'rhodecode_' + setting_key: str(new_value),
368 })
330 })
369
331
370 with mock.patch.dict(
332 with mock.patch.dict(
371 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
333 rhodecode.CONFIG, {'labs_settings_active': 'true'}):
372 app.post(
334 app.post(
373 url('admin_settings_vcs'),
335 url('admin_settings_vcs'),
374 params=form_defaults,
336 params=form_defaults,
375 status=302)
337 status=302)
376
338
377 setting = SettingsModel().get_setting_by_name(setting_key)
339 setting = SettingsModel().get_setting_by_name(setting_key)
378 assert setting.app_settings_value is new_value
340 assert setting.app_settings_value is new_value
379
341
380 @pytest.fixture
342 @pytest.fixture
381 def disable_sql_cache(self, request):
343 def disable_sql_cache(self, request):
382 patcher = mock.patch(
344 patcher = mock.patch(
383 'rhodecode.lib.caching_query.FromCache.process_query')
345 'rhodecode.lib.caching_query.FromCache.process_query')
384 request.addfinalizer(patcher.stop)
346 request.addfinalizer(patcher.stop)
385 patcher.start()
347 patcher.start()
386
348
387 @pytest.fixture
349 @pytest.fixture
388 def form_defaults(self):
350 def form_defaults(self):
389 from rhodecode.controllers.admin.settings import SettingsController
351 from rhodecode.controllers.admin.settings import SettingsController
390 controller = SettingsController()
352 controller = SettingsController()
391 return controller._form_defaults()
353 return controller._form_defaults()
392
354
393 # TODO: johbo: What we really want is to checkpoint before a test run and
355 # TODO: johbo: What we really want is to checkpoint before a test run and
394 # reset the session afterwards.
356 # reset the session afterwards.
395 @pytest.fixture(scope='class', autouse=True)
357 @pytest.fixture(scope='class', autouse=True)
396 def cleanup_settings(self, request, pylonsapp):
358 def cleanup_settings(self, request, pylonsapp):
397 ui_id = RhodeCodeUi.ui_id
359 ui_id = RhodeCodeUi.ui_id
398 original_ids = list(
360 original_ids = list(
399 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
361 r.ui_id for r in RhodeCodeUi.query().values(ui_id))
400
362
401 @request.addfinalizer
363 @request.addfinalizer
402 def cleanup():
364 def cleanup():
403 RhodeCodeUi.query().filter(
365 RhodeCodeUi.query().filter(
404 ui_id.notin_(original_ids)).delete(False)
366 ui_id.notin_(original_ids)).delete(False)
405
367
406
368
407 @pytest.mark.usefixtures('autologin_user', 'app')
369 @pytest.mark.usefixtures('autologin_user', 'app')
408 class TestLabsSettings(object):
370 class TestLabsSettings(object):
409 def test_get_settings_page_disabled(self):
371 def test_get_settings_page_disabled(self):
410 with mock.patch.dict(rhodecode.CONFIG,
372 with mock.patch.dict(rhodecode.CONFIG,
411 {'labs_settings_active': 'false'}):
373 {'labs_settings_active': 'false'}):
412 response = self.app.get(url('admin_settings_labs'), status=302)
374 response = self.app.get(url('admin_settings_labs'), status=302)
413
375
414 assert response.location.endswith(url('admin_settings'))
376 assert response.location.endswith(url('admin_settings'))
415
377
416 def test_get_settings_page_enabled(self):
378 def test_get_settings_page_enabled(self):
417 from rhodecode.controllers.admin import settings
379 from rhodecode.controllers.admin import settings
418 lab_settings = [
380 lab_settings = [
419 settings.LabSetting(
381 settings.LabSetting(
420 key='rhodecode_bool',
382 key='rhodecode_bool',
421 type='bool',
383 type='bool',
422 group='bool group',
384 group='bool group',
423 label='bool label',
385 label='bool label',
424 help='bool help'
386 help='bool help'
425 ),
387 ),
426 settings.LabSetting(
388 settings.LabSetting(
427 key='rhodecode_text',
389 key='rhodecode_text',
428 type='unicode',
390 type='unicode',
429 group='text group',
391 group='text group',
430 label='text label',
392 label='text label',
431 help='text help'
393 help='text help'
432 ),
394 ),
433 ]
395 ]
434 with mock.patch.dict(rhodecode.CONFIG,
396 with mock.patch.dict(rhodecode.CONFIG,
435 {'labs_settings_active': 'true'}):
397 {'labs_settings_active': 'true'}):
436 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
398 with mock.patch.object(settings, '_LAB_SETTINGS', lab_settings):
437 response = self.app.get(url('admin_settings_labs'))
399 response = self.app.get(url('admin_settings_labs'))
438
400
439 assert '<label>bool group:</label>' in response
401 assert '<label>bool group:</label>' in response
440 assert '<label for="rhodecode_bool">bool label</label>' in response
402 assert '<label for="rhodecode_bool">bool label</label>' in response
441 assert '<p class="help-block">bool help</p>' in response
403 assert '<p class="help-block">bool help</p>' in response
442 assert 'name="rhodecode_bool" type="checkbox"' in response
404 assert 'name="rhodecode_bool" type="checkbox"' in response
443
405
444 assert '<label>text group:</label>' in response
406 assert '<label>text group:</label>' in response
445 assert '<label for="rhodecode_text">text label</label>' in response
407 assert '<label for="rhodecode_text">text label</label>' in response
446 assert '<p class="help-block">text help</p>' in response
408 assert '<p class="help-block">text help</p>' in response
447 assert 'name="rhodecode_text" size="60" type="text"' in response
409 assert 'name="rhodecode_text" size="60" type="text"' in response
448
410
449
411
450 @pytest.mark.usefixtures('app')
412 @pytest.mark.usefixtures('app')
451 class TestOpenSourceLicenses(object):
413 class TestOpenSourceLicenses(object):
452
414
453 def _get_url(self):
415 def _get_url(self):
454 return ADMIN_PREFIX + '/settings/open_source'
416 return ADMIN_PREFIX + '/settings/open_source'
455
417
456 def test_records_are_displayed(self, autologin_user):
418 def test_records_are_displayed(self, autologin_user):
457 sample_licenses = {
419 sample_licenses = {
458 "python2.7-pytest-2.7.1": {
420 "python2.7-pytest-2.7.1": {
459 "UNKNOWN": None
421 "UNKNOWN": None
460 },
422 },
461 "python2.7-Markdown-2.6.2": {
423 "python2.7-Markdown-2.6.2": {
462 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
424 "BSD-3-Clause": "http://spdx.org/licenses/BSD-3-Clause"
463 }
425 }
464 }
426 }
465 read_licenses_patch = mock.patch(
427 read_licenses_patch = mock.patch(
466 'rhodecode.admin.views.read_opensource_licenses',
428 'rhodecode.admin.views.open_source_licenses.read_opensource_licenses',
467 return_value=sample_licenses)
429 return_value=sample_licenses)
468 with read_licenses_patch:
430 with read_licenses_patch:
469 response = self.app.get(self._get_url(), status=200)
431 response = self.app.get(self._get_url(), status=200)
470
432
471 assert_response = AssertResponse(response)
433 assert_response = AssertResponse(response)
472 assert_response.element_contains(
434 assert_response.element_contains(
473 '.panel-heading', 'Licenses of Third Party Packages')
435 '.panel-heading', 'Licenses of Third Party Packages')
474 for name in sample_licenses:
436 for name in sample_licenses:
475 response.mustcontain(name)
437 response.mustcontain(name)
476 for license in sample_licenses[name]:
438 for license in sample_licenses[name]:
477 assert_response.element_contains('.panel-body', license)
439 assert_response.element_contains('.panel-body', license)
478
440
479 def test_records_can_be_read(self, autologin_user):
441 def test_records_can_be_read(self, autologin_user):
480 response = self.app.get(self._get_url(), status=200)
442 response = self.app.get(self._get_url(), status=200)
481 assert_response = AssertResponse(response)
443 assert_response = AssertResponse(response)
482 assert_response.element_contains(
444 assert_response.element_contains(
483 '.panel-heading', 'Licenses of Third Party Packages')
445 '.panel-heading', 'Licenses of Third Party Packages')
484
446
485 def test_forbidden_when_normal_user(self, autologin_regular_user):
447 def test_forbidden_when_normal_user(self, autologin_regular_user):
486 self.app.get(self._get_url(), status=403)
448 self.app.get(self._get_url(), status=403)
487
449
488
450
451 @pytest.mark.usefixtures('app')
452 class TestUserSessions(object):
453
454 def _get_url(self, name='admin_settings_sessions'):
455 return {
456 'admin_settings_sessions': ADMIN_PREFIX + '/settings/sessions',
457 'admin_settings_sessions_cleanup': ADMIN_PREFIX + '/settings/sessions/cleanup'
458 }[name]
459
460 def test_forbidden_when_normal_user(self, autologin_regular_user):
461 self.app.get(self._get_url(), status=403)
462
463 def test_show_sessions_page(self, autologin_user):
464 response = self.app.get(self._get_url(), status=200)
465 response.mustcontain('file')
466
467 def test_cleanup_old_sessions(self, autologin_user, csrf_token):
468
469 post_data = {
470 'csrf_token': csrf_token,
471 'expire_days': '60'
472 }
473 response = self.app.post(
474 self._get_url('admin_settings_sessions_cleanup'), params=post_data,
475 status=302)
476 assert_session_flash(response, 'Please execute this command')
477
478
479 @pytest.mark.usefixtures('app')
480 class TestAdminSystemInfo(object):
481 def _get_url(self, name='admin_settings_system'):
482 return {
483 'admin_settings_system': ADMIN_PREFIX + '/settings/system',
484 'admin_settings_system_update': ADMIN_PREFIX + '/settings/system/updates',
485 }[name]
486
487 def test_forbidden_when_normal_user(self, autologin_regular_user):
488 self.app.get(self._get_url(), status=403)
489
490 def test_system_info_page(self, autologin_user):
491 response = self.app.get(self._get_url())
492 response.mustcontain('RhodeCode Community Edition, version {}'.format(
493 rhodecode.__version__))
494
495 def test_system_update_new_version(self, autologin_user):
496 update_data = {
497 'versions': [
498 {
499 'version': '100.3.1415926535',
500 'general': 'The latest version we are ever going to ship'
501 },
502 {
503 'version': '0.0.0',
504 'general': 'The first version we ever shipped'
505 }
506 ]
507 }
508 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
509 response = self.app.get(self._get_url('admin_settings_system_update'))
510 response.mustcontain('A <b>new version</b> is available')
511
512 def test_system_update_nothing_new(self, autologin_user):
513 update_data = {
514 'versions': [
515 {
516 'version': '0.0.0',
517 'general': 'The first version we ever shipped'
518 }
519 ]
520 }
521 with mock.patch(UPDATE_DATA_QUALNAME, return_value=update_data):
522 response = self.app.get(self._get_url('admin_settings_system_update'))
523 response.mustcontain(
524 'You already have the <b>latest</b> stable version.')
525
526 def test_system_update_bad_response(self, autologin_user):
527 with mock.patch(UPDATE_DATA_QUALNAME, side_effect=ValueError('foo')):
528 response = self.app.get(self._get_url('admin_settings_system_update'))
529 response.mustcontain(
530 'Bad data sent from update server')
531
532
489 @pytest.mark.usefixtures("app")
533 @pytest.mark.usefixtures("app")
490 class TestAdminSettingsIssueTracker:
534 class TestAdminSettingsIssueTracker(object):
491 RC_PREFIX = 'rhodecode_'
535 RC_PREFIX = 'rhodecode_'
492 SHORT_PATTERN_KEY = 'issuetracker_pat_'
536 SHORT_PATTERN_KEY = 'issuetracker_pat_'
493 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
537 PATTERN_KEY = RC_PREFIX + SHORT_PATTERN_KEY
494
538
495 def test_issuetracker_index(self, autologin_user):
539 def test_issuetracker_index(self, autologin_user):
496 response = self.app.get(url('admin_settings_issuetracker'))
540 response = self.app.get(url('admin_settings_issuetracker'))
497 assert response.status_code == 200
541 assert response.status_code == 200
498
542
499 def test_add_empty_issuetracker_pattern(
543 def test_add_empty_issuetracker_pattern(
500 self, request, autologin_user, csrf_token):
544 self, request, autologin_user, csrf_token):
501 post_url = url('admin_settings_issuetracker_save')
545 post_url = url('admin_settings_issuetracker_save')
502 post_data = {
546 post_data = {
503 'csrf_token': csrf_token
547 'csrf_token': csrf_token
504 }
548 }
505 self.app.post(post_url, post_data, status=302)
549 self.app.post(post_url, post_data, status=302)
506
550
507 def test_add_issuetracker_pattern(
551 def test_add_issuetracker_pattern(
508 self, request, autologin_user, csrf_token):
552 self, request, autologin_user, csrf_token):
509 pattern = 'issuetracker_pat'
553 pattern = 'issuetracker_pat'
510 another_pattern = pattern+'1'
554 another_pattern = pattern+'1'
511 post_url = url('admin_settings_issuetracker_save')
555 post_url = url('admin_settings_issuetracker_save')
512 post_data = {
556 post_data = {
513 'new_pattern_pattern_0': pattern,
557 'new_pattern_pattern_0': pattern,
514 'new_pattern_url_0': 'url',
558 'new_pattern_url_0': 'url',
515 'new_pattern_prefix_0': 'prefix',
559 'new_pattern_prefix_0': 'prefix',
516 'new_pattern_description_0': 'description',
560 'new_pattern_description_0': 'description',
517 'new_pattern_pattern_1': another_pattern,
561 'new_pattern_pattern_1': another_pattern,
518 'new_pattern_url_1': 'url1',
562 'new_pattern_url_1': 'url1',
519 'new_pattern_prefix_1': 'prefix1',
563 'new_pattern_prefix_1': 'prefix1',
520 'new_pattern_description_1': 'description1',
564 'new_pattern_description_1': 'description1',
521 'csrf_token': csrf_token
565 'csrf_token': csrf_token
522 }
566 }
523 self.app.post(post_url, post_data, status=302)
567 self.app.post(post_url, post_data, status=302)
524 settings = SettingsModel().get_all_settings()
568 settings = SettingsModel().get_all_settings()
525 self.uid = md5(pattern)
569 self.uid = md5(pattern)
526 assert settings[self.PATTERN_KEY+self.uid] == pattern
570 assert settings[self.PATTERN_KEY+self.uid] == pattern
527 self.another_uid = md5(another_pattern)
571 self.another_uid = md5(another_pattern)
528 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
572 assert settings[self.PATTERN_KEY+self.another_uid] == another_pattern
529
573
530 @request.addfinalizer
574 @request.addfinalizer
531 def cleanup():
575 def cleanup():
532 defaults = SettingsModel().get_all_settings()
576 defaults = SettingsModel().get_all_settings()
533
577
534 entries = [name for name in defaults if (
578 entries = [name for name in defaults if (
535 (self.uid in name) or (self.another_uid) in name)]
579 (self.uid in name) or (self.another_uid) in name)]
536 start = len(self.RC_PREFIX)
580 start = len(self.RC_PREFIX)
537 for del_key in entries:
581 for del_key in entries:
538 # TODO: anderson: get_by_name needs name without prefix
582 # TODO: anderson: get_by_name needs name without prefix
539 entry = SettingsModel().get_setting_by_name(del_key[start:])
583 entry = SettingsModel().get_setting_by_name(del_key[start:])
540 Session().delete(entry)
584 Session().delete(entry)
541
585
542 Session().commit()
586 Session().commit()
543
587
544 def test_edit_issuetracker_pattern(
588 def test_edit_issuetracker_pattern(
545 self, autologin_user, backend, csrf_token, request):
589 self, autologin_user, backend, csrf_token, request):
546 old_pattern = 'issuetracker_pat'
590 old_pattern = 'issuetracker_pat'
547 old_uid = md5(old_pattern)
591 old_uid = md5(old_pattern)
548 pattern = 'issuetracker_pat_new'
592 pattern = 'issuetracker_pat_new'
549 self.new_uid = md5(pattern)
593 self.new_uid = md5(pattern)
550
594
551 SettingsModel().create_or_update_setting(
595 SettingsModel().create_or_update_setting(
552 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
596 self.SHORT_PATTERN_KEY+old_uid, old_pattern, 'unicode')
553
597
554 post_url = url('admin_settings_issuetracker_save')
598 post_url = url('admin_settings_issuetracker_save')
555 post_data = {
599 post_data = {
556 'new_pattern_pattern_0': pattern,
600 'new_pattern_pattern_0': pattern,
557 'new_pattern_url_0': 'url',
601 'new_pattern_url_0': 'url',
558 'new_pattern_prefix_0': 'prefix',
602 'new_pattern_prefix_0': 'prefix',
559 'new_pattern_description_0': 'description',
603 'new_pattern_description_0': 'description',
560 'uid': old_uid,
604 'uid': old_uid,
561 'csrf_token': csrf_token
605 'csrf_token': csrf_token
562 }
606 }
563 self.app.post(post_url, post_data, status=302)
607 self.app.post(post_url, post_data, status=302)
564 settings = SettingsModel().get_all_settings()
608 settings = SettingsModel().get_all_settings()
565 assert settings[self.PATTERN_KEY+self.new_uid] == pattern
609 assert settings[self.PATTERN_KEY+self.new_uid] == pattern
566 assert self.PATTERN_KEY+old_uid not in settings
610 assert self.PATTERN_KEY+old_uid not in settings
567
611
568 @request.addfinalizer
612 @request.addfinalizer
569 def cleanup():
613 def cleanup():
570 IssueTrackerSettingsModel().delete_entries(self.new_uid)
614 IssueTrackerSettingsModel().delete_entries(self.new_uid)
571
615
572 def test_replace_issuetracker_pattern_description(
616 def test_replace_issuetracker_pattern_description(
573 self, autologin_user, csrf_token, request, settings_util):
617 self, autologin_user, csrf_token, request, settings_util):
574 prefix = 'issuetracker'
618 prefix = 'issuetracker'
575 pattern = 'issuetracker_pat'
619 pattern = 'issuetracker_pat'
576 self.uid = md5(pattern)
620 self.uid = md5(pattern)
577 pattern_key = '_'.join([prefix, 'pat', self.uid])
621 pattern_key = '_'.join([prefix, 'pat', self.uid])
578 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
622 rc_pattern_key = '_'.join(['rhodecode', pattern_key])
579 desc_key = '_'.join([prefix, 'desc', self.uid])
623 desc_key = '_'.join([prefix, 'desc', self.uid])
580 rc_desc_key = '_'.join(['rhodecode', desc_key])
624 rc_desc_key = '_'.join(['rhodecode', desc_key])
581 new_description = 'new_description'
625 new_description = 'new_description'
582
626
583 settings_util.create_rhodecode_setting(
627 settings_util.create_rhodecode_setting(
584 pattern_key, pattern, 'unicode', cleanup=False)
628 pattern_key, pattern, 'unicode', cleanup=False)
585 settings_util.create_rhodecode_setting(
629 settings_util.create_rhodecode_setting(
586 desc_key, 'old description', 'unicode', cleanup=False)
630 desc_key, 'old description', 'unicode', cleanup=False)
587
631
588 post_url = url('admin_settings_issuetracker_save')
632 post_url = url('admin_settings_issuetracker_save')
589 post_data = {
633 post_data = {
590 'new_pattern_pattern_0': pattern,
634 'new_pattern_pattern_0': pattern,
591 'new_pattern_url_0': 'url',
635 'new_pattern_url_0': 'url',
592 'new_pattern_prefix_0': 'prefix',
636 'new_pattern_prefix_0': 'prefix',
593 'new_pattern_description_0': new_description,
637 'new_pattern_description_0': new_description,
594 'uid': self.uid,
638 'uid': self.uid,
595 'csrf_token': csrf_token
639 'csrf_token': csrf_token
596 }
640 }
597 self.app.post(post_url, post_data, status=302)
641 self.app.post(post_url, post_data, status=302)
598 settings = SettingsModel().get_all_settings()
642 settings = SettingsModel().get_all_settings()
599 assert settings[rc_pattern_key] == pattern
643 assert settings[rc_pattern_key] == pattern
600 assert settings[rc_desc_key] == new_description
644 assert settings[rc_desc_key] == new_description
601
645
602 @request.addfinalizer
646 @request.addfinalizer
603 def cleanup():
647 def cleanup():
604 IssueTrackerSettingsModel().delete_entries(self.uid)
648 IssueTrackerSettingsModel().delete_entries(self.uid)
605
649
606 def test_delete_issuetracker_pattern(
650 def test_delete_issuetracker_pattern(
607 self, autologin_user, backend, csrf_token, settings_util):
651 self, autologin_user, backend, csrf_token, settings_util):
608 pattern = 'issuetracker_pat'
652 pattern = 'issuetracker_pat'
609 uid = md5(pattern)
653 uid = md5(pattern)
610 settings_util.create_rhodecode_setting(
654 settings_util.create_rhodecode_setting(
611 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
655 self.SHORT_PATTERN_KEY+uid, pattern, 'unicode', cleanup=False)
612
656
613 post_url = url('admin_issuetracker_delete')
657 post_url = url('admin_issuetracker_delete')
614 post_data = {
658 post_data = {
615 '_method': 'delete',
659 '_method': 'delete',
616 'uid': uid,
660 'uid': uid,
617 'csrf_token': csrf_token
661 'csrf_token': csrf_token
618 }
662 }
619 self.app.post(post_url, post_data, status=302)
663 self.app.post(post_url, post_data, status=302)
620 settings = SettingsModel().get_all_settings()
664 settings = SettingsModel().get_all_settings()
621 assert 'rhodecode_%s%s' % (self.SHORT_PATTERN_KEY, uid) not in settings
665 assert 'rhodecode_%s%s' % (self.SHORT_PATTERN_KEY, uid) not in settings
General Comments 0
You need to be logged in to leave comments. Login now