##// END OF EJS Templates
settings: switched system-info to pyramid view.
marcink -
r1306:48d69f2d default
parent child Browse files
Show More
@@ -0,0 +1,200 b''
1 # -*- coding: utf-8 -*-
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 #
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
7 # (only), as published by the Free Software Foundation.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
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/>.
16 #
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
21 import logging
22 import urllib2
23 import packaging.version
24
25 from pylons import tmpl_context as c
26 from pyramid.view import view_config
27
28 import rhodecode
29 from rhodecode.lib import helpers as h
30 from rhodecode.lib.auth import (LoginRequired, HasPermissionAllDecorator)
31 from rhodecode.lib.utils2 import str2bool
32 from rhodecode.lib import system_info
33 from rhodecode.lib.ext_json import json
34
35 from rhodecode.admin.views.base import AdminSettingsView
36 from rhodecode.admin.navigation import navigation_list
37 from rhodecode.model.settings import SettingsModel
38
39 log = logging.getLogger(__name__)
40
41
42 class AdminSystemInfoSettingsView(AdminSettingsView):
43
44 @staticmethod
45 def get_update_data(update_url):
46 """Return the JSON update data."""
47 ver = rhodecode.__version__
48 log.debug('Checking for upgrade on `%s` server', update_url)
49 opener = urllib2.build_opener()
50 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
51 response = opener.open(update_url)
52 response_data = response.read()
53 data = json.loads(response_data)
54
55 return data
56
57 def get_update_url(self):
58 settings = SettingsModel().get_all_settings()
59 return settings.get('rhodecode_update_url')
60
61 @LoginRequired()
62 @HasPermissionAllDecorator('hg.admin')
63 @view_config(
64 route_name='admin_settings_system', request_method='GET',
65 renderer='rhodecode:templates/admin/settings/settings.mako')
66 def settings_sessions(self):
67 _ = self.request.translate
68
69 c.active = 'system'
70 c.navlist = navigation_list(self.request)
71
72 # TODO(marcink), figure out how to allow only selected users to do this
73 c.allowed_to_snapshot = self._rhodecode_user.admin
74
75 snapshot = str2bool(self.request.params.get('snapshot'))
76
77 c.rhodecode_update_url = self.get_update_url()
78 server_info = system_info.get_system_info(self.request.environ)
79
80 for key, val in server_info.items():
81 setattr(c, key, val)
82
83 def val(name, subkey='human_value'):
84 return server_info[name][subkey]
85
86 def state(name):
87 return server_info[name]['state']
88
89 def val2(name):
90 val = server_info[name]['human_value']
91 state = server_info[name]['state']
92 return val, state
93
94 update_info_msg = _('Note: please make sure this server can '
95 'access `${url}` for the update link to work',
96 mapping=dict(url=c.rhodecode_update_url))
97 c.data_items = [
98 # update info
99 (_('Update info'), h.literal(
100 '<span class="link" id="check_for_update" >%s.</span>' % (
101 _('Check for updates')) +
102 '<br/> <span >%s.</span>' % (update_info_msg)
103 ), ''),
104
105 # RhodeCode specific
106 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
107 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
108 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
109 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
110 ('', '', ''), # spacer
111
112 # Database
113 (_('Database'), val('database')['url'], state('database')),
114 (_('Database version'), val('database')['version'], state('database')),
115 ('', '', ''), # spacer
116
117 # Platform/Python
118 (_('Platform'), val('platform')['name'], state('platform')),
119 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
120 (_('Python version'), val('python')['version'], state('python')),
121 (_('Python path'), val('python')['executable'], state('python')),
122 ('', '', ''), # spacer
123
124 # Systems stats
125 (_('CPU'), val('cpu'), state('cpu')),
126 (_('Load'), val('load')['text'], state('load')),
127 (_('Memory'), val('memory')['text'], state('memory')),
128 (_('Uptime'), val('uptime')['text'], state('uptime')),
129 ('', '', ''), # spacer
130
131 # Repo storage
132 (_('Storage location'), val('storage')['path'], state('storage')),
133 (_('Storage info'), val('storage')['text'], state('storage')),
134 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
135
136 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
137 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
138
139 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
140 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
141
142 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
143 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
144
145 (_('Search info'), val('search')['text'], state('search')),
146 (_('Search location'), val('search')['location'], state('search')),
147 ('', '', ''), # spacer
148
149 # VCS specific
150 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
151 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
152 (_('GIT'), val('git'), state('git')),
153 (_('HG'), val('hg'), state('hg')),
154 (_('SVN'), val('svn'), state('svn')),
155
156 ]
157
158 if snapshot:
159 if c.allowed_to_snapshot:
160 c.data_items.pop(0) # remove server info
161 self.request.override_renderer = 'admin/settings/settings_system_snapshot.mako'
162 else:
163 self.request.session.flash(
164 'You are not allowed to do this', queue='warning')
165 return {}
166
167 @LoginRequired()
168 @HasPermissionAllDecorator('hg.admin')
169 @view_config(
170 route_name='admin_settings_system_update', request_method='GET',
171 renderer='rhodecode:templates/admin/settings/settings_system_update.mako')
172 def settings_sessions_cleanup(self):
173 _ = self.request.translate
174
175 update_url = self.get_update_url()
176
177 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">{}</div>'.format(s)
178 try:
179 data = self.get_update_data(update_url)
180 except urllib2.URLError as e:
181 log.exception("Exception contacting upgrade server")
182 return _err('Failed to contact upgrade server: %r' % e)
183 except ValueError as e:
184 log.exception("Bad data sent from update server")
185 return _err('Bad data sent from update server')
186
187 latest = data['versions'][0]
188
189 c.update_url = update_url
190 c.latest_data = latest
191 c.latest_ver = latest['version']
192 c.cur_ver = rhodecode.__version__
193 c.should_upgrade = False
194
195 if (packaging.version.Version(c.latest_ver) >
196 packaging.version.Version(c.cur_ver)):
197 c.should_upgrade = True
198 c.important_notices = latest['general']
199
200 return {}
@@ -1,50 +1,57 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 from rhodecode.admin.navigation import NavigationRegistry
23 23 from rhodecode.config.routing import ADMIN_PREFIX
24 24 from rhodecode.lib.utils2 import str2bool
25 25
26 26
27 27 def includeme(config):
28 28 settings = config.get_settings()
29 29
30 30 # Create admin navigation registry and add it to the pyramid registry.
31 31 labs_active = str2bool(settings.get('labs_settings_active', False))
32 32 navigation_registry = NavigationRegistry(labs_active=labs_active)
33 33 config.registry.registerUtility(navigation_registry)
34 34
35 35 config.add_route(
36 36 name='admin_settings_open_source',
37 37 pattern=ADMIN_PREFIX + '/settings/open_source')
38 38 config.add_route(
39 39 name='admin_settings_vcs_svn_generate_cfg',
40 40 pattern=ADMIN_PREFIX + '/settings/vcs/svn_generate_cfg')
41 41
42 42 config.add_route(
43 name='admin_settings_system',
44 pattern=ADMIN_PREFIX + '/settings/system')
45 config.add_route(
46 name='admin_settings_system_update',
47 pattern=ADMIN_PREFIX + '/settings/system/updates')
48
49 config.add_route(
43 50 name='admin_settings_sessions',
44 51 pattern=ADMIN_PREFIX + '/settings/sessions')
45 52 config.add_route(
46 53 name='admin_settings_sessions_cleanup',
47 54 pattern=ADMIN_PREFIX + '/settings/sessions/cleanup')
48 55
49 56 # Scan module for configuration decorators.
50 57 config.scan()
@@ -1,1173 +1,1167 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Routes configuration
23 23
24 24 The more specific and detailed routes should be defined first so they
25 25 may take precedent over the more generic routes. For more information
26 26 refer to the routes manual at http://routes.groovie.org/docs/
27 27
28 28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 29 and _route_name variable which uses some of stored naming here to do redirects.
30 30 """
31 31 import os
32 32 import re
33 33 from routes import Mapper
34 34
35 35 from rhodecode.config import routing_links
36 36
37 37 # prefix for non repository related links needs to be prefixed with `/`
38 38 ADMIN_PREFIX = '/_admin'
39 39 STATIC_FILE_PREFIX = '/_static'
40 40
41 41 # Default requirements for URL parts
42 42 URL_NAME_REQUIREMENTS = {
43 43 # group name can have a slash in them, but they must not end with a slash
44 44 'group_name': r'.*?[^/]',
45 45 'repo_group_name': r'.*?[^/]',
46 46 # repo names can have a slash in them, but they must not end with a slash
47 47 'repo_name': r'.*?[^/]',
48 48 # file path eats up everything at the end
49 49 'f_path': r'.*',
50 50 # reference types
51 51 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
52 52 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
53 53 }
54 54
55 55
56 56 def add_route_requirements(route_path, requirements):
57 57 """
58 58 Adds regex requirements to pyramid routes using a mapping dict
59 59
60 60 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
61 61 '/{action}/{id:\d+}'
62 62
63 63 """
64 64 for key, regex in requirements.items():
65 65 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
66 66 return route_path
67 67
68 68
69 69 class JSRoutesMapper(Mapper):
70 70 """
71 71 Wrapper for routes.Mapper to make pyroutes compatible url definitions
72 72 """
73 73 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
74 74 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
75 75 def __init__(self, *args, **kw):
76 76 super(JSRoutesMapper, self).__init__(*args, **kw)
77 77 self._jsroutes = []
78 78
79 79 def connect(self, *args, **kw):
80 80 """
81 81 Wrapper for connect to take an extra argument jsroute=True
82 82
83 83 :param jsroute: boolean, if True will add the route to the pyroutes list
84 84 """
85 85 if kw.pop('jsroute', False):
86 86 if not self._named_route_regex.match(args[0]):
87 87 raise Exception('only named routes can be added to pyroutes')
88 88 self._jsroutes.append(args[0])
89 89
90 90 super(JSRoutesMapper, self).connect(*args, **kw)
91 91
92 92 def _extract_route_information(self, route):
93 93 """
94 94 Convert a route into tuple(name, path, args), eg:
95 95 ('user_profile', '/profile/%(username)s', ['username'])
96 96 """
97 97 routepath = route.routepath
98 98 def replace(matchobj):
99 99 if matchobj.group(1):
100 100 return "%%(%s)s" % matchobj.group(1).split(':')[0]
101 101 else:
102 102 return "%%(%s)s" % matchobj.group(2)
103 103
104 104 routepath = self._argument_prog.sub(replace, routepath)
105 105 return (
106 106 route.name,
107 107 routepath,
108 108 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
109 109 for arg in self._argument_prog.findall(route.routepath)]
110 110 )
111 111
112 112 def jsroutes(self):
113 113 """
114 114 Return a list of pyroutes.js compatible routes
115 115 """
116 116 for route_name in self._jsroutes:
117 117 yield self._extract_route_information(self._routenames[route_name])
118 118
119 119
120 120 def make_map(config):
121 121 """Create, configure and return the routes Mapper"""
122 122 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
123 123 always_scan=config['debug'])
124 124 rmap.minimization = False
125 125 rmap.explicit = False
126 126
127 127 from rhodecode.lib.utils2 import str2bool
128 128 from rhodecode.model import repo, repo_group
129 129
130 130 def check_repo(environ, match_dict):
131 131 """
132 132 check for valid repository for proper 404 handling
133 133
134 134 :param environ:
135 135 :param match_dict:
136 136 """
137 137 repo_name = match_dict.get('repo_name')
138 138
139 139 if match_dict.get('f_path'):
140 140 # fix for multiple initial slashes that causes errors
141 141 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
142 142 repo_model = repo.RepoModel()
143 143 by_name_match = repo_model.get_by_repo_name(repo_name)
144 144 # if we match quickly from database, short circuit the operation,
145 145 # and validate repo based on the type.
146 146 if by_name_match:
147 147 return True
148 148
149 149 by_id_match = repo_model.get_repo_by_id(repo_name)
150 150 if by_id_match:
151 151 repo_name = by_id_match.repo_name
152 152 match_dict['repo_name'] = repo_name
153 153 return True
154 154
155 155 return False
156 156
157 157 def check_group(environ, match_dict):
158 158 """
159 159 check for valid repository group path for proper 404 handling
160 160
161 161 :param environ:
162 162 :param match_dict:
163 163 """
164 164 repo_group_name = match_dict.get('group_name')
165 165 repo_group_model = repo_group.RepoGroupModel()
166 166 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
167 167 if by_name_match:
168 168 return True
169 169
170 170 return False
171 171
172 172 def check_user_group(environ, match_dict):
173 173 """
174 174 check for valid user group for proper 404 handling
175 175
176 176 :param environ:
177 177 :param match_dict:
178 178 """
179 179 return True
180 180
181 181 def check_int(environ, match_dict):
182 182 return match_dict.get('id').isdigit()
183 183
184 184
185 185 #==========================================================================
186 186 # CUSTOM ROUTES HERE
187 187 #==========================================================================
188 188
189 189 # MAIN PAGE
190 190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
191 191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
192 192 action='goto_switcher_data')
193 193 rmap.connect('repo_list_data', '/_repos', controller='home',
194 194 action='repo_list_data')
195 195
196 196 rmap.connect('user_autocomplete_data', '/_users', controller='home',
197 197 action='user_autocomplete_data', jsroute=True)
198 198 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
199 199 action='user_group_autocomplete_data', jsroute=True)
200 200
201 201 rmap.connect(
202 202 'user_profile', '/_profiles/{username}', controller='users',
203 203 action='user_profile')
204 204
205 205 # TODO: johbo: Static links, to be replaced by our redirection mechanism
206 206 rmap.connect('rst_help',
207 207 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
208 208 _static=True)
209 209 rmap.connect('markdown_help',
210 210 'http://daringfireball.net/projects/markdown/syntax',
211 211 _static=True)
212 212 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
213 213 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
214 214 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
215 215 # TODO: anderson - making this a static link since redirect won't play
216 216 # nice with POST requests
217 217 rmap.connect('enterprise_license_convert_from_old',
218 218 'https://rhodecode.com/u/license-upgrade',
219 219 _static=True)
220 220
221 221 routing_links.connect_redirection_links(rmap)
222 222
223 223 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
224 224 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
225 225
226 226 # ADMIN REPOSITORY ROUTES
227 227 with rmap.submapper(path_prefix=ADMIN_PREFIX,
228 228 controller='admin/repos') as m:
229 229 m.connect('repos', '/repos',
230 230 action='create', conditions={'method': ['POST']})
231 231 m.connect('repos', '/repos',
232 232 action='index', conditions={'method': ['GET']})
233 233 m.connect('new_repo', '/create_repository', jsroute=True,
234 234 action='create_repository', conditions={'method': ['GET']})
235 235 m.connect('/repos/{repo_name}',
236 236 action='update', conditions={'method': ['PUT'],
237 237 'function': check_repo},
238 238 requirements=URL_NAME_REQUIREMENTS)
239 239 m.connect('delete_repo', '/repos/{repo_name}',
240 240 action='delete', conditions={'method': ['DELETE']},
241 241 requirements=URL_NAME_REQUIREMENTS)
242 242 m.connect('repo', '/repos/{repo_name}',
243 243 action='show', conditions={'method': ['GET'],
244 244 'function': check_repo},
245 245 requirements=URL_NAME_REQUIREMENTS)
246 246
247 247 # ADMIN REPOSITORY GROUPS ROUTES
248 248 with rmap.submapper(path_prefix=ADMIN_PREFIX,
249 249 controller='admin/repo_groups') as m:
250 250 m.connect('repo_groups', '/repo_groups',
251 251 action='create', conditions={'method': ['POST']})
252 252 m.connect('repo_groups', '/repo_groups',
253 253 action='index', conditions={'method': ['GET']})
254 254 m.connect('new_repo_group', '/repo_groups/new',
255 255 action='new', conditions={'method': ['GET']})
256 256 m.connect('update_repo_group', '/repo_groups/{group_name}',
257 257 action='update', conditions={'method': ['PUT'],
258 258 'function': check_group},
259 259 requirements=URL_NAME_REQUIREMENTS)
260 260
261 261 # EXTRAS REPO GROUP ROUTES
262 262 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
263 263 action='edit',
264 264 conditions={'method': ['GET'], 'function': check_group},
265 265 requirements=URL_NAME_REQUIREMENTS)
266 266 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
267 267 action='edit',
268 268 conditions={'method': ['PUT'], 'function': check_group},
269 269 requirements=URL_NAME_REQUIREMENTS)
270 270
271 271 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
272 272 action='edit_repo_group_advanced',
273 273 conditions={'method': ['GET'], 'function': check_group},
274 274 requirements=URL_NAME_REQUIREMENTS)
275 275 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
276 276 action='edit_repo_group_advanced',
277 277 conditions={'method': ['PUT'], 'function': check_group},
278 278 requirements=URL_NAME_REQUIREMENTS)
279 279
280 280 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
281 281 action='edit_repo_group_perms',
282 282 conditions={'method': ['GET'], 'function': check_group},
283 283 requirements=URL_NAME_REQUIREMENTS)
284 284 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
285 285 action='update_perms',
286 286 conditions={'method': ['PUT'], 'function': check_group},
287 287 requirements=URL_NAME_REQUIREMENTS)
288 288
289 289 m.connect('delete_repo_group', '/repo_groups/{group_name}',
290 290 action='delete', conditions={'method': ['DELETE'],
291 291 'function': check_group},
292 292 requirements=URL_NAME_REQUIREMENTS)
293 293
294 294 # ADMIN USER ROUTES
295 295 with rmap.submapper(path_prefix=ADMIN_PREFIX,
296 296 controller='admin/users') as m:
297 297 m.connect('users', '/users',
298 298 action='create', conditions={'method': ['POST']})
299 299 m.connect('users', '/users',
300 300 action='index', conditions={'method': ['GET']})
301 301 m.connect('new_user', '/users/new',
302 302 action='new', conditions={'method': ['GET']})
303 303 m.connect('update_user', '/users/{user_id}',
304 304 action='update', conditions={'method': ['PUT']})
305 305 m.connect('delete_user', '/users/{user_id}',
306 306 action='delete', conditions={'method': ['DELETE']})
307 307 m.connect('edit_user', '/users/{user_id}/edit',
308 308 action='edit', conditions={'method': ['GET']}, jsroute=True)
309 309 m.connect('user', '/users/{user_id}',
310 310 action='show', conditions={'method': ['GET']})
311 311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
312 312 action='reset_password', conditions={'method': ['POST']})
313 313 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
314 314 action='create_personal_repo_group', conditions={'method': ['POST']})
315 315
316 316 # EXTRAS USER ROUTES
317 317 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
318 318 action='edit_advanced', conditions={'method': ['GET']})
319 319 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
320 320 action='update_advanced', conditions={'method': ['PUT']})
321 321
322 322 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
323 323 action='edit_auth_tokens', conditions={'method': ['GET']})
324 324 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
325 325 action='add_auth_token', conditions={'method': ['PUT']})
326 326 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
327 327 action='delete_auth_token', conditions={'method': ['DELETE']})
328 328
329 329 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
330 330 action='edit_global_perms', conditions={'method': ['GET']})
331 331 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
332 332 action='update_global_perms', conditions={'method': ['PUT']})
333 333
334 334 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
335 335 action='edit_perms_summary', conditions={'method': ['GET']})
336 336
337 337 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
338 338 action='edit_emails', conditions={'method': ['GET']})
339 339 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
340 340 action='add_email', conditions={'method': ['PUT']})
341 341 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
342 342 action='delete_email', conditions={'method': ['DELETE']})
343 343
344 344 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
345 345 action='edit_ips', conditions={'method': ['GET']})
346 346 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
347 347 action='add_ip', conditions={'method': ['PUT']})
348 348 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
349 349 action='delete_ip', conditions={'method': ['DELETE']})
350 350
351 351 # ADMIN USER GROUPS REST ROUTES
352 352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
353 353 controller='admin/user_groups') as m:
354 354 m.connect('users_groups', '/user_groups',
355 355 action='create', conditions={'method': ['POST']})
356 356 m.connect('users_groups', '/user_groups',
357 357 action='index', conditions={'method': ['GET']})
358 358 m.connect('new_users_group', '/user_groups/new',
359 359 action='new', conditions={'method': ['GET']})
360 360 m.connect('update_users_group', '/user_groups/{user_group_id}',
361 361 action='update', conditions={'method': ['PUT']})
362 362 m.connect('delete_users_group', '/user_groups/{user_group_id}',
363 363 action='delete', conditions={'method': ['DELETE']})
364 364 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
365 365 action='edit', conditions={'method': ['GET']},
366 366 function=check_user_group)
367 367
368 368 # EXTRAS USER GROUP ROUTES
369 369 m.connect('edit_user_group_global_perms',
370 370 '/user_groups/{user_group_id}/edit/global_permissions',
371 371 action='edit_global_perms', conditions={'method': ['GET']})
372 372 m.connect('edit_user_group_global_perms',
373 373 '/user_groups/{user_group_id}/edit/global_permissions',
374 374 action='update_global_perms', conditions={'method': ['PUT']})
375 375 m.connect('edit_user_group_perms_summary',
376 376 '/user_groups/{user_group_id}/edit/permissions_summary',
377 377 action='edit_perms_summary', conditions={'method': ['GET']})
378 378
379 379 m.connect('edit_user_group_perms',
380 380 '/user_groups/{user_group_id}/edit/permissions',
381 381 action='edit_perms', conditions={'method': ['GET']})
382 382 m.connect('edit_user_group_perms',
383 383 '/user_groups/{user_group_id}/edit/permissions',
384 384 action='update_perms', conditions={'method': ['PUT']})
385 385
386 386 m.connect('edit_user_group_advanced',
387 387 '/user_groups/{user_group_id}/edit/advanced',
388 388 action='edit_advanced', conditions={'method': ['GET']})
389 389
390 390 m.connect('edit_user_group_members',
391 391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
392 392 action='user_group_members', conditions={'method': ['GET']})
393 393
394 394 # ADMIN PERMISSIONS ROUTES
395 395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
396 396 controller='admin/permissions') as m:
397 397 m.connect('admin_permissions_application', '/permissions/application',
398 398 action='permission_application_update', conditions={'method': ['POST']})
399 399 m.connect('admin_permissions_application', '/permissions/application',
400 400 action='permission_application', conditions={'method': ['GET']})
401 401
402 402 m.connect('admin_permissions_global', '/permissions/global',
403 403 action='permission_global_update', conditions={'method': ['POST']})
404 404 m.connect('admin_permissions_global', '/permissions/global',
405 405 action='permission_global', conditions={'method': ['GET']})
406 406
407 407 m.connect('admin_permissions_object', '/permissions/object',
408 408 action='permission_objects_update', conditions={'method': ['POST']})
409 409 m.connect('admin_permissions_object', '/permissions/object',
410 410 action='permission_objects', conditions={'method': ['GET']})
411 411
412 412 m.connect('admin_permissions_ips', '/permissions/ips',
413 413 action='permission_ips', conditions={'method': ['POST']})
414 414 m.connect('admin_permissions_ips', '/permissions/ips',
415 415 action='permission_ips', conditions={'method': ['GET']})
416 416
417 417 m.connect('admin_permissions_overview', '/permissions/overview',
418 418 action='permission_perms', conditions={'method': ['GET']})
419 419
420 420 # ADMIN DEFAULTS REST ROUTES
421 421 with rmap.submapper(path_prefix=ADMIN_PREFIX,
422 422 controller='admin/defaults') as m:
423 423 m.connect('admin_defaults_repositories', '/defaults/repositories',
424 424 action='update_repository_defaults', conditions={'method': ['POST']})
425 425 m.connect('admin_defaults_repositories', '/defaults/repositories',
426 426 action='index', conditions={'method': ['GET']})
427 427
428 428 # ADMIN DEBUG STYLE ROUTES
429 429 if str2bool(config.get('debug_style')):
430 430 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
431 431 controller='debug_style') as m:
432 432 m.connect('debug_style_home', '',
433 433 action='index', conditions={'method': ['GET']})
434 434 m.connect('debug_style_template', '/t/{t_path}',
435 435 action='template', conditions={'method': ['GET']})
436 436
437 437 # ADMIN SETTINGS ROUTES
438 438 with rmap.submapper(path_prefix=ADMIN_PREFIX,
439 439 controller='admin/settings') as m:
440 440
441 441 # default
442 442 m.connect('admin_settings', '/settings',
443 443 action='settings_global_update',
444 444 conditions={'method': ['POST']})
445 445 m.connect('admin_settings', '/settings',
446 446 action='settings_global', conditions={'method': ['GET']})
447 447
448 448 m.connect('admin_settings_vcs', '/settings/vcs',
449 449 action='settings_vcs_update',
450 450 conditions={'method': ['POST']})
451 451 m.connect('admin_settings_vcs', '/settings/vcs',
452 452 action='settings_vcs',
453 453 conditions={'method': ['GET']})
454 454 m.connect('admin_settings_vcs', '/settings/vcs',
455 455 action='delete_svn_pattern',
456 456 conditions={'method': ['DELETE']})
457 457
458 458 m.connect('admin_settings_mapping', '/settings/mapping',
459 459 action='settings_mapping_update',
460 460 conditions={'method': ['POST']})
461 461 m.connect('admin_settings_mapping', '/settings/mapping',
462 462 action='settings_mapping', conditions={'method': ['GET']})
463 463
464 464 m.connect('admin_settings_global', '/settings/global',
465 465 action='settings_global_update',
466 466 conditions={'method': ['POST']})
467 467 m.connect('admin_settings_global', '/settings/global',
468 468 action='settings_global', conditions={'method': ['GET']})
469 469
470 470 m.connect('admin_settings_visual', '/settings/visual',
471 471 action='settings_visual_update',
472 472 conditions={'method': ['POST']})
473 473 m.connect('admin_settings_visual', '/settings/visual',
474 474 action='settings_visual', conditions={'method': ['GET']})
475 475
476 476 m.connect('admin_settings_issuetracker',
477 477 '/settings/issue-tracker', action='settings_issuetracker',
478 478 conditions={'method': ['GET']})
479 479 m.connect('admin_settings_issuetracker_save',
480 480 '/settings/issue-tracker/save',
481 481 action='settings_issuetracker_save',
482 482 conditions={'method': ['POST']})
483 483 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
484 484 action='settings_issuetracker_test',
485 485 conditions={'method': ['POST']})
486 486 m.connect('admin_issuetracker_delete',
487 487 '/settings/issue-tracker/delete',
488 488 action='settings_issuetracker_delete',
489 489 conditions={'method': ['DELETE']})
490 490
491 491 m.connect('admin_settings_email', '/settings/email',
492 492 action='settings_email_update',
493 493 conditions={'method': ['POST']})
494 494 m.connect('admin_settings_email', '/settings/email',
495 495 action='settings_email', conditions={'method': ['GET']})
496 496
497 497 m.connect('admin_settings_hooks', '/settings/hooks',
498 498 action='settings_hooks_update',
499 499 conditions={'method': ['POST', 'DELETE']})
500 500 m.connect('admin_settings_hooks', '/settings/hooks',
501 501 action='settings_hooks', conditions={'method': ['GET']})
502 502
503 503 m.connect('admin_settings_search', '/settings/search',
504 504 action='settings_search', conditions={'method': ['GET']})
505 505
506 m.connect('admin_settings_system', '/settings/system',
507 action='settings_system', conditions={'method': ['GET']})
508
509 m.connect('admin_settings_system_update', '/settings/system/updates',
510 action='settings_system_update', conditions={'method': ['GET']})
511
512 506 m.connect('admin_settings_supervisor', '/settings/supervisor',
513 507 action='settings_supervisor', conditions={'method': ['GET']})
514 508 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
515 509 action='settings_supervisor_log', conditions={'method': ['GET']})
516 510
517 511 m.connect('admin_settings_labs', '/settings/labs',
518 512 action='settings_labs_update',
519 513 conditions={'method': ['POST']})
520 514 m.connect('admin_settings_labs', '/settings/labs',
521 515 action='settings_labs', conditions={'method': ['GET']})
522 516
523 517 # ADMIN MY ACCOUNT
524 518 with rmap.submapper(path_prefix=ADMIN_PREFIX,
525 519 controller='admin/my_account') as m:
526 520
527 521 m.connect('my_account', '/my_account',
528 522 action='my_account', conditions={'method': ['GET']})
529 523 m.connect('my_account_edit', '/my_account/edit',
530 524 action='my_account_edit', conditions={'method': ['GET']})
531 525 m.connect('my_account', '/my_account',
532 526 action='my_account_update', conditions={'method': ['POST']})
533 527
534 528 m.connect('my_account_password', '/my_account/password',
535 529 action='my_account_password', conditions={'method': ['GET', 'POST']})
536 530
537 531 m.connect('my_account_repos', '/my_account/repos',
538 532 action='my_account_repos', conditions={'method': ['GET']})
539 533
540 534 m.connect('my_account_watched', '/my_account/watched',
541 535 action='my_account_watched', conditions={'method': ['GET']})
542 536
543 537 m.connect('my_account_pullrequests', '/my_account/pull_requests',
544 538 action='my_account_pullrequests', conditions={'method': ['GET']})
545 539
546 540 m.connect('my_account_perms', '/my_account/perms',
547 541 action='my_account_perms', conditions={'method': ['GET']})
548 542
549 543 m.connect('my_account_emails', '/my_account/emails',
550 544 action='my_account_emails', conditions={'method': ['GET']})
551 545 m.connect('my_account_emails', '/my_account/emails',
552 546 action='my_account_emails_add', conditions={'method': ['POST']})
553 547 m.connect('my_account_emails', '/my_account/emails',
554 548 action='my_account_emails_delete', conditions={'method': ['DELETE']})
555 549
556 550 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
557 551 action='my_account_auth_tokens', conditions={'method': ['GET']})
558 552 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
559 553 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
560 554 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
561 555 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
562 556 m.connect('my_account_notifications', '/my_account/notifications',
563 557 action='my_notifications',
564 558 conditions={'method': ['GET']})
565 559 m.connect('my_account_notifications_toggle_visibility',
566 560 '/my_account/toggle_visibility',
567 561 action='my_notifications_toggle_visibility',
568 562 conditions={'method': ['POST']})
569 563 m.connect('my_account_notifications_test_channelstream',
570 564 '/my_account/test_channelstream',
571 565 action='my_account_notifications_test_channelstream',
572 566 conditions={'method': ['POST']})
573 567
574 568 # NOTIFICATION REST ROUTES
575 569 with rmap.submapper(path_prefix=ADMIN_PREFIX,
576 570 controller='admin/notifications') as m:
577 571 m.connect('notifications', '/notifications',
578 572 action='index', conditions={'method': ['GET']})
579 573 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
580 574 action='mark_all_read', conditions={'method': ['POST']})
581 575 m.connect('/notifications/{notification_id}',
582 576 action='update', conditions={'method': ['PUT']})
583 577 m.connect('/notifications/{notification_id}',
584 578 action='delete', conditions={'method': ['DELETE']})
585 579 m.connect('notification', '/notifications/{notification_id}',
586 580 action='show', conditions={'method': ['GET']})
587 581
588 582 # ADMIN GIST
589 583 with rmap.submapper(path_prefix=ADMIN_PREFIX,
590 584 controller='admin/gists') as m:
591 585 m.connect('gists', '/gists',
592 586 action='create', conditions={'method': ['POST']})
593 587 m.connect('gists', '/gists', jsroute=True,
594 588 action='index', conditions={'method': ['GET']})
595 589 m.connect('new_gist', '/gists/new', jsroute=True,
596 590 action='new', conditions={'method': ['GET']})
597 591
598 592 m.connect('/gists/{gist_id}',
599 593 action='delete', conditions={'method': ['DELETE']})
600 594 m.connect('edit_gist', '/gists/{gist_id}/edit',
601 595 action='edit_form', conditions={'method': ['GET']})
602 596 m.connect('edit_gist', '/gists/{gist_id}/edit',
603 597 action='edit', conditions={'method': ['POST']})
604 598 m.connect(
605 599 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
606 600 action='check_revision', conditions={'method': ['GET']})
607 601
608 602 m.connect('gist', '/gists/{gist_id}',
609 603 action='show', conditions={'method': ['GET']})
610 604 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
611 605 revision='tip',
612 606 action='show', conditions={'method': ['GET']})
613 607 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
614 608 revision='tip',
615 609 action='show', conditions={'method': ['GET']})
616 610 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
617 611 revision='tip',
618 612 action='show', conditions={'method': ['GET']},
619 613 requirements=URL_NAME_REQUIREMENTS)
620 614
621 615 # ADMIN MAIN PAGES
622 616 with rmap.submapper(path_prefix=ADMIN_PREFIX,
623 617 controller='admin/admin') as m:
624 618 m.connect('admin_home', '', action='index')
625 619 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
626 620 action='add_repo')
627 621 m.connect(
628 622 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
629 623 action='pull_requests')
630 624 m.connect(
631 625 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
632 626 action='pull_requests')
633 627 m.connect(
634 628 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
635 629 action='pull_requests')
636 630
637 631 # USER JOURNAL
638 632 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
639 633 controller='journal', action='index')
640 634 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
641 635 controller='journal', action='journal_rss')
642 636 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
643 637 controller='journal', action='journal_atom')
644 638
645 639 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
646 640 controller='journal', action='public_journal')
647 641
648 642 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
649 643 controller='journal', action='public_journal_rss')
650 644
651 645 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
652 646 controller='journal', action='public_journal_rss')
653 647
654 648 rmap.connect('public_journal_atom',
655 649 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
656 650 action='public_journal_atom')
657 651
658 652 rmap.connect('public_journal_atom_old',
659 653 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
660 654 action='public_journal_atom')
661 655
662 656 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
663 657 controller='journal', action='toggle_following', jsroute=True,
664 658 conditions={'method': ['POST']})
665 659
666 660 # FULL TEXT SEARCH
667 661 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
668 662 controller='search')
669 663 rmap.connect('search_repo_home', '/{repo_name}/search',
670 664 controller='search',
671 665 action='index',
672 666 conditions={'function': check_repo},
673 667 requirements=URL_NAME_REQUIREMENTS)
674 668
675 669 # FEEDS
676 670 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
677 671 controller='feed', action='rss',
678 672 conditions={'function': check_repo},
679 673 requirements=URL_NAME_REQUIREMENTS)
680 674
681 675 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
682 676 controller='feed', action='atom',
683 677 conditions={'function': check_repo},
684 678 requirements=URL_NAME_REQUIREMENTS)
685 679
686 680 #==========================================================================
687 681 # REPOSITORY ROUTES
688 682 #==========================================================================
689 683
690 684 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
691 685 controller='admin/repos', action='repo_creating',
692 686 requirements=URL_NAME_REQUIREMENTS)
693 687 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
694 688 controller='admin/repos', action='repo_check',
695 689 requirements=URL_NAME_REQUIREMENTS)
696 690
697 691 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
698 692 controller='summary', action='repo_stats',
699 693 conditions={'function': check_repo},
700 694 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
701 695
702 696 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
703 697 controller='summary', action='repo_refs_data', jsroute=True,
704 698 requirements=URL_NAME_REQUIREMENTS)
705 699 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
706 700 controller='summary', action='repo_refs_changelog_data',
707 701 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
708 702 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
709 703 controller='summary', action='repo_default_reviewers_data',
710 704 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
711 705
712 706 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
713 707 controller='changeset', revision='tip', jsroute=True,
714 708 conditions={'function': check_repo},
715 709 requirements=URL_NAME_REQUIREMENTS)
716 710 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
717 711 controller='changeset', revision='tip', action='changeset_children',
718 712 conditions={'function': check_repo},
719 713 requirements=URL_NAME_REQUIREMENTS)
720 714 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
721 715 controller='changeset', revision='tip', action='changeset_parents',
722 716 conditions={'function': check_repo},
723 717 requirements=URL_NAME_REQUIREMENTS)
724 718
725 719 # repo edit options
726 720 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
727 721 controller='admin/repos', action='edit',
728 722 conditions={'method': ['GET'], 'function': check_repo},
729 723 requirements=URL_NAME_REQUIREMENTS)
730 724
731 725 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
732 726 jsroute=True,
733 727 controller='admin/repos', action='edit_permissions',
734 728 conditions={'method': ['GET'], 'function': check_repo},
735 729 requirements=URL_NAME_REQUIREMENTS)
736 730 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
737 731 controller='admin/repos', action='edit_permissions_update',
738 732 conditions={'method': ['PUT'], 'function': check_repo},
739 733 requirements=URL_NAME_REQUIREMENTS)
740 734
741 735 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
742 736 controller='admin/repos', action='edit_fields',
743 737 conditions={'method': ['GET'], 'function': check_repo},
744 738 requirements=URL_NAME_REQUIREMENTS)
745 739 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
746 740 controller='admin/repos', action='create_repo_field',
747 741 conditions={'method': ['PUT'], 'function': check_repo},
748 742 requirements=URL_NAME_REQUIREMENTS)
749 743 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
750 744 controller='admin/repos', action='delete_repo_field',
751 745 conditions={'method': ['DELETE'], 'function': check_repo},
752 746 requirements=URL_NAME_REQUIREMENTS)
753 747
754 748 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
755 749 controller='admin/repos', action='edit_advanced',
756 750 conditions={'method': ['GET'], 'function': check_repo},
757 751 requirements=URL_NAME_REQUIREMENTS)
758 752
759 753 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
760 754 controller='admin/repos', action='edit_advanced_locking',
761 755 conditions={'method': ['PUT'], 'function': check_repo},
762 756 requirements=URL_NAME_REQUIREMENTS)
763 757 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
764 758 controller='admin/repos', action='toggle_locking',
765 759 conditions={'method': ['GET'], 'function': check_repo},
766 760 requirements=URL_NAME_REQUIREMENTS)
767 761
768 762 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
769 763 controller='admin/repos', action='edit_advanced_journal',
770 764 conditions={'method': ['PUT'], 'function': check_repo},
771 765 requirements=URL_NAME_REQUIREMENTS)
772 766
773 767 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
774 768 controller='admin/repos', action='edit_advanced_fork',
775 769 conditions={'method': ['PUT'], 'function': check_repo},
776 770 requirements=URL_NAME_REQUIREMENTS)
777 771
778 772 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
779 773 controller='admin/repos', action='edit_caches_form',
780 774 conditions={'method': ['GET'], 'function': check_repo},
781 775 requirements=URL_NAME_REQUIREMENTS)
782 776 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
783 777 controller='admin/repos', action='edit_caches',
784 778 conditions={'method': ['PUT'], 'function': check_repo},
785 779 requirements=URL_NAME_REQUIREMENTS)
786 780
787 781 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
788 782 controller='admin/repos', action='edit_remote_form',
789 783 conditions={'method': ['GET'], 'function': check_repo},
790 784 requirements=URL_NAME_REQUIREMENTS)
791 785 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
792 786 controller='admin/repos', action='edit_remote',
793 787 conditions={'method': ['PUT'], 'function': check_repo},
794 788 requirements=URL_NAME_REQUIREMENTS)
795 789
796 790 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
797 791 controller='admin/repos', action='edit_statistics_form',
798 792 conditions={'method': ['GET'], 'function': check_repo},
799 793 requirements=URL_NAME_REQUIREMENTS)
800 794 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
801 795 controller='admin/repos', action='edit_statistics',
802 796 conditions={'method': ['PUT'], 'function': check_repo},
803 797 requirements=URL_NAME_REQUIREMENTS)
804 798 rmap.connect('repo_settings_issuetracker',
805 799 '/{repo_name}/settings/issue-tracker',
806 800 controller='admin/repos', action='repo_issuetracker',
807 801 conditions={'method': ['GET'], 'function': check_repo},
808 802 requirements=URL_NAME_REQUIREMENTS)
809 803 rmap.connect('repo_issuetracker_test',
810 804 '/{repo_name}/settings/issue-tracker/test',
811 805 controller='admin/repos', action='repo_issuetracker_test',
812 806 conditions={'method': ['POST'], 'function': check_repo},
813 807 requirements=URL_NAME_REQUIREMENTS)
814 808 rmap.connect('repo_issuetracker_delete',
815 809 '/{repo_name}/settings/issue-tracker/delete',
816 810 controller='admin/repos', action='repo_issuetracker_delete',
817 811 conditions={'method': ['DELETE'], 'function': check_repo},
818 812 requirements=URL_NAME_REQUIREMENTS)
819 813 rmap.connect('repo_issuetracker_save',
820 814 '/{repo_name}/settings/issue-tracker/save',
821 815 controller='admin/repos', action='repo_issuetracker_save',
822 816 conditions={'method': ['POST'], 'function': check_repo},
823 817 requirements=URL_NAME_REQUIREMENTS)
824 818 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
825 819 controller='admin/repos', action='repo_settings_vcs_update',
826 820 conditions={'method': ['POST'], 'function': check_repo},
827 821 requirements=URL_NAME_REQUIREMENTS)
828 822 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
829 823 controller='admin/repos', action='repo_settings_vcs',
830 824 conditions={'method': ['GET'], 'function': check_repo},
831 825 requirements=URL_NAME_REQUIREMENTS)
832 826 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
833 827 controller='admin/repos', action='repo_delete_svn_pattern',
834 828 conditions={'method': ['DELETE'], 'function': check_repo},
835 829 requirements=URL_NAME_REQUIREMENTS)
836 830 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
837 831 controller='admin/repos', action='repo_settings_pullrequest',
838 832 conditions={'method': ['GET', 'POST'], 'function': check_repo},
839 833 requirements=URL_NAME_REQUIREMENTS)
840 834
841 835 # still working url for backward compat.
842 836 rmap.connect('raw_changeset_home_depraced',
843 837 '/{repo_name}/raw-changeset/{revision}',
844 838 controller='changeset', action='changeset_raw',
845 839 revision='tip', conditions={'function': check_repo},
846 840 requirements=URL_NAME_REQUIREMENTS)
847 841
848 842 # new URLs
849 843 rmap.connect('changeset_raw_home',
850 844 '/{repo_name}/changeset-diff/{revision}',
851 845 controller='changeset', action='changeset_raw',
852 846 revision='tip', conditions={'function': check_repo},
853 847 requirements=URL_NAME_REQUIREMENTS)
854 848
855 849 rmap.connect('changeset_patch_home',
856 850 '/{repo_name}/changeset-patch/{revision}',
857 851 controller='changeset', action='changeset_patch',
858 852 revision='tip', conditions={'function': check_repo},
859 853 requirements=URL_NAME_REQUIREMENTS)
860 854
861 855 rmap.connect('changeset_download_home',
862 856 '/{repo_name}/changeset-download/{revision}',
863 857 controller='changeset', action='changeset_download',
864 858 revision='tip', conditions={'function': check_repo},
865 859 requirements=URL_NAME_REQUIREMENTS)
866 860
867 861 rmap.connect('changeset_comment',
868 862 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
869 863 controller='changeset', revision='tip', action='comment',
870 864 conditions={'function': check_repo},
871 865 requirements=URL_NAME_REQUIREMENTS)
872 866
873 867 rmap.connect('changeset_comment_preview',
874 868 '/{repo_name}/changeset/comment/preview', jsroute=True,
875 869 controller='changeset', action='preview_comment',
876 870 conditions={'function': check_repo, 'method': ['POST']},
877 871 requirements=URL_NAME_REQUIREMENTS)
878 872
879 873 rmap.connect('changeset_comment_delete',
880 874 '/{repo_name}/changeset/comment/{comment_id}/delete',
881 875 controller='changeset', action='delete_comment',
882 876 conditions={'function': check_repo, 'method': ['DELETE']},
883 877 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
884 878
885 879 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
886 880 controller='changeset', action='changeset_info',
887 881 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
888 882
889 883 rmap.connect('compare_home',
890 884 '/{repo_name}/compare',
891 885 controller='compare', action='index',
892 886 conditions={'function': check_repo},
893 887 requirements=URL_NAME_REQUIREMENTS)
894 888
895 889 rmap.connect('compare_url',
896 890 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
897 891 controller='compare', action='compare',
898 892 conditions={'function': check_repo},
899 893 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
900 894
901 895 rmap.connect('pullrequest_home',
902 896 '/{repo_name}/pull-request/new', controller='pullrequests',
903 897 action='index', conditions={'function': check_repo,
904 898 'method': ['GET']},
905 899 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
906 900
907 901 rmap.connect('pullrequest',
908 902 '/{repo_name}/pull-request/new', controller='pullrequests',
909 903 action='create', conditions={'function': check_repo,
910 904 'method': ['POST']},
911 905 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
912 906
913 907 rmap.connect('pullrequest_repo_refs',
914 908 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
915 909 controller='pullrequests',
916 910 action='get_repo_refs',
917 911 conditions={'function': check_repo, 'method': ['GET']},
918 912 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
919 913
920 914 rmap.connect('pullrequest_repo_destinations',
921 915 '/{repo_name}/pull-request/repo-destinations',
922 916 controller='pullrequests',
923 917 action='get_repo_destinations',
924 918 conditions={'function': check_repo, 'method': ['GET']},
925 919 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
926 920
927 921 rmap.connect('pullrequest_show',
928 922 '/{repo_name}/pull-request/{pull_request_id}',
929 923 controller='pullrequests',
930 924 action='show', conditions={'function': check_repo,
931 925 'method': ['GET']},
932 926 requirements=URL_NAME_REQUIREMENTS)
933 927
934 928 rmap.connect('pullrequest_update',
935 929 '/{repo_name}/pull-request/{pull_request_id}',
936 930 controller='pullrequests',
937 931 action='update', conditions={'function': check_repo,
938 932 'method': ['PUT']},
939 933 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
940 934
941 935 rmap.connect('pullrequest_merge',
942 936 '/{repo_name}/pull-request/{pull_request_id}',
943 937 controller='pullrequests',
944 938 action='merge', conditions={'function': check_repo,
945 939 'method': ['POST']},
946 940 requirements=URL_NAME_REQUIREMENTS)
947 941
948 942 rmap.connect('pullrequest_delete',
949 943 '/{repo_name}/pull-request/{pull_request_id}',
950 944 controller='pullrequests',
951 945 action='delete', conditions={'function': check_repo,
952 946 'method': ['DELETE']},
953 947 requirements=URL_NAME_REQUIREMENTS)
954 948
955 949 rmap.connect('pullrequest_show_all',
956 950 '/{repo_name}/pull-request',
957 951 controller='pullrequests',
958 952 action='show_all', conditions={'function': check_repo,
959 953 'method': ['GET']},
960 954 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
961 955
962 956 rmap.connect('pullrequest_comment',
963 957 '/{repo_name}/pull-request-comment/{pull_request_id}',
964 958 controller='pullrequests',
965 959 action='comment', conditions={'function': check_repo,
966 960 'method': ['POST']},
967 961 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
968 962
969 963 rmap.connect('pullrequest_comment_delete',
970 964 '/{repo_name}/pull-request-comment/{comment_id}/delete',
971 965 controller='pullrequests', action='delete_comment',
972 966 conditions={'function': check_repo, 'method': ['DELETE']},
973 967 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
974 968
975 969 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
976 970 controller='summary', conditions={'function': check_repo},
977 971 requirements=URL_NAME_REQUIREMENTS)
978 972
979 973 rmap.connect('branches_home', '/{repo_name}/branches',
980 974 controller='branches', conditions={'function': check_repo},
981 975 requirements=URL_NAME_REQUIREMENTS)
982 976
983 977 rmap.connect('tags_home', '/{repo_name}/tags',
984 978 controller='tags', conditions={'function': check_repo},
985 979 requirements=URL_NAME_REQUIREMENTS)
986 980
987 981 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
988 982 controller='bookmarks', conditions={'function': check_repo},
989 983 requirements=URL_NAME_REQUIREMENTS)
990 984
991 985 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
992 986 controller='changelog', conditions={'function': check_repo},
993 987 requirements=URL_NAME_REQUIREMENTS)
994 988
995 989 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
996 990 controller='changelog', action='changelog_summary',
997 991 conditions={'function': check_repo},
998 992 requirements=URL_NAME_REQUIREMENTS)
999 993
1000 994 rmap.connect('changelog_file_home',
1001 995 '/{repo_name}/changelog/{revision}/{f_path}',
1002 996 controller='changelog', f_path=None,
1003 997 conditions={'function': check_repo},
1004 998 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1005 999
1006 1000 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1007 1001 controller='changelog', action='changelog_details',
1008 1002 conditions={'function': check_repo},
1009 1003 requirements=URL_NAME_REQUIREMENTS)
1010 1004
1011 1005 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1012 1006 controller='files', revision='tip', f_path='',
1013 1007 conditions={'function': check_repo},
1014 1008 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1015 1009
1016 1010 rmap.connect('files_home_simple_catchrev',
1017 1011 '/{repo_name}/files/{revision}',
1018 1012 controller='files', revision='tip', f_path='',
1019 1013 conditions={'function': check_repo},
1020 1014 requirements=URL_NAME_REQUIREMENTS)
1021 1015
1022 1016 rmap.connect('files_home_simple_catchall',
1023 1017 '/{repo_name}/files',
1024 1018 controller='files', revision='tip', f_path='',
1025 1019 conditions={'function': check_repo},
1026 1020 requirements=URL_NAME_REQUIREMENTS)
1027 1021
1028 1022 rmap.connect('files_history_home',
1029 1023 '/{repo_name}/history/{revision}/{f_path}',
1030 1024 controller='files', action='history', revision='tip', f_path='',
1031 1025 conditions={'function': check_repo},
1032 1026 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1033 1027
1034 1028 rmap.connect('files_authors_home',
1035 1029 '/{repo_name}/authors/{revision}/{f_path}',
1036 1030 controller='files', action='authors', revision='tip', f_path='',
1037 1031 conditions={'function': check_repo},
1038 1032 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1039 1033
1040 1034 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1041 1035 controller='files', action='diff', f_path='',
1042 1036 conditions={'function': check_repo},
1043 1037 requirements=URL_NAME_REQUIREMENTS)
1044 1038
1045 1039 rmap.connect('files_diff_2way_home',
1046 1040 '/{repo_name}/diff-2way/{f_path}',
1047 1041 controller='files', action='diff_2way', f_path='',
1048 1042 conditions={'function': check_repo},
1049 1043 requirements=URL_NAME_REQUIREMENTS)
1050 1044
1051 1045 rmap.connect('files_rawfile_home',
1052 1046 '/{repo_name}/rawfile/{revision}/{f_path}',
1053 1047 controller='files', action='rawfile', revision='tip',
1054 1048 f_path='', conditions={'function': check_repo},
1055 1049 requirements=URL_NAME_REQUIREMENTS)
1056 1050
1057 1051 rmap.connect('files_raw_home',
1058 1052 '/{repo_name}/raw/{revision}/{f_path}',
1059 1053 controller='files', action='raw', revision='tip', f_path='',
1060 1054 conditions={'function': check_repo},
1061 1055 requirements=URL_NAME_REQUIREMENTS)
1062 1056
1063 1057 rmap.connect('files_render_home',
1064 1058 '/{repo_name}/render/{revision}/{f_path}',
1065 1059 controller='files', action='index', revision='tip', f_path='',
1066 1060 rendered=True, conditions={'function': check_repo},
1067 1061 requirements=URL_NAME_REQUIREMENTS)
1068 1062
1069 1063 rmap.connect('files_annotate_home',
1070 1064 '/{repo_name}/annotate/{revision}/{f_path}',
1071 1065 controller='files', action='index', revision='tip',
1072 1066 f_path='', annotate=True, conditions={'function': check_repo},
1073 1067 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1074 1068
1075 1069 rmap.connect('files_edit',
1076 1070 '/{repo_name}/edit/{revision}/{f_path}',
1077 1071 controller='files', action='edit', revision='tip',
1078 1072 f_path='',
1079 1073 conditions={'function': check_repo, 'method': ['POST']},
1080 1074 requirements=URL_NAME_REQUIREMENTS)
1081 1075
1082 1076 rmap.connect('files_edit_home',
1083 1077 '/{repo_name}/edit/{revision}/{f_path}',
1084 1078 controller='files', action='edit_home', revision='tip',
1085 1079 f_path='', conditions={'function': check_repo},
1086 1080 requirements=URL_NAME_REQUIREMENTS)
1087 1081
1088 1082 rmap.connect('files_add',
1089 1083 '/{repo_name}/add/{revision}/{f_path}',
1090 1084 controller='files', action='add', revision='tip',
1091 1085 f_path='',
1092 1086 conditions={'function': check_repo, 'method': ['POST']},
1093 1087 requirements=URL_NAME_REQUIREMENTS)
1094 1088
1095 1089 rmap.connect('files_add_home',
1096 1090 '/{repo_name}/add/{revision}/{f_path}',
1097 1091 controller='files', action='add_home', revision='tip',
1098 1092 f_path='', conditions={'function': check_repo},
1099 1093 requirements=URL_NAME_REQUIREMENTS)
1100 1094
1101 1095 rmap.connect('files_delete',
1102 1096 '/{repo_name}/delete/{revision}/{f_path}',
1103 1097 controller='files', action='delete', revision='tip',
1104 1098 f_path='',
1105 1099 conditions={'function': check_repo, 'method': ['POST']},
1106 1100 requirements=URL_NAME_REQUIREMENTS)
1107 1101
1108 1102 rmap.connect('files_delete_home',
1109 1103 '/{repo_name}/delete/{revision}/{f_path}',
1110 1104 controller='files', action='delete_home', revision='tip',
1111 1105 f_path='', conditions={'function': check_repo},
1112 1106 requirements=URL_NAME_REQUIREMENTS)
1113 1107
1114 1108 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1115 1109 controller='files', action='archivefile',
1116 1110 conditions={'function': check_repo},
1117 1111 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1118 1112
1119 1113 rmap.connect('files_nodelist_home',
1120 1114 '/{repo_name}/nodelist/{revision}/{f_path}',
1121 1115 controller='files', action='nodelist',
1122 1116 conditions={'function': check_repo},
1123 1117 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1124 1118
1125 1119 rmap.connect('files_nodetree_full',
1126 1120 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1127 1121 controller='files', action='nodetree_full',
1128 1122 conditions={'function': check_repo},
1129 1123 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1130 1124
1131 1125 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1132 1126 controller='forks', action='fork_create',
1133 1127 conditions={'function': check_repo, 'method': ['POST']},
1134 1128 requirements=URL_NAME_REQUIREMENTS)
1135 1129
1136 1130 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1137 1131 controller='forks', action='fork',
1138 1132 conditions={'function': check_repo},
1139 1133 requirements=URL_NAME_REQUIREMENTS)
1140 1134
1141 1135 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1142 1136 controller='forks', action='forks',
1143 1137 conditions={'function': check_repo},
1144 1138 requirements=URL_NAME_REQUIREMENTS)
1145 1139
1146 1140 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1147 1141 controller='followers', action='followers',
1148 1142 conditions={'function': check_repo},
1149 1143 requirements=URL_NAME_REQUIREMENTS)
1150 1144
1151 1145 # must be here for proper group/repo catching pattern
1152 1146 _connect_with_slash(
1153 1147 rmap, 'repo_group_home', '/{group_name}',
1154 1148 controller='home', action='index_repo_group',
1155 1149 conditions={'function': check_group},
1156 1150 requirements=URL_NAME_REQUIREMENTS)
1157 1151
1158 1152 # catch all, at the end
1159 1153 _connect_with_slash(
1160 1154 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1161 1155 controller='summary', action='index',
1162 1156 conditions={'function': check_repo},
1163 1157 requirements=URL_NAME_REQUIREMENTS)
1164 1158
1165 1159 return rmap
1166 1160
1167 1161
1168 1162 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1169 1163 """
1170 1164 Connect a route with an optional trailing slash in `path`.
1171 1165 """
1172 1166 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1173 1167 mapper.connect(name, path, *args, **kwargs)
@@ -1,842 +1,692 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21
22 22 """
23 23 settings controller for rhodecode admin
24 24 """
25 25
26 26 import collections
27 27 import logging
28 import urllib2
29 28
30 29 import datetime
31 30 import formencode
32 31 from formencode import htmlfill
33 import packaging.version
34 32 from pylons import request, tmpl_context as c, url, config
35 33 from pylons.controllers.util import redirect
36 from pylons.i18n.translation import _, lazy_ugettext
34 from pylons.i18n.translation import _
37 35 from pyramid.threadlocal import get_current_registry
38 36 from webob.exc import HTTPBadRequest
39 37
40 38 import rhodecode
41 39 from rhodecode.admin.navigation import navigation_list
42 40 from rhodecode.lib import auth
43 41 from rhodecode.lib import helpers as h
44 42 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
45 43 from rhodecode.lib.base import BaseController, render
46 44 from rhodecode.lib.celerylib import tasks, run_task
47 45 from rhodecode.lib.utils import repo2db_mapper
48 46 from rhodecode.lib.utils2 import (
49 47 str2bool, safe_unicode, AttributeDict, safe_int)
50 48 from rhodecode.lib.compat import OrderedDict
51 from rhodecode.lib.ext_json import json
52 49 from rhodecode.lib.utils import jsonify
53 50
54 51 from rhodecode.model.db import RhodeCodeUi, Repository
55 52 from rhodecode.model.forms import ApplicationSettingsForm, \
56 53 ApplicationUiSettingsForm, ApplicationVisualisationForm, \
57 54 LabsSettingsForm, IssueTrackerPatternsForm
58 55 from rhodecode.model.repo_group import RepoGroupModel
59 56
60 57 from rhodecode.model.scm import ScmModel
61 58 from rhodecode.model.notification import EmailNotificationModel
62 59 from rhodecode.model.meta import Session
63 60 from rhodecode.model.settings import (
64 61 IssueTrackerSettingsModel, VcsSettingsModel, SettingNotFound,
65 62 SettingsModel)
66 63
67 64 from rhodecode.model.supervisor import SupervisorModel, SUPERVISOR_MASTER
68 65 from rhodecode.svn_support.config_keys import generate_config
69 66
70 67
71 68 log = logging.getLogger(__name__)
72 69
73 70
74 71 class SettingsController(BaseController):
75 72 """REST Controller styled on the Atom Publishing Protocol"""
76 73 # To properly map this controller, ensure your config/routing.py
77 74 # file has a resource setup:
78 75 # map.resource('setting', 'settings', controller='admin/settings',
79 76 # path_prefix='/admin', name_prefix='admin_')
80 77
81 78 @LoginRequired()
82 79 def __before__(self):
83 80 super(SettingsController, self).__before__()
84 81 c.labs_active = str2bool(
85 82 rhodecode.CONFIG.get('labs_settings_active', 'true'))
86 83 c.navlist = navigation_list(request)
87 84
88 85 def _get_hg_ui_settings(self):
89 86 ret = RhodeCodeUi.query().all()
90 87
91 88 if not ret:
92 89 raise Exception('Could not get application ui settings !')
93 90 settings = {}
94 91 for each in ret:
95 92 k = each.ui_key
96 93 v = each.ui_value
97 94 if k == '/':
98 95 k = 'root_path'
99 96
100 97 if k in ['push_ssl', 'publish']:
101 98 v = str2bool(v)
102 99
103 100 if k.find('.') != -1:
104 101 k = k.replace('.', '_')
105 102
106 103 if each.ui_section in ['hooks', 'extensions']:
107 104 v = each.ui_active
108 105
109 106 settings[each.ui_section + '_' + k] = v
110 107 return settings
111 108
112 109 @HasPermissionAllDecorator('hg.admin')
113 110 @auth.CSRFRequired()
114 111 @jsonify
115 112 def delete_svn_pattern(self):
116 113 if not request.is_xhr:
117 114 raise HTTPBadRequest()
118 115
119 116 delete_pattern_id = request.POST.get('delete_svn_pattern')
120 117 model = VcsSettingsModel()
121 118 try:
122 119 model.delete_global_svn_pattern(delete_pattern_id)
123 120 except SettingNotFound:
124 121 raise HTTPBadRequest()
125 122
126 123 Session().commit()
127 124 return True
128 125
129 126 @HasPermissionAllDecorator('hg.admin')
130 127 @auth.CSRFRequired()
131 128 def settings_vcs_update(self):
132 129 """POST /admin/settings: All items in the collection"""
133 130 # url('admin_settings_vcs')
134 131 c.active = 'vcs'
135 132
136 133 model = VcsSettingsModel()
137 134 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
138 135 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
139 136
140 137 # TODO: Replace with request.registry after migrating to pyramid.
141 138 pyramid_settings = get_current_registry().settings
142 139 c.svn_proxy_generate_config = pyramid_settings[generate_config]
143 140
144 141 application_form = ApplicationUiSettingsForm()()
145 142
146 143 try:
147 144 form_result = application_form.to_python(dict(request.POST))
148 145 except formencode.Invalid as errors:
149 146 h.flash(
150 147 _("Some form inputs contain invalid data."),
151 148 category='error')
152 149 return htmlfill.render(
153 150 render('admin/settings/settings.mako'),
154 151 defaults=errors.value,
155 152 errors=errors.error_dict or {},
156 153 prefix_error=False,
157 154 encoding="UTF-8",
158 155 force_defaults=False
159 156 )
160 157
161 158 try:
162 159 if c.visual.allow_repo_location_change:
163 160 model.update_global_path_setting(
164 161 form_result['paths_root_path'])
165 162
166 163 model.update_global_ssl_setting(form_result['web_push_ssl'])
167 164 model.update_global_hook_settings(form_result)
168 165
169 166 model.create_or_update_global_svn_settings(form_result)
170 167 model.create_or_update_global_hg_settings(form_result)
171 168 model.create_or_update_global_pr_settings(form_result)
172 169 except Exception:
173 170 log.exception("Exception while updating settings")
174 171 h.flash(_('Error occurred during updating '
175 172 'application settings'), category='error')
176 173 else:
177 174 Session().commit()
178 175 h.flash(_('Updated VCS settings'), category='success')
179 176 return redirect(url('admin_settings_vcs'))
180 177
181 178 return htmlfill.render(
182 179 render('admin/settings/settings.mako'),
183 180 defaults=self._form_defaults(),
184 181 encoding="UTF-8",
185 182 force_defaults=False)
186 183
187 184 @HasPermissionAllDecorator('hg.admin')
188 185 def settings_vcs(self):
189 186 """GET /admin/settings: All items in the collection"""
190 187 # url('admin_settings_vcs')
191 188 c.active = 'vcs'
192 189 model = VcsSettingsModel()
193 190 c.svn_branch_patterns = model.get_global_svn_branch_patterns()
194 191 c.svn_tag_patterns = model.get_global_svn_tag_patterns()
195 192
196 193 # TODO: Replace with request.registry after migrating to pyramid.
197 194 pyramid_settings = get_current_registry().settings
198 195 c.svn_proxy_generate_config = pyramid_settings[generate_config]
199 196
200 197 return htmlfill.render(
201 198 render('admin/settings/settings.mako'),
202 199 defaults=self._form_defaults(),
203 200 encoding="UTF-8",
204 201 force_defaults=False)
205 202
206 203 @HasPermissionAllDecorator('hg.admin')
207 204 @auth.CSRFRequired()
208 205 def settings_mapping_update(self):
209 206 """POST /admin/settings/mapping: All items in the collection"""
210 207 # url('admin_settings_mapping')
211 208 c.active = 'mapping'
212 209 rm_obsolete = request.POST.get('destroy', False)
213 210 invalidate_cache = request.POST.get('invalidate', False)
214 211 log.debug(
215 212 'rescanning repo location with destroy obsolete=%s', rm_obsolete)
216 213
217 214 if invalidate_cache:
218 215 log.debug('invalidating all repositories cache')
219 216 for repo in Repository.get_all():
220 217 ScmModel().mark_for_invalidation(repo.repo_name, delete=True)
221 218
222 219 filesystem_repos = ScmModel().repo_scan()
223 220 added, removed = repo2db_mapper(filesystem_repos, rm_obsolete)
224 221 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
225 222 h.flash(_('Repositories successfully '
226 223 'rescanned added: %s ; removed: %s') %
227 224 (_repr(added), _repr(removed)),
228 225 category='success')
229 226 return redirect(url('admin_settings_mapping'))
230 227
231 228 @HasPermissionAllDecorator('hg.admin')
232 229 def settings_mapping(self):
233 230 """GET /admin/settings/mapping: All items in the collection"""
234 231 # url('admin_settings_mapping')
235 232 c.active = 'mapping'
236 233
237 234 return htmlfill.render(
238 235 render('admin/settings/settings.mako'),
239 236 defaults=self._form_defaults(),
240 237 encoding="UTF-8",
241 238 force_defaults=False)
242 239
243 240 @HasPermissionAllDecorator('hg.admin')
244 241 @auth.CSRFRequired()
245 242 def settings_global_update(self):
246 243 """POST /admin/settings/global: All items in the collection"""
247 244 # url('admin_settings_global')
248 245 c.active = 'global'
249 246 c.personal_repo_group_default_pattern = RepoGroupModel()\
250 247 .get_personal_group_name_pattern()
251 248 application_form = ApplicationSettingsForm()()
252 249 try:
253 250 form_result = application_form.to_python(dict(request.POST))
254 251 except formencode.Invalid as errors:
255 252 return htmlfill.render(
256 253 render('admin/settings/settings.mako'),
257 254 defaults=errors.value,
258 255 errors=errors.error_dict or {},
259 256 prefix_error=False,
260 257 encoding="UTF-8",
261 258 force_defaults=False)
262 259
263 260 try:
264 261 settings = [
265 262 ('title', 'rhodecode_title', 'unicode'),
266 263 ('realm', 'rhodecode_realm', 'unicode'),
267 264 ('pre_code', 'rhodecode_pre_code', 'unicode'),
268 265 ('post_code', 'rhodecode_post_code', 'unicode'),
269 266 ('captcha_public_key', 'rhodecode_captcha_public_key', 'unicode'),
270 267 ('captcha_private_key', 'rhodecode_captcha_private_key', 'unicode'),
271 268 ('create_personal_repo_group', 'rhodecode_create_personal_repo_group', 'bool'),
272 269 ('personal_repo_group_pattern', 'rhodecode_personal_repo_group_pattern', 'unicode'),
273 270 ]
274 271 for setting, form_key, type_ in settings:
275 272 sett = SettingsModel().create_or_update_setting(
276 273 setting, form_result[form_key], type_)
277 274 Session().add(sett)
278 275
279 276 Session().commit()
280 277 SettingsModel().invalidate_settings_cache()
281 278 h.flash(_('Updated application settings'), category='success')
282 279 except Exception:
283 280 log.exception("Exception while updating application settings")
284 281 h.flash(
285 282 _('Error occurred during updating application settings'),
286 283 category='error')
287 284
288 285 return redirect(url('admin_settings_global'))
289 286
290 287 @HasPermissionAllDecorator('hg.admin')
291 288 def settings_global(self):
292 289 """GET /admin/settings/global: All items in the collection"""
293 290 # url('admin_settings_global')
294 291 c.active = 'global'
295 292 c.personal_repo_group_default_pattern = RepoGroupModel()\
296 293 .get_personal_group_name_pattern()
297 294
298 295 return htmlfill.render(
299 296 render('admin/settings/settings.mako'),
300 297 defaults=self._form_defaults(),
301 298 encoding="UTF-8",
302 299 force_defaults=False)
303 300
304 301 @HasPermissionAllDecorator('hg.admin')
305 302 @auth.CSRFRequired()
306 303 def settings_visual_update(self):
307 304 """POST /admin/settings/visual: All items in the collection"""
308 305 # url('admin_settings_visual')
309 306 c.active = 'visual'
310 307 application_form = ApplicationVisualisationForm()()
311 308 try:
312 309 form_result = application_form.to_python(dict(request.POST))
313 310 except formencode.Invalid as errors:
314 311 return htmlfill.render(
315 312 render('admin/settings/settings.mako'),
316 313 defaults=errors.value,
317 314 errors=errors.error_dict or {},
318 315 prefix_error=False,
319 316 encoding="UTF-8",
320 317 force_defaults=False
321 318 )
322 319
323 320 try:
324 321 settings = [
325 322 ('show_public_icon', 'rhodecode_show_public_icon', 'bool'),
326 323 ('show_private_icon', 'rhodecode_show_private_icon', 'bool'),
327 324 ('stylify_metatags', 'rhodecode_stylify_metatags', 'bool'),
328 325 ('repository_fields', 'rhodecode_repository_fields', 'bool'),
329 326 ('dashboard_items', 'rhodecode_dashboard_items', 'int'),
330 327 ('admin_grid_items', 'rhodecode_admin_grid_items', 'int'),
331 328 ('show_version', 'rhodecode_show_version', 'bool'),
332 329 ('use_gravatar', 'rhodecode_use_gravatar', 'bool'),
333 330 ('markup_renderer', 'rhodecode_markup_renderer', 'unicode'),
334 331 ('gravatar_url', 'rhodecode_gravatar_url', 'unicode'),
335 332 ('clone_uri_tmpl', 'rhodecode_clone_uri_tmpl', 'unicode'),
336 333 ('support_url', 'rhodecode_support_url', 'unicode'),
337 334 ('show_revision_number', 'rhodecode_show_revision_number', 'bool'),
338 335 ('show_sha_length', 'rhodecode_show_sha_length', 'int'),
339 336 ]
340 337 for setting, form_key, type_ in settings:
341 338 sett = SettingsModel().create_or_update_setting(
342 339 setting, form_result[form_key], type_)
343 340 Session().add(sett)
344 341
345 342 Session().commit()
346 343 SettingsModel().invalidate_settings_cache()
347 344 h.flash(_('Updated visualisation settings'), category='success')
348 345 except Exception:
349 346 log.exception("Exception updating visualization settings")
350 347 h.flash(_('Error occurred during updating '
351 348 'visualisation settings'),
352 349 category='error')
353 350
354 351 return redirect(url('admin_settings_visual'))
355 352
356 353 @HasPermissionAllDecorator('hg.admin')
357 354 def settings_visual(self):
358 355 """GET /admin/settings/visual: All items in the collection"""
359 356 # url('admin_settings_visual')
360 357 c.active = 'visual'
361 358
362 359 return htmlfill.render(
363 360 render('admin/settings/settings.mako'),
364 361 defaults=self._form_defaults(),
365 362 encoding="UTF-8",
366 363 force_defaults=False)
367 364
368 365 @HasPermissionAllDecorator('hg.admin')
369 366 @auth.CSRFRequired()
370 367 def settings_issuetracker_test(self):
371 368 if request.is_xhr:
372 369 return h.urlify_commit_message(
373 370 request.POST.get('test_text', ''),
374 371 'repo_group/test_repo1')
375 372 else:
376 373 raise HTTPBadRequest()
377 374
378 375 @HasPermissionAllDecorator('hg.admin')
379 376 @auth.CSRFRequired()
380 377 def settings_issuetracker_delete(self):
381 378 uid = request.POST.get('uid')
382 379 IssueTrackerSettingsModel().delete_entries(uid)
383 380 h.flash(_('Removed issue tracker entry'), category='success')
384 381 return redirect(url('admin_settings_issuetracker'))
385 382
386 383 @HasPermissionAllDecorator('hg.admin')
387 384 def settings_issuetracker(self):
388 385 """GET /admin/settings/issue-tracker: All items in the collection"""
389 386 # url('admin_settings_issuetracker')
390 387 c.active = 'issuetracker'
391 388 defaults = SettingsModel().get_all_settings()
392 389
393 390 entry_key = 'rhodecode_issuetracker_pat_'
394 391
395 392 c.issuetracker_entries = {}
396 393 for k, v in defaults.items():
397 394 if k.startswith(entry_key):
398 395 uid = k[len(entry_key):]
399 396 c.issuetracker_entries[uid] = None
400 397
401 398 for uid in c.issuetracker_entries:
402 399 c.issuetracker_entries[uid] = AttributeDict({
403 400 'pat': defaults.get('rhodecode_issuetracker_pat_' + uid),
404 401 'url': defaults.get('rhodecode_issuetracker_url_' + uid),
405 402 'pref': defaults.get('rhodecode_issuetracker_pref_' + uid),
406 403 'desc': defaults.get('rhodecode_issuetracker_desc_' + uid),
407 404 })
408 405
409 406 return render('admin/settings/settings.mako')
410 407
411 408 @HasPermissionAllDecorator('hg.admin')
412 409 @auth.CSRFRequired()
413 410 def settings_issuetracker_save(self):
414 411 settings_model = IssueTrackerSettingsModel()
415 412
416 413 form = IssueTrackerPatternsForm()().to_python(request.POST)
417 414 if form:
418 415 for uid in form.get('delete_patterns', []):
419 416 settings_model.delete_entries(uid)
420 417
421 418 for pattern in form.get('patterns', []):
422 419 for setting, value, type_ in pattern:
423 420 sett = settings_model.create_or_update_setting(
424 421 setting, value, type_)
425 422 Session().add(sett)
426 423
427 424 Session().commit()
428 425
429 426 SettingsModel().invalidate_settings_cache()
430 427 h.flash(_('Updated issue tracker entries'), category='success')
431 428 return redirect(url('admin_settings_issuetracker'))
432 429
433 430 @HasPermissionAllDecorator('hg.admin')
434 431 @auth.CSRFRequired()
435 432 def settings_email_update(self):
436 433 """POST /admin/settings/email: All items in the collection"""
437 434 # url('admin_settings_email')
438 435 c.active = 'email'
439 436
440 437 test_email = request.POST.get('test_email')
441 438
442 439 if not test_email:
443 440 h.flash(_('Please enter email address'), category='error')
444 441 return redirect(url('admin_settings_email'))
445 442
446 443 email_kwargs = {
447 444 'date': datetime.datetime.now(),
448 445 'user': c.rhodecode_user,
449 446 'rhodecode_version': c.rhodecode_version
450 447 }
451 448
452 449 (subject, headers, email_body,
453 450 email_body_plaintext) = EmailNotificationModel().render_email(
454 451 EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs)
455 452
456 453 recipients = [test_email] if test_email else None
457 454
458 455 run_task(tasks.send_email, recipients, subject,
459 456 email_body_plaintext, email_body)
460 457
461 458 h.flash(_('Send email task created'), category='success')
462 459 return redirect(url('admin_settings_email'))
463 460
464 461 @HasPermissionAllDecorator('hg.admin')
465 462 def settings_email(self):
466 463 """GET /admin/settings/email: All items in the collection"""
467 464 # url('admin_settings_email')
468 465 c.active = 'email'
469 466 c.rhodecode_ini = rhodecode.CONFIG
470 467
471 468 return htmlfill.render(
472 469 render('admin/settings/settings.mako'),
473 470 defaults=self._form_defaults(),
474 471 encoding="UTF-8",
475 472 force_defaults=False)
476 473
477 474 @HasPermissionAllDecorator('hg.admin')
478 475 @auth.CSRFRequired()
479 476 def settings_hooks_update(self):
480 477 """POST or DELETE /admin/settings/hooks: All items in the collection"""
481 478 # url('admin_settings_hooks')
482 479 c.active = 'hooks'
483 480 if c.visual.allow_custom_hooks_settings:
484 481 ui_key = request.POST.get('new_hook_ui_key')
485 482 ui_value = request.POST.get('new_hook_ui_value')
486 483
487 484 hook_id = request.POST.get('hook_id')
488 485 new_hook = False
489 486
490 487 model = SettingsModel()
491 488 try:
492 489 if ui_value and ui_key:
493 490 model.create_or_update_hook(ui_key, ui_value)
494 491 h.flash(_('Added new hook'), category='success')
495 492 new_hook = True
496 493 elif hook_id:
497 494 RhodeCodeUi.delete(hook_id)
498 495 Session().commit()
499 496
500 497 # check for edits
501 498 update = False
502 499 _d = request.POST.dict_of_lists()
503 500 for k, v in zip(_d.get('hook_ui_key', []),
504 501 _d.get('hook_ui_value_new', [])):
505 502 model.create_or_update_hook(k, v)
506 503 update = True
507 504
508 505 if update and not new_hook:
509 506 h.flash(_('Updated hooks'), category='success')
510 507 Session().commit()
511 508 except Exception:
512 509 log.exception("Exception during hook creation")
513 510 h.flash(_('Error occurred during hook creation'),
514 511 category='error')
515 512
516 513 return redirect(url('admin_settings_hooks'))
517 514
518 515 @HasPermissionAllDecorator('hg.admin')
519 516 def settings_hooks(self):
520 517 """GET /admin/settings/hooks: All items in the collection"""
521 518 # url('admin_settings_hooks')
522 519 c.active = 'hooks'
523 520
524 521 model = SettingsModel()
525 522 c.hooks = model.get_builtin_hooks()
526 523 c.custom_hooks = model.get_custom_hooks()
527 524
528 525 return htmlfill.render(
529 526 render('admin/settings/settings.mako'),
530 527 defaults=self._form_defaults(),
531 528 encoding="UTF-8",
532 529 force_defaults=False)
533 530
534 531 @HasPermissionAllDecorator('hg.admin')
535 532 def settings_search(self):
536 533 """GET /admin/settings/search: All items in the collection"""
537 534 # url('admin_settings_search')
538 535 c.active = 'search'
539 536
540 537 from rhodecode.lib.index import searcher_from_config
541 538 searcher = searcher_from_config(config)
542 539 c.statistics = searcher.statistics()
543 540
544 541 return render('admin/settings/settings.mako')
545 542
546 543 @HasPermissionAllDecorator('hg.admin')
547 def settings_system(self):
548 """GET /admin/settings/system: All items in the collection"""
549 # url('admin_settings_system')
550 snapshot = str2bool(request.GET.get('snapshot'))
551 defaults = self._form_defaults()
552
553 c.active = 'system'
554 c.rhodecode_update_url = defaults.get('rhodecode_update_url')
555 server_info = ScmModel().get_server_info(request.environ)
556
557 for key, val in server_info.iteritems():
558 setattr(c, key, val)
559
560 def val(name, subkey='human_value'):
561 return server_info[name][subkey]
562
563 def state(name):
564 return server_info[name]['state']
565
566 def val2(name):
567 val = server_info[name]['human_value']
568 state = server_info[name]['state']
569 return val, state
570
571 c.data_items = [
572 # update info
573 (_('Update info'), h.literal(
574 '<span class="link" id="check_for_update" >%s.</span>' % (
575 _('Check for updates')) +
576 '<br/> <span >%s.</span>' % (_('Note: please make sure this server can access `%s` for the update link to work') % c.rhodecode_update_url)
577 ), ''),
578
579 # RhodeCode specific
580 (_('RhodeCode Version'), val('rhodecode_app')['text'], state('rhodecode_app')),
581 (_('RhodeCode Server IP'), val('server')['server_ip'], state('server')),
582 (_('RhodeCode Server ID'), val('server')['server_id'], state('server')),
583 (_('RhodeCode Configuration'), val('rhodecode_config')['path'], state('rhodecode_config')),
584 ('', '', ''), # spacer
585
586 # Database
587 (_('Database'), val('database')['url'], state('database')),
588 (_('Database version'), val('database')['version'], state('database')),
589 ('', '', ''), # spacer
590
591 # Platform/Python
592 (_('Platform'), val('platform')['name'], state('platform')),
593 (_('Platform UUID'), val('platform')['uuid'], state('platform')),
594 (_('Python version'), val('python')['version'], state('python')),
595 (_('Python path'), val('python')['executable'], state('python')),
596 ('', '', ''), # spacer
597
598 # Systems stats
599 (_('CPU'), val('cpu'), state('cpu')),
600 (_('Load'), val('load')['text'], state('load')),
601 (_('Memory'), val('memory')['text'], state('memory')),
602 (_('Uptime'), val('uptime')['text'], state('uptime')),
603 ('', '', ''), # spacer
604
605 # Repo storage
606 (_('Storage location'), val('storage')['path'], state('storage')),
607 (_('Storage info'), val('storage')['text'], state('storage')),
608 (_('Storage inodes'), val('storage_inodes')['text'], state('storage_inodes')),
609
610 (_('Gist storage location'), val('storage_gist')['path'], state('storage_gist')),
611 (_('Gist storage info'), val('storage_gist')['text'], state('storage_gist')),
612
613 (_('Archive cache storage location'), val('storage_archive')['path'], state('storage_archive')),
614 (_('Archive cache info'), val('storage_archive')['text'], state('storage_archive')),
615
616 (_('Temp storage location'), val('storage_temp')['path'], state('storage_temp')),
617 (_('Temp storage info'), val('storage_temp')['text'], state('storage_temp')),
618
619 (_('Search info'), val('search')['text'], state('search')),
620 (_('Search location'), val('search')['location'], state('search')),
621 ('', '', ''), # spacer
622
623 # VCS specific
624 (_('VCS Backends'), val('vcs_backends'), state('vcs_backends')),
625 (_('VCS Server'), val('vcs_server')['text'], state('vcs_server')),
626 (_('GIT'), val('git'), state('git')),
627 (_('HG'), val('hg'), state('hg')),
628 (_('SVN'), val('svn'), state('svn')),
629
630 ]
631
632 # TODO: marcink, figure out how to allow only selected users to do this
633 c.allowed_to_snapshot = c.rhodecode_user.admin
634
635 if snapshot:
636 if c.allowed_to_snapshot:
637 c.data_items.pop(0) # remove server info
638 return render('admin/settings/settings_system_snapshot.mako')
639 else:
640 h.flash('You are not allowed to do this', category='warning')
641
642 return htmlfill.render(
643 render('admin/settings/settings.mako'),
644 defaults=defaults,
645 encoding="UTF-8",
646 force_defaults=False)
647
648 @staticmethod
649 def get_update_data(update_url):
650 """Return the JSON update data."""
651 ver = rhodecode.__version__
652 log.debug('Checking for upgrade on `%s` server', update_url)
653 opener = urllib2.build_opener()
654 opener.addheaders = [('User-agent', 'RhodeCode-SCM/%s' % ver)]
655 response = opener.open(update_url)
656 response_data = response.read()
657 data = json.loads(response_data)
658
659 return data
660
661 @HasPermissionAllDecorator('hg.admin')
662 def settings_system_update(self):
663 """GET /admin/settings/system/updates: All items in the collection"""
664 # url('admin_settings_system_update')
665 defaults = self._form_defaults()
666 update_url = defaults.get('rhodecode_update_url', '')
667
668 _err = lambda s: '<div style="color:#ff8888; padding:4px 0px">%s</div>' % (s)
669 try:
670 data = self.get_update_data(update_url)
671 except urllib2.URLError as e:
672 log.exception("Exception contacting upgrade server")
673 return _err('Failed to contact upgrade server: %r' % e)
674 except ValueError as e:
675 log.exception("Bad data sent from update server")
676 return _err('Bad data sent from update server')
677
678 latest = data['versions'][0]
679
680 c.update_url = update_url
681 c.latest_data = latest
682 c.latest_ver = latest['version']
683 c.cur_ver = rhodecode.__version__
684 c.should_upgrade = False
685
686 if (packaging.version.Version(c.latest_ver) >
687 packaging.version.Version(c.cur_ver)):
688 c.should_upgrade = True
689 c.important_notices = latest['general']
690
691 return render('admin/settings/settings_system_update.mako')
692
693 @HasPermissionAllDecorator('hg.admin')
694 544 def settings_supervisor(self):
695 545 c.rhodecode_ini = rhodecode.CONFIG
696 546 c.active = 'supervisor'
697 547
698 548 c.supervisor_procs = OrderedDict([
699 549 (SUPERVISOR_MASTER, {}),
700 550 ])
701 551
702 552 c.log_size = 10240
703 553 supervisor = SupervisorModel()
704 554
705 555 _connection = supervisor.get_connection(
706 556 c.rhodecode_ini.get('supervisor.uri'))
707 557 c.connection_error = None
708 558 try:
709 559 _connection.supervisor.getAllProcessInfo()
710 560 except Exception as e:
711 561 c.connection_error = str(e)
712 562 log.exception("Exception reading supervisor data")
713 563 return render('admin/settings/settings.mako')
714 564
715 565 groupid = c.rhodecode_ini.get('supervisor.group_id')
716 566
717 567 # feed our group processes to the main
718 568 for proc in supervisor.get_group_processes(_connection, groupid):
719 569 c.supervisor_procs[proc['name']] = {}
720 570
721 571 for k in c.supervisor_procs.keys():
722 572 try:
723 573 # master process info
724 574 if k == SUPERVISOR_MASTER:
725 575 _data = supervisor.get_master_state(_connection)
726 576 _data['name'] = 'supervisor master'
727 577 _data['description'] = 'pid %s, id: %s, ver: %s' % (
728 578 _data['pid'], _data['id'], _data['ver'])
729 579 c.supervisor_procs[k] = _data
730 580 else:
731 581 procid = groupid + ":" + k
732 582 c.supervisor_procs[k] = supervisor.get_process_info(_connection, procid)
733 583 except Exception as e:
734 584 log.exception("Exception reading supervisor data")
735 585 c.supervisor_procs[k] = {'_rhodecode_error': str(e)}
736 586
737 587 return render('admin/settings/settings.mako')
738 588
739 589 @HasPermissionAllDecorator('hg.admin')
740 590 def settings_supervisor_log(self, procid):
741 591 import rhodecode
742 592 c.rhodecode_ini = rhodecode.CONFIG
743 593 c.active = 'supervisor_tail'
744 594
745 595 supervisor = SupervisorModel()
746 596 _connection = supervisor.get_connection(c.rhodecode_ini.get('supervisor.uri'))
747 597 groupid = c.rhodecode_ini.get('supervisor.group_id')
748 598 procid = groupid + ":" + procid if procid != SUPERVISOR_MASTER else procid
749 599
750 600 c.log_size = 10240
751 601 offset = abs(safe_int(request.GET.get('offset', c.log_size))) * -1
752 602 c.log = supervisor.read_process_log(_connection, procid, offset, 0)
753 603
754 604 return render('admin/settings/settings.mako')
755 605
756 606 @HasPermissionAllDecorator('hg.admin')
757 607 @auth.CSRFRequired()
758 608 def settings_labs_update(self):
759 609 """POST /admin/settings/labs: All items in the collection"""
760 610 # url('admin_settings/labs', method={'POST'})
761 611 c.active = 'labs'
762 612
763 613 application_form = LabsSettingsForm()()
764 614 try:
765 615 form_result = application_form.to_python(dict(request.POST))
766 616 except formencode.Invalid as errors:
767 617 h.flash(
768 618 _('Some form inputs contain invalid data.'),
769 619 category='error')
770 620 return htmlfill.render(
771 621 render('admin/settings/settings.mako'),
772 622 defaults=errors.value,
773 623 errors=errors.error_dict or {},
774 624 prefix_error=False,
775 625 encoding='UTF-8',
776 626 force_defaults=False
777 627 )
778 628
779 629 try:
780 630 session = Session()
781 631 for setting in _LAB_SETTINGS:
782 632 setting_name = setting.key[len('rhodecode_'):]
783 633 sett = SettingsModel().create_or_update_setting(
784 634 setting_name, form_result[setting.key], setting.type)
785 635 session.add(sett)
786 636
787 637 except Exception:
788 638 log.exception('Exception while updating lab settings')
789 639 h.flash(_('Error occurred during updating labs settings'),
790 640 category='error')
791 641 else:
792 642 Session().commit()
793 643 SettingsModel().invalidate_settings_cache()
794 644 h.flash(_('Updated Labs settings'), category='success')
795 645 return redirect(url('admin_settings_labs'))
796 646
797 647 return htmlfill.render(
798 648 render('admin/settings/settings.mako'),
799 649 defaults=self._form_defaults(),
800 650 encoding='UTF-8',
801 651 force_defaults=False)
802 652
803 653 @HasPermissionAllDecorator('hg.admin')
804 654 def settings_labs(self):
805 655 """GET /admin/settings/labs: All items in the collection"""
806 656 # url('admin_settings_labs')
807 657 if not c.labs_active:
808 658 redirect(url('admin_settings'))
809 659
810 660 c.active = 'labs'
811 661 c.lab_settings = _LAB_SETTINGS
812 662
813 663 return htmlfill.render(
814 664 render('admin/settings/settings.mako'),
815 665 defaults=self._form_defaults(),
816 666 encoding='UTF-8',
817 667 force_defaults=False)
818 668
819 669 def _form_defaults(self):
820 670 defaults = SettingsModel().get_all_settings()
821 671 defaults.update(self._get_hg_ui_settings())
822 672 defaults.update({
823 673 'new_svn_branch': '',
824 674 'new_svn_tag': '',
825 675 })
826 676 return defaults
827 677
828 678
829 679 # :param key: name of the setting including the 'rhodecode_' prefix
830 680 # :param type: the RhodeCodeSetting type to use.
831 681 # :param group: the i18ned group in which we should dispaly this setting
832 682 # :param label: the i18ned label we should display for this setting
833 683 # :param help: the i18ned help we should dispaly for this setting
834 684 LabSetting = collections.namedtuple(
835 685 'LabSetting', ('key', 'type', 'group', 'label', 'help'))
836 686
837 687
838 688 # This list has to be kept in sync with the form
839 689 # rhodecode.model.forms.LabsSettingsForm.
840 690 _LAB_SETTINGS = [
841 691
842 692 ]
@@ -1,57 +1,57 b''
1 1
2 2 <div id="update_notice" style="display: none; margin: -40px 0px 20px 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 <a href="${url('admin_settings_system', snapshot=1)}" class="panel-edit">${_('create summary snapshot')}</a>
11 <a href="${h.route_path('admin_settings_system', _query={'snapshot':1})}" class="panel-edit">${_('create summary snapshot')}</a>
12 12 % endif
13 13 </div>
14 14 <div class="panel-body">
15 15 <dl class="dl-horizontal settings">
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">${_('Python Packages')}</h3>
33 33 </div>
34 34 <div class="panel-body">
35 35 <table class="table">
36 36 <colgroup>
37 37 <col class='label'>
38 38 <col class='content'>
39 39 </colgroup>
40 40 <tbody>
41 41 % for key, value in c.py_modules['human_value']:
42 42 <tr>
43 43 <td>${key}</td>
44 44 <td>${value}</td>
45 45 </tr>
46 46 % endfor
47 47 </tbody>
48 48 </table>
49 49 </div>
50 50 </div>
51 51
52 52 <script>
53 53 $('#check_for_update').click(function(e){
54 54 $('#update_notice').show();
55 $('#update_notice').load("${h.url('admin_settings_system_update',version=c.rhodecode_version, platform=c.platform)}");
55 $('#update_notice').load("${h.route_path('admin_settings_system_update',version=c.rhodecode_version, platform=c.platform)}");
56 56 })
57 57 </script>
General Comments 0
You need to be logged in to leave comments. Login now