##// END OF EJS Templates
Implements #842 RhodeCode version disclosure....
marcink -
r3910:36f7562a beta
parent child Browse files
Show More
@@ -1,514 +1,519 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.admin.settings
3 rhodecode.controllers.admin.settings
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 settings controller for rhodecode admin
6 settings controller for rhodecode admin
7
7
8 :created_on: Jul 14, 2010
8 :created_on: Jul 14, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28 import formencode
28 import formencode
29 import pkg_resources
29 import pkg_resources
30 import platform
30 import platform
31
31
32 from sqlalchemy import func
32 from sqlalchemy import func
33 from formencode import htmlfill
33 from formencode import htmlfill
34 from pylons import request, session, tmpl_context as c, url, config
34 from pylons import request, session, tmpl_context as c, url, config
35 from pylons.controllers.util import abort, redirect
35 from pylons.controllers.util import abort, redirect
36 from pylons.i18n.translation import _
36 from pylons.i18n.translation import _
37
37
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
39 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 HasPermissionAnyDecorator, NotAnonymous, HasPermissionAny,\
40 HasPermissionAnyDecorator, NotAnonymous, HasPermissionAny,\
41 HasReposGroupPermissionAll, HasReposGroupPermissionAny, AuthUser
41 HasReposGroupPermissionAll, HasReposGroupPermissionAny, AuthUser
42 from rhodecode.lib.base import BaseController, render
42 from rhodecode.lib.base import BaseController, render
43 from rhodecode.lib.celerylib import tasks, run_task
43 from rhodecode.lib.celerylib import tasks, run_task
44 from rhodecode.lib.utils import repo2db_mapper, set_rhodecode_config, \
44 from rhodecode.lib.utils import repo2db_mapper, set_rhodecode_config, \
45 check_git_version
45 check_git_version
46 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
46 from rhodecode.model.db import RhodeCodeUi, Repository, RepoGroup, \
47 RhodeCodeSetting, PullRequest, PullRequestReviewers
47 RhodeCodeSetting, PullRequest, PullRequestReviewers
48 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
49 ApplicationUiSettingsForm, ApplicationVisualisationForm
49 ApplicationUiSettingsForm, ApplicationVisualisationForm
50 from rhodecode.model.scm import ScmModel, RepoGroupList
50 from rhodecode.model.scm import ScmModel, RepoGroupList
51 from rhodecode.model.user import UserModel
51 from rhodecode.model.user import UserModel
52 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.repo import RepoModel
53 from rhodecode.model.db import User
53 from rhodecode.model.db import User
54 from rhodecode.model.notification import EmailNotificationModel
54 from rhodecode.model.notification import EmailNotificationModel
55 from rhodecode.model.meta import Session
55 from rhodecode.model.meta import Session
56 from rhodecode.lib.utils2 import str2bool, safe_unicode
56 from rhodecode.lib.utils2 import str2bool, safe_unicode
57 from rhodecode.lib.compat import json
57 from rhodecode.lib.compat import json
58 log = logging.getLogger(__name__)
58 log = logging.getLogger(__name__)
59
59
60
60
61 class SettingsController(BaseController):
61 class SettingsController(BaseController):
62 """REST Controller styled on the Atom Publishing Protocol"""
62 """REST Controller styled on the Atom Publishing Protocol"""
63 # To properly map this controller, ensure your config/routing.py
63 # To properly map this controller, ensure your config/routing.py
64 # file has a resource setup:
64 # file has a resource setup:
65 # map.resource('setting', 'settings', controller='admin/settings',
65 # map.resource('setting', 'settings', controller='admin/settings',
66 # path_prefix='/admin', name_prefix='admin_')
66 # path_prefix='/admin', name_prefix='admin_')
67
67
68 @LoginRequired()
68 @LoginRequired()
69 def __before__(self):
69 def __before__(self):
70 super(SettingsController, self).__before__()
70 super(SettingsController, self).__before__()
71 c.modules = sorted([(p.project_name, p.version)
71 c.modules = sorted([(p.project_name, p.version)
72 for p in pkg_resources.working_set]
72 for p in pkg_resources.working_set]
73 + [('git', check_git_version())],
73 + [('git', check_git_version())],
74 key=lambda k: k[0].lower())
74 key=lambda k: k[0].lower())
75 c.py_version = platform.python_version()
75 c.py_version = platform.python_version()
76 c.platform = platform.platform()
76 c.platform = platform.platform()
77
77
78 @HasPermissionAllDecorator('hg.admin')
78 @HasPermissionAllDecorator('hg.admin')
79 def index(self, format='html'):
79 def index(self, format='html'):
80 """GET /admin/settings: All items in the collection"""
80 """GET /admin/settings: All items in the collection"""
81 # url('admin_settings')
81 # url('admin_settings')
82
82
83 defaults = RhodeCodeSetting.get_app_settings()
83 defaults = RhodeCodeSetting.get_app_settings()
84 defaults.update(self._get_hg_ui_settings())
84 defaults.update(self._get_hg_ui_settings())
85
85
86 return htmlfill.render(
86 return htmlfill.render(
87 render('admin/settings/settings.html'),
87 render('admin/settings/settings.html'),
88 defaults=defaults,
88 defaults=defaults,
89 encoding="UTF-8",
89 encoding="UTF-8",
90 force_defaults=False
90 force_defaults=False
91 )
91 )
92
92
93 @HasPermissionAllDecorator('hg.admin')
93 @HasPermissionAllDecorator('hg.admin')
94 def create(self):
94 def create(self):
95 """POST /admin/settings: Create a new item"""
95 """POST /admin/settings: Create a new item"""
96 # url('admin_settings')
96 # url('admin_settings')
97
97
98 @HasPermissionAllDecorator('hg.admin')
98 @HasPermissionAllDecorator('hg.admin')
99 def new(self, format='html'):
99 def new(self, format='html'):
100 """GET /admin/settings/new: Form to create a new item"""
100 """GET /admin/settings/new: Form to create a new item"""
101 # url('admin_new_setting')
101 # url('admin_new_setting')
102
102
103 @HasPermissionAllDecorator('hg.admin')
103 @HasPermissionAllDecorator('hg.admin')
104 def update(self, setting_id):
104 def update(self, setting_id):
105 """PUT /admin/settings/setting_id: Update an existing item"""
105 """PUT /admin/settings/setting_id: Update an existing item"""
106 # Forms posted to this method should contain a hidden field:
106 # Forms posted to this method should contain a hidden field:
107 # <input type="hidden" name="_method" value="PUT" />
107 # <input type="hidden" name="_method" value="PUT" />
108 # Or using helpers:
108 # Or using helpers:
109 # h.form(url('admin_setting', setting_id=ID),
109 # h.form(url('admin_setting', setting_id=ID),
110 # method='put')
110 # method='put')
111 # url('admin_setting', setting_id=ID)
111 # url('admin_setting', setting_id=ID)
112
112
113 if setting_id == 'mapping':
113 if setting_id == 'mapping':
114 rm_obsolete = request.POST.get('destroy', False)
114 rm_obsolete = request.POST.get('destroy', False)
115 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
115 log.debug('Rescanning directories with destroy=%s' % rm_obsolete)
116 initial = ScmModel().repo_scan()
116 initial = ScmModel().repo_scan()
117 log.debug('invalidating all repositories')
117 log.debug('invalidating all repositories')
118 for repo_name in initial.keys():
118 for repo_name in initial.keys():
119 ScmModel().mark_for_invalidation(repo_name)
119 ScmModel().mark_for_invalidation(repo_name)
120
120
121 added, removed = repo2db_mapper(initial, rm_obsolete)
121 added, removed = repo2db_mapper(initial, rm_obsolete)
122 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
122 _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-'
123 h.flash(_('Repositories successfully '
123 h.flash(_('Repositories successfully '
124 'rescanned added: %s ; removed: %s') %
124 'rescanned added: %s ; removed: %s') %
125 (_repr(added), _repr(removed)),
125 (_repr(added), _repr(removed)),
126 category='success')
126 category='success')
127
127
128 if setting_id == 'whoosh':
128 if setting_id == 'whoosh':
129 repo_location = self._get_hg_ui_settings()['paths_root_path']
129 repo_location = self._get_hg_ui_settings()['paths_root_path']
130 full_index = request.POST.get('full_index', False)
130 full_index = request.POST.get('full_index', False)
131 run_task(tasks.whoosh_index, repo_location, full_index)
131 run_task(tasks.whoosh_index, repo_location, full_index)
132 h.flash(_('Whoosh reindex task scheduled'), category='success')
132 h.flash(_('Whoosh reindex task scheduled'), category='success')
133
133
134 if setting_id == 'global':
134 if setting_id == 'global':
135
135
136 application_form = ApplicationSettingsForm()()
136 application_form = ApplicationSettingsForm()()
137 try:
137 try:
138 form_result = application_form.to_python(dict(request.POST))
138 form_result = application_form.to_python(dict(request.POST))
139 except formencode.Invalid, errors:
139 except formencode.Invalid, errors:
140 return htmlfill.render(
140 return htmlfill.render(
141 render('admin/settings/settings.html'),
141 render('admin/settings/settings.html'),
142 defaults=errors.value,
142 defaults=errors.value,
143 errors=errors.error_dict or {},
143 errors=errors.error_dict or {},
144 prefix_error=False,
144 prefix_error=False,
145 encoding="UTF-8"
145 encoding="UTF-8"
146 )
146 )
147
147
148 try:
148 try:
149 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
149 sett1 = RhodeCodeSetting.get_by_name_or_create('title')
150 sett1.app_settings_value = form_result['rhodecode_title']
150 sett1.app_settings_value = form_result['rhodecode_title']
151 Session().add(sett1)
151 Session().add(sett1)
152
152
153 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
153 sett2 = RhodeCodeSetting.get_by_name_or_create('realm')
154 sett2.app_settings_value = form_result['rhodecode_realm']
154 sett2.app_settings_value = form_result['rhodecode_realm']
155 Session().add(sett2)
155 Session().add(sett2)
156
156
157 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
157 sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code')
158 sett3.app_settings_value = form_result['rhodecode_ga_code']
158 sett3.app_settings_value = form_result['rhodecode_ga_code']
159 Session().add(sett3)
159 Session().add(sett3)
160
160
161 Session().commit()
161 Session().commit()
162 set_rhodecode_config(config)
162 set_rhodecode_config(config)
163 h.flash(_('Updated application settings'), category='success')
163 h.flash(_('Updated application settings'), category='success')
164
164
165 except Exception:
165 except Exception:
166 log.error(traceback.format_exc())
166 log.error(traceback.format_exc())
167 h.flash(_('Error occurred during updating '
167 h.flash(_('Error occurred during updating '
168 'application settings'),
168 'application settings'),
169 category='error')
169 category='error')
170
170
171 if setting_id == 'visual':
171 if setting_id == 'visual':
172
172
173 application_form = ApplicationVisualisationForm()()
173 application_form = ApplicationVisualisationForm()()
174 try:
174 try:
175 form_result = application_form.to_python(dict(request.POST))
175 form_result = application_form.to_python(dict(request.POST))
176 except formencode.Invalid, errors:
176 except formencode.Invalid, errors:
177 return htmlfill.render(
177 return htmlfill.render(
178 render('admin/settings/settings.html'),
178 render('admin/settings/settings.html'),
179 defaults=errors.value,
179 defaults=errors.value,
180 errors=errors.error_dict or {},
180 errors=errors.error_dict or {},
181 prefix_error=False,
181 prefix_error=False,
182 encoding="UTF-8"
182 encoding="UTF-8"
183 )
183 )
184
184
185 try:
185 try:
186 #TODO: rewrite this to something less ugly
186 #TODO: rewrite this to something less ugly
187 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
187 sett1 = RhodeCodeSetting.get_by_name_or_create('show_public_icon')
188 sett1.app_settings_value = \
188 sett1.app_settings_value = \
189 form_result['rhodecode_show_public_icon']
189 form_result['rhodecode_show_public_icon']
190 Session().add(sett1)
190 Session().add(sett1)
191
191
192 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
192 sett2 = RhodeCodeSetting.get_by_name_or_create('show_private_icon')
193 sett2.app_settings_value = \
193 sett2.app_settings_value = \
194 form_result['rhodecode_show_private_icon']
194 form_result['rhodecode_show_private_icon']
195 Session().add(sett2)
195 Session().add(sett2)
196
196
197 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
197 sett3 = RhodeCodeSetting.get_by_name_or_create('stylify_metatags')
198 sett3.app_settings_value = \
198 sett3.app_settings_value = \
199 form_result['rhodecode_stylify_metatags']
199 form_result['rhodecode_stylify_metatags']
200 Session().add(sett3)
200 Session().add(sett3)
201
201
202 sett4 = RhodeCodeSetting.get_by_name_or_create('repository_fields')
202 sett4 = RhodeCodeSetting.get_by_name_or_create('repository_fields')
203 sett4.app_settings_value = \
203 sett4.app_settings_value = \
204 form_result['rhodecode_repository_fields']
204 form_result['rhodecode_repository_fields']
205 Session().add(sett4)
205 Session().add(sett4)
206
206
207 sett5 = RhodeCodeSetting.get_by_name_or_create('dashboard_items')
207 sett5 = RhodeCodeSetting.get_by_name_or_create('dashboard_items')
208 sett5.app_settings_value = \
208 sett5.app_settings_value = \
209 form_result['rhodecode_dashboard_items']
209 form_result['rhodecode_dashboard_items']
210 Session().add(sett5)
210 Session().add(sett5)
211
211
212 sett6 = RhodeCodeSetting.get_by_name_or_create('show_version')
213 sett6.app_settings_value = \
214 form_result['rhodecode_show_version']
215 Session().add(sett6)
216
212 Session().commit()
217 Session().commit()
213 set_rhodecode_config(config)
218 set_rhodecode_config(config)
214 h.flash(_('Updated visualisation settings'),
219 h.flash(_('Updated visualisation settings'),
215 category='success')
220 category='success')
216
221
217 except Exception:
222 except Exception:
218 log.error(traceback.format_exc())
223 log.error(traceback.format_exc())
219 h.flash(_('Error occurred during updating '
224 h.flash(_('Error occurred during updating '
220 'visualisation settings'),
225 'visualisation settings'),
221 category='error')
226 category='error')
222
227
223 if setting_id == 'vcs':
228 if setting_id == 'vcs':
224 application_form = ApplicationUiSettingsForm()()
229 application_form = ApplicationUiSettingsForm()()
225 try:
230 try:
226 form_result = application_form.to_python(dict(request.POST))
231 form_result = application_form.to_python(dict(request.POST))
227 except formencode.Invalid, errors:
232 except formencode.Invalid, errors:
228 return htmlfill.render(
233 return htmlfill.render(
229 render('admin/settings/settings.html'),
234 render('admin/settings/settings.html'),
230 defaults=errors.value,
235 defaults=errors.value,
231 errors=errors.error_dict or {},
236 errors=errors.error_dict or {},
232 prefix_error=False,
237 prefix_error=False,
233 encoding="UTF-8"
238 encoding="UTF-8"
234 )
239 )
235
240
236 try:
241 try:
237 sett = RhodeCodeUi.get_by_key('push_ssl')
242 sett = RhodeCodeUi.get_by_key('push_ssl')
238 sett.ui_value = form_result['web_push_ssl']
243 sett.ui_value = form_result['web_push_ssl']
239 Session().add(sett)
244 Session().add(sett)
240
245
241 sett = RhodeCodeUi.get_by_key('/')
246 sett = RhodeCodeUi.get_by_key('/')
242 sett.ui_value = form_result['paths_root_path']
247 sett.ui_value = form_result['paths_root_path']
243 Session().add(sett)
248 Session().add(sett)
244
249
245 #HOOKS
250 #HOOKS
246 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
251 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_UPDATE)
247 sett.ui_active = form_result['hooks_changegroup_update']
252 sett.ui_active = form_result['hooks_changegroup_update']
248 Session().add(sett)
253 Session().add(sett)
249
254
250 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
255 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_REPO_SIZE)
251 sett.ui_active = form_result['hooks_changegroup_repo_size']
256 sett.ui_active = form_result['hooks_changegroup_repo_size']
252 Session().add(sett)
257 Session().add(sett)
253
258
254 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
259 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PUSH)
255 sett.ui_active = form_result['hooks_changegroup_push_logger']
260 sett.ui_active = form_result['hooks_changegroup_push_logger']
256 Session().add(sett)
261 Session().add(sett)
257
262
258 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
263 sett = RhodeCodeUi.get_by_key(RhodeCodeUi.HOOK_PULL)
259 sett.ui_active = form_result['hooks_outgoing_pull_logger']
264 sett.ui_active = form_result['hooks_outgoing_pull_logger']
260
265
261 Session().add(sett)
266 Session().add(sett)
262
267
263 ## EXTENSIONS
268 ## EXTENSIONS
264 sett = RhodeCodeUi.get_by_key('largefiles')
269 sett = RhodeCodeUi.get_by_key('largefiles')
265 if not sett:
270 if not sett:
266 #make one if it's not there !
271 #make one if it's not there !
267 sett = RhodeCodeUi()
272 sett = RhodeCodeUi()
268 sett.ui_key = 'largefiles'
273 sett.ui_key = 'largefiles'
269 sett.ui_section = 'extensions'
274 sett.ui_section = 'extensions'
270 sett.ui_active = form_result['extensions_largefiles']
275 sett.ui_active = form_result['extensions_largefiles']
271 Session().add(sett)
276 Session().add(sett)
272
277
273 sett = RhodeCodeUi.get_by_key('hgsubversion')
278 sett = RhodeCodeUi.get_by_key('hgsubversion')
274 if not sett:
279 if not sett:
275 #make one if it's not there !
280 #make one if it's not there !
276 sett = RhodeCodeUi()
281 sett = RhodeCodeUi()
277 sett.ui_key = 'hgsubversion'
282 sett.ui_key = 'hgsubversion'
278 sett.ui_section = 'extensions'
283 sett.ui_section = 'extensions'
279
284
280 sett.ui_active = form_result['extensions_hgsubversion']
285 sett.ui_active = form_result['extensions_hgsubversion']
281 Session().add(sett)
286 Session().add(sett)
282
287
283 # sett = RhodeCodeUi.get_by_key('hggit')
288 # sett = RhodeCodeUi.get_by_key('hggit')
284 # if not sett:
289 # if not sett:
285 # #make one if it's not there !
290 # #make one if it's not there !
286 # sett = RhodeCodeUi()
291 # sett = RhodeCodeUi()
287 # sett.ui_key = 'hggit'
292 # sett.ui_key = 'hggit'
288 # sett.ui_section = 'extensions'
293 # sett.ui_section = 'extensions'
289 #
294 #
290 # sett.ui_active = form_result['extensions_hggit']
295 # sett.ui_active = form_result['extensions_hggit']
291 # Session().add(sett)
296 # Session().add(sett)
292
297
293 Session().commit()
298 Session().commit()
294
299
295 h.flash(_('Updated VCS settings'), category='success')
300 h.flash(_('Updated VCS settings'), category='success')
296
301
297 except Exception:
302 except Exception:
298 log.error(traceback.format_exc())
303 log.error(traceback.format_exc())
299 h.flash(_('Error occurred during updating '
304 h.flash(_('Error occurred during updating '
300 'application settings'), category='error')
305 'application settings'), category='error')
301
306
302 if setting_id == 'hooks':
307 if setting_id == 'hooks':
303 ui_key = request.POST.get('new_hook_ui_key')
308 ui_key = request.POST.get('new_hook_ui_key')
304 ui_value = request.POST.get('new_hook_ui_value')
309 ui_value = request.POST.get('new_hook_ui_value')
305 try:
310 try:
306
311
307 if ui_value and ui_key:
312 if ui_value and ui_key:
308 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
313 RhodeCodeUi.create_or_update_hook(ui_key, ui_value)
309 h.flash(_('Added new hook'),
314 h.flash(_('Added new hook'),
310 category='success')
315 category='success')
311
316
312 # check for edits
317 # check for edits
313 update = False
318 update = False
314 _d = request.POST.dict_of_lists()
319 _d = request.POST.dict_of_lists()
315 for k, v in zip(_d.get('hook_ui_key', []),
320 for k, v in zip(_d.get('hook_ui_key', []),
316 _d.get('hook_ui_value_new', [])):
321 _d.get('hook_ui_value_new', [])):
317 RhodeCodeUi.create_or_update_hook(k, v)
322 RhodeCodeUi.create_or_update_hook(k, v)
318 update = True
323 update = True
319
324
320 if update:
325 if update:
321 h.flash(_('Updated hooks'), category='success')
326 h.flash(_('Updated hooks'), category='success')
322 Session().commit()
327 Session().commit()
323 except Exception:
328 except Exception:
324 log.error(traceback.format_exc())
329 log.error(traceback.format_exc())
325 h.flash(_('Error occurred during hook creation'),
330 h.flash(_('Error occurred during hook creation'),
326 category='error')
331 category='error')
327
332
328 return redirect(url('admin_edit_setting', setting_id='hooks'))
333 return redirect(url('admin_edit_setting', setting_id='hooks'))
329
334
330 if setting_id == 'email':
335 if setting_id == 'email':
331 test_email = request.POST.get('test_email')
336 test_email = request.POST.get('test_email')
332 test_email_subj = 'RhodeCode TestEmail'
337 test_email_subj = 'RhodeCode TestEmail'
333 test_email_body = 'RhodeCode Email test'
338 test_email_body = 'RhodeCode Email test'
334
339
335 test_email_html_body = EmailNotificationModel()\
340 test_email_html_body = EmailNotificationModel()\
336 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
341 .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT,
337 body=test_email_body)
342 body=test_email_body)
338
343
339 recipients = [test_email] if test_email else None
344 recipients = [test_email] if test_email else None
340
345
341 run_task(tasks.send_email, recipients, test_email_subj,
346 run_task(tasks.send_email, recipients, test_email_subj,
342 test_email_body, test_email_html_body)
347 test_email_body, test_email_html_body)
343
348
344 h.flash(_('Email task created'), category='success')
349 h.flash(_('Email task created'), category='success')
345 return redirect(url('admin_settings'))
350 return redirect(url('admin_settings'))
346
351
347 @HasPermissionAllDecorator('hg.admin')
352 @HasPermissionAllDecorator('hg.admin')
348 def delete(self, setting_id):
353 def delete(self, setting_id):
349 """DELETE /admin/settings/setting_id: Delete an existing item"""
354 """DELETE /admin/settings/setting_id: Delete an existing item"""
350 # Forms posted to this method should contain a hidden field:
355 # Forms posted to this method should contain a hidden field:
351 # <input type="hidden" name="_method" value="DELETE" />
356 # <input type="hidden" name="_method" value="DELETE" />
352 # Or using helpers:
357 # Or using helpers:
353 # h.form(url('admin_setting', setting_id=ID),
358 # h.form(url('admin_setting', setting_id=ID),
354 # method='delete')
359 # method='delete')
355 # url('admin_setting', setting_id=ID)
360 # url('admin_setting', setting_id=ID)
356 if setting_id == 'hooks':
361 if setting_id == 'hooks':
357 hook_id = request.POST.get('hook_id')
362 hook_id = request.POST.get('hook_id')
358 RhodeCodeUi.delete(hook_id)
363 RhodeCodeUi.delete(hook_id)
359 Session().commit()
364 Session().commit()
360
365
361 @HasPermissionAllDecorator('hg.admin')
366 @HasPermissionAllDecorator('hg.admin')
362 def show(self, setting_id, format='html'):
367 def show(self, setting_id, format='html'):
363 """
368 """
364 GET /admin/settings/setting_id: Show a specific item"""
369 GET /admin/settings/setting_id: Show a specific item"""
365 # url('admin_setting', setting_id=ID)
370 # url('admin_setting', setting_id=ID)
366
371
367 @HasPermissionAllDecorator('hg.admin')
372 @HasPermissionAllDecorator('hg.admin')
368 def edit(self, setting_id, format='html'):
373 def edit(self, setting_id, format='html'):
369 """
374 """
370 GET /admin/settings/setting_id/edit: Form to
375 GET /admin/settings/setting_id/edit: Form to
371 edit an existing item"""
376 edit an existing item"""
372 # url('admin_edit_setting', setting_id=ID)
377 # url('admin_edit_setting', setting_id=ID)
373
378
374 c.hooks = RhodeCodeUi.get_builtin_hooks()
379 c.hooks = RhodeCodeUi.get_builtin_hooks()
375 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
380 c.custom_hooks = RhodeCodeUi.get_custom_hooks()
376
381
377 return htmlfill.render(
382 return htmlfill.render(
378 render('admin/settings/hooks.html'),
383 render('admin/settings/hooks.html'),
379 defaults={},
384 defaults={},
380 encoding="UTF-8",
385 encoding="UTF-8",
381 force_defaults=False
386 force_defaults=False
382 )
387 )
383
388
384 def _load_my_repos_data(self):
389 def _load_my_repos_data(self):
385 repos_list = Session().query(Repository)\
390 repos_list = Session().query(Repository)\
386 .filter(Repository.user_id ==
391 .filter(Repository.user_id ==
387 self.rhodecode_user.user_id)\
392 self.rhodecode_user.user_id)\
388 .order_by(func.lower(Repository.repo_name)).all()
393 .order_by(func.lower(Repository.repo_name)).all()
389
394
390 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
395 repos_data = RepoModel().get_repos_as_dict(repos_list=repos_list,
391 admin=True)
396 admin=True)
392 #json used to render the grid
397 #json used to render the grid
393 return json.dumps(repos_data)
398 return json.dumps(repos_data)
394
399
395 @NotAnonymous()
400 @NotAnonymous()
396 def my_account(self):
401 def my_account(self):
397 """
402 """
398 GET /_admin/my_account Displays info about my account
403 GET /_admin/my_account Displays info about my account
399 """
404 """
400 # url('admin_settings_my_account')
405 # url('admin_settings_my_account')
401
406
402 c.user = User.get(self.rhodecode_user.user_id)
407 c.user = User.get(self.rhodecode_user.user_id)
403 c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
408 c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
404 ip_addr=self.ip_addr)
409 ip_addr=self.ip_addr)
405 c.ldap_dn = c.user.ldap_dn
410 c.ldap_dn = c.user.ldap_dn
406
411
407 if c.user.username == 'default':
412 if c.user.username == 'default':
408 h.flash(_("You can't edit this user since it's"
413 h.flash(_("You can't edit this user since it's"
409 " crucial for entire application"), category='warning')
414 " crucial for entire application"), category='warning')
410 return redirect(url('users'))
415 return redirect(url('users'))
411
416
412 #json used to render the grid
417 #json used to render the grid
413 c.data = self._load_my_repos_data()
418 c.data = self._load_my_repos_data()
414
419
415 defaults = c.user.get_dict()
420 defaults = c.user.get_dict()
416
421
417 c.form = htmlfill.render(
422 c.form = htmlfill.render(
418 render('admin/users/user_edit_my_account_form.html'),
423 render('admin/users/user_edit_my_account_form.html'),
419 defaults=defaults,
424 defaults=defaults,
420 encoding="UTF-8",
425 encoding="UTF-8",
421 force_defaults=False
426 force_defaults=False
422 )
427 )
423 return render('admin/users/user_edit_my_account.html')
428 return render('admin/users/user_edit_my_account.html')
424
429
425 @NotAnonymous()
430 @NotAnonymous()
426 def my_account_update(self):
431 def my_account_update(self):
427 """PUT /_admin/my_account_update: Update an existing item"""
432 """PUT /_admin/my_account_update: Update an existing item"""
428 # Forms posted to this method should contain a hidden field:
433 # Forms posted to this method should contain a hidden field:
429 # <input type="hidden" name="_method" value="PUT" />
434 # <input type="hidden" name="_method" value="PUT" />
430 # Or using helpers:
435 # Or using helpers:
431 # h.form(url('admin_settings_my_account_update'),
436 # h.form(url('admin_settings_my_account_update'),
432 # method='put')
437 # method='put')
433 # url('admin_settings_my_account_update', id=ID)
438 # url('admin_settings_my_account_update', id=ID)
434 uid = self.rhodecode_user.user_id
439 uid = self.rhodecode_user.user_id
435 c.user = User.get(self.rhodecode_user.user_id)
440 c.user = User.get(self.rhodecode_user.user_id)
436 c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
441 c.perm_user = AuthUser(user_id=self.rhodecode_user.user_id,
437 ip_addr=self.ip_addr)
442 ip_addr=self.ip_addr)
438 c.ldap_dn = c.user.ldap_dn
443 c.ldap_dn = c.user.ldap_dn
439 email = self.rhodecode_user.email
444 email = self.rhodecode_user.email
440 _form = UserForm(edit=True,
445 _form = UserForm(edit=True,
441 old_data={'user_id': uid, 'email': email})()
446 old_data={'user_id': uid, 'email': email})()
442 form_result = {}
447 form_result = {}
443 try:
448 try:
444 form_result = _form.to_python(dict(request.POST))
449 form_result = _form.to_python(dict(request.POST))
445 skip_attrs = ['admin', 'active'] # skip attr for my account
450 skip_attrs = ['admin', 'active'] # skip attr for my account
446 if c.ldap_dn:
451 if c.ldap_dn:
447 #forbid updating username for ldap accounts
452 #forbid updating username for ldap accounts
448 skip_attrs.append('username')
453 skip_attrs.append('username')
449 UserModel().update(uid, form_result, skip_attrs=skip_attrs)
454 UserModel().update(uid, form_result, skip_attrs=skip_attrs)
450 h.flash(_('Your account was updated successfully'),
455 h.flash(_('Your account was updated successfully'),
451 category='success')
456 category='success')
452 Session().commit()
457 Session().commit()
453 except formencode.Invalid, errors:
458 except formencode.Invalid, errors:
454 #json used to render the grid
459 #json used to render the grid
455 c.data = self._load_my_repos_data()
460 c.data = self._load_my_repos_data()
456 c.form = htmlfill.render(
461 c.form = htmlfill.render(
457 render('admin/users/user_edit_my_account_form.html'),
462 render('admin/users/user_edit_my_account_form.html'),
458 defaults=errors.value,
463 defaults=errors.value,
459 errors=errors.error_dict or {},
464 errors=errors.error_dict or {},
460 prefix_error=False,
465 prefix_error=False,
461 encoding="UTF-8")
466 encoding="UTF-8")
462 return render('admin/users/user_edit_my_account.html')
467 return render('admin/users/user_edit_my_account.html')
463 except Exception:
468 except Exception:
464 log.error(traceback.format_exc())
469 log.error(traceback.format_exc())
465 h.flash(_('Error occurred during update of user %s') \
470 h.flash(_('Error occurred during update of user %s') \
466 % form_result.get('username'), category='error')
471 % form_result.get('username'), category='error')
467
472
468 return redirect(url('my_account'))
473 return redirect(url('my_account'))
469
474
470 @NotAnonymous()
475 @NotAnonymous()
471 def my_account_my_pullrequests(self):
476 def my_account_my_pullrequests(self):
472 c.show_closed = request.GET.get('pr_show_closed')
477 c.show_closed = request.GET.get('pr_show_closed')
473
478
474 def _filter(pr):
479 def _filter(pr):
475 s = sorted(pr, key=lambda o: o.created_on, reverse=True)
480 s = sorted(pr, key=lambda o: o.created_on, reverse=True)
476 if not c.show_closed:
481 if not c.show_closed:
477 s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
482 s = filter(lambda p: p.status != PullRequest.STATUS_CLOSED, s)
478 return s
483 return s
479
484
480 c.my_pull_requests = _filter(PullRequest.query()\
485 c.my_pull_requests = _filter(PullRequest.query()\
481 .filter(PullRequest.user_id ==
486 .filter(PullRequest.user_id ==
482 self.rhodecode_user.user_id)\
487 self.rhodecode_user.user_id)\
483 .all())
488 .all())
484
489
485 c.participate_in_pull_requests = _filter([
490 c.participate_in_pull_requests = _filter([
486 x.pull_request for x in PullRequestReviewers.query()\
491 x.pull_request for x in PullRequestReviewers.query()\
487 .filter(PullRequestReviewers.user_id ==
492 .filter(PullRequestReviewers.user_id ==
488 self.rhodecode_user.user_id).all()])
493 self.rhodecode_user.user_id).all()])
489
494
490 return render('admin/users/user_edit_my_account_pullrequests.html')
495 return render('admin/users/user_edit_my_account_pullrequests.html')
491
496
492 def _get_hg_ui_settings(self):
497 def _get_hg_ui_settings(self):
493 ret = RhodeCodeUi.query().all()
498 ret = RhodeCodeUi.query().all()
494
499
495 if not ret:
500 if not ret:
496 raise Exception('Could not get application ui settings !')
501 raise Exception('Could not get application ui settings !')
497 settings = {}
502 settings = {}
498 for each in ret:
503 for each in ret:
499 k = each.ui_key
504 k = each.ui_key
500 v = each.ui_value
505 v = each.ui_value
501 if k == '/':
506 if k == '/':
502 k = 'root_path'
507 k = 'root_path'
503
508
504 if k == 'push_ssl':
509 if k == 'push_ssl':
505 v = str2bool(v)
510 v = str2bool(v)
506
511
507 if k.find('.') != -1:
512 if k.find('.') != -1:
508 k = k.replace('.', '_')
513 k = k.replace('.', '_')
509
514
510 if each.ui_section in ['hooks', 'extensions']:
515 if each.ui_section in ['hooks', 'extensions']:
511 v = each.ui_active
516 v = each.ui_active
512
517
513 settings[each.ui_section + '_' + k] = v
518 settings[each.ui_section + '_' + k] = v
514 return settings
519 return settings
@@ -1,345 +1,347 b''
1 """The base Controller API
1 """The base Controller API
2
2
3 Provides the BaseController class for subclassing.
3 Provides the BaseController class for subclassing.
4 """
4 """
5 import logging
5 import logging
6 import time
6 import time
7 import traceback
7 import traceback
8
8
9 from paste.auth.basic import AuthBasicAuthenticator
9 from paste.auth.basic import AuthBasicAuthenticator
10 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden
10 from paste.httpexceptions import HTTPUnauthorized, HTTPForbidden
11 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
11 from paste.httpheaders import WWW_AUTHENTICATE, AUTHORIZATION
12
12
13 from pylons import config, tmpl_context as c, request, session, url
13 from pylons import config, tmpl_context as c, request, session, url
14 from pylons.controllers import WSGIController
14 from pylons.controllers import WSGIController
15 from pylons.controllers.util import redirect
15 from pylons.controllers.util import redirect
16 from pylons.templating import render_mako as render
16 from pylons.templating import render_mako as render
17
17
18 from rhodecode import __version__, BACKENDS
18 from rhodecode import __version__, BACKENDS
19
19
20 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
20 from rhodecode.lib.utils2 import str2bool, safe_unicode, AttributeDict,\
21 safe_str, safe_int
21 safe_str, safe_int
22 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
22 from rhodecode.lib.auth import AuthUser, get_container_username, authfunc,\
23 HasPermissionAnyMiddleware, CookieStoreWrapper
23 HasPermissionAnyMiddleware, CookieStoreWrapper
24 from rhodecode.lib.utils import get_repo_slug
24 from rhodecode.lib.utils import get_repo_slug
25 from rhodecode.model import meta
25 from rhodecode.model import meta
26
26
27 from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting
27 from rhodecode.model.db import Repository, RhodeCodeUi, User, RhodeCodeSetting
28 from rhodecode.model.notification import NotificationModel
28 from rhodecode.model.notification import NotificationModel
29 from rhodecode.model.scm import ScmModel
29 from rhodecode.model.scm import ScmModel
30 from rhodecode.model.meta import Session
30 from rhodecode.model.meta import Session
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 def _filter_proxy(ip):
35 def _filter_proxy(ip):
36 """
36 """
37 HEADERS can have mutliple ips inside the left-most being the original
37 HEADERS can have mutliple ips inside the left-most being the original
38 client, and each successive proxy that passed the request adding the IP
38 client, and each successive proxy that passed the request adding the IP
39 address where it received the request from.
39 address where it received the request from.
40
40
41 :param ip:
41 :param ip:
42 """
42 """
43 if ',' in ip:
43 if ',' in ip:
44 _ips = ip.split(',')
44 _ips = ip.split(',')
45 _first_ip = _ips[0].strip()
45 _first_ip = _ips[0].strip()
46 log.debug('Got multiple IPs %s, using %s' % (','.join(_ips), _first_ip))
46 log.debug('Got multiple IPs %s, using %s' % (','.join(_ips), _first_ip))
47 return _first_ip
47 return _first_ip
48 return ip
48 return ip
49
49
50
50
51 def _get_ip_addr(environ):
51 def _get_ip_addr(environ):
52 proxy_key = 'HTTP_X_REAL_IP'
52 proxy_key = 'HTTP_X_REAL_IP'
53 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
53 proxy_key2 = 'HTTP_X_FORWARDED_FOR'
54 def_key = 'REMOTE_ADDR'
54 def_key = 'REMOTE_ADDR'
55
55
56 ip = environ.get(proxy_key)
56 ip = environ.get(proxy_key)
57 if ip:
57 if ip:
58 return _filter_proxy(ip)
58 return _filter_proxy(ip)
59
59
60 ip = environ.get(proxy_key2)
60 ip = environ.get(proxy_key2)
61 if ip:
61 if ip:
62 return _filter_proxy(ip)
62 return _filter_proxy(ip)
63
63
64 ip = environ.get(def_key, '0.0.0.0')
64 ip = environ.get(def_key, '0.0.0.0')
65 return _filter_proxy(ip)
65 return _filter_proxy(ip)
66
66
67
67
68 def _get_access_path(environ):
68 def _get_access_path(environ):
69 path = environ.get('PATH_INFO')
69 path = environ.get('PATH_INFO')
70 org_req = environ.get('pylons.original_request')
70 org_req = environ.get('pylons.original_request')
71 if org_req:
71 if org_req:
72 path = org_req.environ.get('PATH_INFO')
72 path = org_req.environ.get('PATH_INFO')
73 return path
73 return path
74
74
75
75
76 class BasicAuth(AuthBasicAuthenticator):
76 class BasicAuth(AuthBasicAuthenticator):
77
77
78 def __init__(self, realm, authfunc, auth_http_code=None):
78 def __init__(self, realm, authfunc, auth_http_code=None):
79 self.realm = realm
79 self.realm = realm
80 self.authfunc = authfunc
80 self.authfunc = authfunc
81 self._rc_auth_http_code = auth_http_code
81 self._rc_auth_http_code = auth_http_code
82
82
83 def build_authentication(self):
83 def build_authentication(self):
84 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
84 head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
85 if self._rc_auth_http_code and self._rc_auth_http_code == '403':
85 if self._rc_auth_http_code and self._rc_auth_http_code == '403':
86 # return 403 if alternative http return code is specified in
86 # return 403 if alternative http return code is specified in
87 # RhodeCode config
87 # RhodeCode config
88 return HTTPForbidden(headers=head)
88 return HTTPForbidden(headers=head)
89 return HTTPUnauthorized(headers=head)
89 return HTTPUnauthorized(headers=head)
90
90
91 def authenticate(self, environ):
91 def authenticate(self, environ):
92 authorization = AUTHORIZATION(environ)
92 authorization = AUTHORIZATION(environ)
93 if not authorization:
93 if not authorization:
94 return self.build_authentication()
94 return self.build_authentication()
95 (authmeth, auth) = authorization.split(' ', 1)
95 (authmeth, auth) = authorization.split(' ', 1)
96 if 'basic' != authmeth.lower():
96 if 'basic' != authmeth.lower():
97 return self.build_authentication()
97 return self.build_authentication()
98 auth = auth.strip().decode('base64')
98 auth = auth.strip().decode('base64')
99 _parts = auth.split(':', 1)
99 _parts = auth.split(':', 1)
100 if len(_parts) == 2:
100 if len(_parts) == 2:
101 username, password = _parts
101 username, password = _parts
102 if self.authfunc(environ, username, password):
102 if self.authfunc(environ, username, password):
103 return username
103 return username
104 return self.build_authentication()
104 return self.build_authentication()
105
105
106 __call__ = authenticate
106 __call__ = authenticate
107
107
108
108
109 class BaseVCSController(object):
109 class BaseVCSController(object):
110
110
111 def __init__(self, application, config):
111 def __init__(self, application, config):
112 self.application = application
112 self.application = application
113 self.config = config
113 self.config = config
114 # base path of repo locations
114 # base path of repo locations
115 self.basepath = self.config['base_path']
115 self.basepath = self.config['base_path']
116 #authenticate this mercurial request using authfunc
116 #authenticate this mercurial request using authfunc
117 self.authenticate = BasicAuth('', authfunc,
117 self.authenticate = BasicAuth('', authfunc,
118 config.get('auth_ret_code'))
118 config.get('auth_ret_code'))
119 self.ip_addr = '0.0.0.0'
119 self.ip_addr = '0.0.0.0'
120
120
121 def _handle_request(self, environ, start_response):
121 def _handle_request(self, environ, start_response):
122 raise NotImplementedError()
122 raise NotImplementedError()
123
123
124 def _get_by_id(self, repo_name):
124 def _get_by_id(self, repo_name):
125 """
125 """
126 Get's a special pattern _<ID> from clone url and tries to replace it
126 Get's a special pattern _<ID> from clone url and tries to replace it
127 with a repository_name for support of _<ID> non changable urls
127 with a repository_name for support of _<ID> non changable urls
128
128
129 :param repo_name:
129 :param repo_name:
130 """
130 """
131 try:
131 try:
132 data = repo_name.split('/')
132 data = repo_name.split('/')
133 if len(data) >= 2:
133 if len(data) >= 2:
134 by_id = data[1].split('_')
134 by_id = data[1].split('_')
135 if len(by_id) == 2 and by_id[1].isdigit():
135 if len(by_id) == 2 and by_id[1].isdigit():
136 _repo_name = Repository.get(by_id[1]).repo_name
136 _repo_name = Repository.get(by_id[1]).repo_name
137 data[1] = _repo_name
137 data[1] = _repo_name
138 except Exception:
138 except Exception:
139 log.debug('Failed to extract repo_name from id %s' % (
139 log.debug('Failed to extract repo_name from id %s' % (
140 traceback.format_exc()
140 traceback.format_exc()
141 )
141 )
142 )
142 )
143
143
144 return '/'.join(data)
144 return '/'.join(data)
145
145
146 def _invalidate_cache(self, repo_name):
146 def _invalidate_cache(self, repo_name):
147 """
147 """
148 Set's cache for this repository for invalidation on next access
148 Set's cache for this repository for invalidation on next access
149
149
150 :param repo_name: full repo name, also a cache key
150 :param repo_name: full repo name, also a cache key
151 """
151 """
152 ScmModel().mark_for_invalidation(repo_name)
152 ScmModel().mark_for_invalidation(repo_name)
153
153
154 def _check_permission(self, action, user, repo_name, ip_addr=None):
154 def _check_permission(self, action, user, repo_name, ip_addr=None):
155 """
155 """
156 Checks permissions using action (push/pull) user and repository
156 Checks permissions using action (push/pull) user and repository
157 name
157 name
158
158
159 :param action: push or pull action
159 :param action: push or pull action
160 :param user: user instance
160 :param user: user instance
161 :param repo_name: repository name
161 :param repo_name: repository name
162 """
162 """
163 #check IP
163 #check IP
164 authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr)
164 authuser = AuthUser(user_id=user.user_id, ip_addr=ip_addr)
165 if not authuser.ip_allowed:
165 if not authuser.ip_allowed:
166 return False
166 return False
167 else:
167 else:
168 log.info('Access for IP:%s allowed' % (ip_addr))
168 log.info('Access for IP:%s allowed' % (ip_addr))
169 if action == 'push':
169 if action == 'push':
170 if not HasPermissionAnyMiddleware('repository.write',
170 if not HasPermissionAnyMiddleware('repository.write',
171 'repository.admin')(user,
171 'repository.admin')(user,
172 repo_name):
172 repo_name):
173 return False
173 return False
174
174
175 else:
175 else:
176 #any other action need at least read permission
176 #any other action need at least read permission
177 if not HasPermissionAnyMiddleware('repository.read',
177 if not HasPermissionAnyMiddleware('repository.read',
178 'repository.write',
178 'repository.write',
179 'repository.admin')(user,
179 'repository.admin')(user,
180 repo_name):
180 repo_name):
181 return False
181 return False
182
182
183 return True
183 return True
184
184
185 def _get_ip_addr(self, environ):
185 def _get_ip_addr(self, environ):
186 return _get_ip_addr(environ)
186 return _get_ip_addr(environ)
187
187
188 def _check_ssl(self, environ, start_response):
188 def _check_ssl(self, environ, start_response):
189 """
189 """
190 Checks the SSL check flag and returns False if SSL is not present
190 Checks the SSL check flag and returns False if SSL is not present
191 and required True otherwise
191 and required True otherwise
192 """
192 """
193 org_proto = environ['wsgi._org_proto']
193 org_proto = environ['wsgi._org_proto']
194 #check if we have SSL required ! if not it's a bad request !
194 #check if we have SSL required ! if not it's a bad request !
195 require_ssl = str2bool(RhodeCodeUi.get_by_key('push_ssl').ui_value)
195 require_ssl = str2bool(RhodeCodeUi.get_by_key('push_ssl').ui_value)
196 if require_ssl and org_proto == 'http':
196 if require_ssl and org_proto == 'http':
197 log.debug('proto is %s and SSL is required BAD REQUEST !'
197 log.debug('proto is %s and SSL is required BAD REQUEST !'
198 % org_proto)
198 % org_proto)
199 return False
199 return False
200 return True
200 return True
201
201
202 def _check_locking_state(self, environ, action, repo, user_id):
202 def _check_locking_state(self, environ, action, repo, user_id):
203 """
203 """
204 Checks locking on this repository, if locking is enabled and lock is
204 Checks locking on this repository, if locking is enabled and lock is
205 present returns a tuple of make_lock, locked, locked_by.
205 present returns a tuple of make_lock, locked, locked_by.
206 make_lock can have 3 states None (do nothing) True, make lock
206 make_lock can have 3 states None (do nothing) True, make lock
207 False release lock, This value is later propagated to hooks, which
207 False release lock, This value is later propagated to hooks, which
208 do the locking. Think about this as signals passed to hooks what to do.
208 do the locking. Think about this as signals passed to hooks what to do.
209
209
210 """
210 """
211 locked = False # defines that locked error should be thrown to user
211 locked = False # defines that locked error should be thrown to user
212 make_lock = None
212 make_lock = None
213 repo = Repository.get_by_repo_name(repo)
213 repo = Repository.get_by_repo_name(repo)
214 user = User.get(user_id)
214 user = User.get(user_id)
215
215
216 # this is kind of hacky, but due to how mercurial handles client-server
216 # this is kind of hacky, but due to how mercurial handles client-server
217 # server see all operation on changeset; bookmarks, phases and
217 # server see all operation on changeset; bookmarks, phases and
218 # obsolescence marker in different transaction, we don't want to check
218 # obsolescence marker in different transaction, we don't want to check
219 # locking on those
219 # locking on those
220 obsolete_call = environ['QUERY_STRING'] in ['cmd=listkeys',]
220 obsolete_call = environ['QUERY_STRING'] in ['cmd=listkeys',]
221 locked_by = repo.locked
221 locked_by = repo.locked
222 if repo and repo.enable_locking and not obsolete_call:
222 if repo and repo.enable_locking and not obsolete_call:
223 if action == 'push':
223 if action == 'push':
224 #check if it's already locked !, if it is compare users
224 #check if it's already locked !, if it is compare users
225 user_id, _date = repo.locked
225 user_id, _date = repo.locked
226 if user.user_id == user_id:
226 if user.user_id == user_id:
227 log.debug('Got push from user %s, now unlocking' % (user))
227 log.debug('Got push from user %s, now unlocking' % (user))
228 # unlock if we have push from user who locked
228 # unlock if we have push from user who locked
229 make_lock = False
229 make_lock = False
230 else:
230 else:
231 # we're not the same user who locked, ban with 423 !
231 # we're not the same user who locked, ban with 423 !
232 locked = True
232 locked = True
233 if action == 'pull':
233 if action == 'pull':
234 if repo.locked[0] and repo.locked[1]:
234 if repo.locked[0] and repo.locked[1]:
235 locked = True
235 locked = True
236 else:
236 else:
237 log.debug('Setting lock on repo %s by %s' % (repo, user))
237 log.debug('Setting lock on repo %s by %s' % (repo, user))
238 make_lock = True
238 make_lock = True
239
239
240 else:
240 else:
241 log.debug('Repository %s do not have locking enabled' % (repo))
241 log.debug('Repository %s do not have locking enabled' % (repo))
242 log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s'
242 log.debug('FINAL locking values make_lock:%s,locked:%s,locked_by:%s'
243 % (make_lock, locked, locked_by))
243 % (make_lock, locked, locked_by))
244 return make_lock, locked, locked_by
244 return make_lock, locked, locked_by
245
245
246 def __call__(self, environ, start_response):
246 def __call__(self, environ, start_response):
247 start = time.time()
247 start = time.time()
248 try:
248 try:
249 return self._handle_request(environ, start_response)
249 return self._handle_request(environ, start_response)
250 finally:
250 finally:
251 log = logging.getLogger('rhodecode.' + self.__class__.__name__)
251 log = logging.getLogger('rhodecode.' + self.__class__.__name__)
252 log.debug('Request time: %.3fs' % (time.time() - start))
252 log.debug('Request time: %.3fs' % (time.time() - start))
253 meta.Session.remove()
253 meta.Session.remove()
254
254
255
255
256 class BaseController(WSGIController):
256 class BaseController(WSGIController):
257
257
258 def __before__(self):
258 def __before__(self):
259 """
259 """
260 __before__ is called before controller methods and after __call__
260 __before__ is called before controller methods and after __call__
261 """
261 """
262 c.rhodecode_version = __version__
262 c.rhodecode_version = __version__
263 c.rhodecode_instanceid = config.get('instance_id')
263 c.rhodecode_instanceid = config.get('instance_id')
264 c.rhodecode_name = config.get('rhodecode_title')
264 c.rhodecode_name = config.get('rhodecode_title')
265 c.use_gravatar = str2bool(config.get('use_gravatar'))
265 c.use_gravatar = str2bool(config.get('use_gravatar'))
266 c.ga_code = config.get('rhodecode_ga_code')
266 c.ga_code = config.get('rhodecode_ga_code')
267 # Visual options
267 # Visual options
268 c.visual = AttributeDict({})
268 c.visual = AttributeDict({})
269 rc_config = RhodeCodeSetting.get_app_settings()
269 rc_config = RhodeCodeSetting.get_app_settings()
270 ## DB stored
270 ## DB stored
271 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon'))
271 c.visual.show_public_icon = str2bool(rc_config.get('rhodecode_show_public_icon'))
272 c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon'))
272 c.visual.show_private_icon = str2bool(rc_config.get('rhodecode_show_private_icon'))
273 c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags'))
273 c.visual.stylify_metatags = str2bool(rc_config.get('rhodecode_stylify_metatags'))
274 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100))
274 c.visual.dashboard_items = safe_int(rc_config.get('rhodecode_dashboard_items', 100))
275 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
275 c.visual.repository_fields = str2bool(rc_config.get('rhodecode_repository_fields'))
276 c.visual.show_version = str2bool(rc_config.get('rhodecode_show_version'))
277
276 ## INI stored
278 ## INI stored
277 self.cut_off_limit = int(config.get('cut_off_limit'))
279 self.cut_off_limit = int(config.get('cut_off_limit'))
278
280
279 c.repo_name = get_repo_slug(request) # can be empty
281 c.repo_name = get_repo_slug(request) # can be empty
280 c.backends = BACKENDS.keys()
282 c.backends = BACKENDS.keys()
281 c.unread_notifications = NotificationModel()\
283 c.unread_notifications = NotificationModel()\
282 .get_unread_cnt_for_user(c.rhodecode_user.user_id)
284 .get_unread_cnt_for_user(c.rhodecode_user.user_id)
283 self.sa = meta.Session
285 self.sa = meta.Session
284 self.scm_model = ScmModel(self.sa)
286 self.scm_model = ScmModel(self.sa)
285
287
286 def __call__(self, environ, start_response):
288 def __call__(self, environ, start_response):
287 """Invoke the Controller"""
289 """Invoke the Controller"""
288 # WSGIController.__call__ dispatches to the Controller method
290 # WSGIController.__call__ dispatches to the Controller method
289 # the request is routed to. This routing information is
291 # the request is routed to. This routing information is
290 # available in environ['pylons.routes_dict']
292 # available in environ['pylons.routes_dict']
291 try:
293 try:
292 self.ip_addr = _get_ip_addr(environ)
294 self.ip_addr = _get_ip_addr(environ)
293 # make sure that we update permissions each time we call controller
295 # make sure that we update permissions each time we call controller
294 api_key = request.GET.get('api_key')
296 api_key = request.GET.get('api_key')
295 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
297 cookie_store = CookieStoreWrapper(session.get('rhodecode_user'))
296 user_id = cookie_store.get('user_id', None)
298 user_id = cookie_store.get('user_id', None)
297 username = get_container_username(environ, config)
299 username = get_container_username(environ, config)
298 auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
300 auth_user = AuthUser(user_id, api_key, username, self.ip_addr)
299 request.user = auth_user
301 request.user = auth_user
300 self.rhodecode_user = c.rhodecode_user = auth_user
302 self.rhodecode_user = c.rhodecode_user = auth_user
301 if not self.rhodecode_user.is_authenticated and \
303 if not self.rhodecode_user.is_authenticated and \
302 self.rhodecode_user.user_id is not None:
304 self.rhodecode_user.user_id is not None:
303 self.rhodecode_user.set_authenticated(
305 self.rhodecode_user.set_authenticated(
304 cookie_store.get('is_authenticated')
306 cookie_store.get('is_authenticated')
305 )
307 )
306 log.info('IP: %s User: %s accessed %s' % (
308 log.info('IP: %s User: %s accessed %s' % (
307 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
309 self.ip_addr, auth_user, safe_unicode(_get_access_path(environ)))
308 )
310 )
309 return WSGIController.__call__(self, environ, start_response)
311 return WSGIController.__call__(self, environ, start_response)
310 finally:
312 finally:
311 meta.Session.remove()
313 meta.Session.remove()
312
314
313
315
314 class BaseRepoController(BaseController):
316 class BaseRepoController(BaseController):
315 """
317 """
316 Base class for controllers responsible for loading all needed data for
318 Base class for controllers responsible for loading all needed data for
317 repository loaded items are
319 repository loaded items are
318
320
319 c.rhodecode_repo: instance of scm repository
321 c.rhodecode_repo: instance of scm repository
320 c.rhodecode_db_repo: instance of db
322 c.rhodecode_db_repo: instance of db
321 c.repository_followers: number of followers
323 c.repository_followers: number of followers
322 c.repository_forks: number of forks
324 c.repository_forks: number of forks
323 c.repository_following: weather the current user is following the current repo
325 c.repository_following: weather the current user is following the current repo
324 """
326 """
325
327
326 def __before__(self):
328 def __before__(self):
327 super(BaseRepoController, self).__before__()
329 super(BaseRepoController, self).__before__()
328 if c.repo_name:
330 if c.repo_name:
329
331
330 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
332 dbr = c.rhodecode_db_repo = Repository.get_by_repo_name(c.repo_name)
331 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
333 c.rhodecode_repo = c.rhodecode_db_repo.scm_instance
332 # update last change according to VCS data
334 # update last change according to VCS data
333 dbr.update_changeset_cache(dbr.get_changeset())
335 dbr.update_changeset_cache(dbr.get_changeset())
334 if c.rhodecode_repo is None:
336 if c.rhodecode_repo is None:
335 log.error('%s this repository is present in database but it '
337 log.error('%s this repository is present in database but it '
336 'cannot be created as an scm instance', c.repo_name)
338 'cannot be created as an scm instance', c.repo_name)
337
339
338 redirect(url('home'))
340 redirect(url('home'))
339
341
340 # some globals counter for menu
342 # some globals counter for menu
341 c.repository_followers = self.scm_model.get_followers(dbr)
343 c.repository_followers = self.scm_model.get_followers(dbr)
342 c.repository_forks = self.scm_model.get_forks(dbr)
344 c.repository_forks = self.scm_model.get_forks(dbr)
343 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
345 c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
344 c.repository_following = self.scm_model.is_following_repo(c.repo_name,
346 c.repository_following = self.scm_model.is_following_repo(c.repo_name,
345 self.rhodecode_user.user_id)
347 self.rhodecode_user.user_id)
@@ -1,711 +1,712 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.db_manage
3 rhodecode.lib.db_manage
4 ~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Database creation, and setup module for RhodeCode. Used for creation
6 Database creation, and setup module for RhodeCode. Used for creation
7 of database as well as for migration operations
7 of database as well as for migration operations
8
8
9 :created_on: Apr 10, 2010
9 :created_on: Apr 10, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 import sys
28 import sys
29 import time
29 import time
30 import uuid
30 import uuid
31 import logging
31 import logging
32 from os.path import dirname as dn, join as jn
32 from os.path import dirname as dn, join as jn
33
33
34 from rhodecode import __dbversion__, __py_version__
34 from rhodecode import __dbversion__, __py_version__
35
35
36 from rhodecode.model.user import UserModel
36 from rhodecode.model.user import UserModel
37 from rhodecode.lib.utils import ask_ok
37 from rhodecode.lib.utils import ask_ok
38 from rhodecode.model import init_model
38 from rhodecode.model import init_model
39 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
39 from rhodecode.model.db import User, Permission, RhodeCodeUi, \
40 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
40 RhodeCodeSetting, UserToPerm, DbMigrateVersion, RepoGroup, \
41 UserRepoGroupToPerm, CacheInvalidation, UserGroup
41 UserRepoGroupToPerm, CacheInvalidation, UserGroup
42
42
43 from sqlalchemy.engine import create_engine
43 from sqlalchemy.engine import create_engine
44 from rhodecode.model.repos_group import ReposGroupModel
44 from rhodecode.model.repos_group import ReposGroupModel
45 #from rhodecode.model import meta
45 #from rhodecode.model import meta
46 from rhodecode.model.meta import Session, Base
46 from rhodecode.model.meta import Session, Base
47 from rhodecode.model.repo import RepoModel
47 from rhodecode.model.repo import RepoModel
48 from rhodecode.model.permission import PermissionModel
48 from rhodecode.model.permission import PermissionModel
49 from rhodecode.model.users_group import UserGroupModel
49 from rhodecode.model.users_group import UserGroupModel
50
50
51
51
52 log = logging.getLogger(__name__)
52 log = logging.getLogger(__name__)
53
53
54
54
55 def notify(msg):
55 def notify(msg):
56 """
56 """
57 Notification for migrations messages
57 Notification for migrations messages
58 """
58 """
59 ml = len(msg) + (4 * 2)
59 ml = len(msg) + (4 * 2)
60 print('\n%s\n*** %s ***\n%s' % ('*' * ml, msg, '*' * ml)).upper()
60 print('\n%s\n*** %s ***\n%s' % ('*' * ml, msg, '*' * ml)).upper()
61
61
62
62
63 class UpgradeSteps(object):
63 class UpgradeSteps(object):
64 """
64 """
65 Those steps follow schema versions so for example schema
65 Those steps follow schema versions so for example schema
66 for example schema with seq 002 == step_2 and so on.
66 for example schema with seq 002 == step_2 and so on.
67 """
67 """
68
68
69 def __init__(self, klass):
69 def __init__(self, klass):
70 self.klass = klass
70 self.klass = klass
71
71
72 def step_1(self):
72 def step_1(self):
73 pass
73 pass
74
74
75 def step_2(self):
75 def step_2(self):
76 notify('Patching repo paths for newer version of RhodeCode')
76 notify('Patching repo paths for newer version of RhodeCode')
77 self.klass.fix_repo_paths()
77 self.klass.fix_repo_paths()
78
78
79 notify('Patching default user of RhodeCode')
79 notify('Patching default user of RhodeCode')
80 self.klass.fix_default_user()
80 self.klass.fix_default_user()
81
81
82 log.info('Changing ui settings')
82 log.info('Changing ui settings')
83 self.klass.create_ui_settings()
83 self.klass.create_ui_settings()
84
84
85 def step_3(self):
85 def step_3(self):
86 notify('Adding additional settings into RhodeCode db')
86 notify('Adding additional settings into RhodeCode db')
87 self.klass.fix_settings()
87 self.klass.fix_settings()
88 notify('Adding ldap defaults')
88 notify('Adding ldap defaults')
89 self.klass.create_ldap_options(skip_existing=True)
89 self.klass.create_ldap_options(skip_existing=True)
90
90
91 def step_4(self):
91 def step_4(self):
92 notify('create permissions and fix groups')
92 notify('create permissions and fix groups')
93 self.klass.create_permissions()
93 self.klass.create_permissions()
94 self.klass.fixup_groups()
94 self.klass.fixup_groups()
95
95
96 def step_5(self):
96 def step_5(self):
97 pass
97 pass
98
98
99 def step_6(self):
99 def step_6(self):
100
100
101 notify('re-checking permissions')
101 notify('re-checking permissions')
102 self.klass.create_permissions()
102 self.klass.create_permissions()
103
103
104 notify('installing new UI options')
104 notify('installing new UI options')
105 sett4 = RhodeCodeSetting('show_public_icon', True)
105 sett4 = RhodeCodeSetting('show_public_icon', True)
106 Session().add(sett4)
106 Session().add(sett4)
107 sett5 = RhodeCodeSetting('show_private_icon', True)
107 sett5 = RhodeCodeSetting('show_private_icon', True)
108 Session().add(sett5)
108 Session().add(sett5)
109 sett6 = RhodeCodeSetting('stylify_metatags', False)
109 sett6 = RhodeCodeSetting('stylify_metatags', False)
110 Session().add(sett6)
110 Session().add(sett6)
111
111
112 notify('fixing old PULL hook')
112 notify('fixing old PULL hook')
113 _pull = RhodeCodeUi.get_by_key('preoutgoing.pull_logger')
113 _pull = RhodeCodeUi.get_by_key('preoutgoing.pull_logger')
114 if _pull:
114 if _pull:
115 _pull.ui_key = RhodeCodeUi.HOOK_PULL
115 _pull.ui_key = RhodeCodeUi.HOOK_PULL
116 Session().add(_pull)
116 Session().add(_pull)
117
117
118 notify('fixing old PUSH hook')
118 notify('fixing old PUSH hook')
119 _push = RhodeCodeUi.get_by_key('pretxnchangegroup.push_logger')
119 _push = RhodeCodeUi.get_by_key('pretxnchangegroup.push_logger')
120 if _push:
120 if _push:
121 _push.ui_key = RhodeCodeUi.HOOK_PUSH
121 _push.ui_key = RhodeCodeUi.HOOK_PUSH
122 Session().add(_push)
122 Session().add(_push)
123
123
124 notify('installing new pre-push hook')
124 notify('installing new pre-push hook')
125 hooks4 = RhodeCodeUi()
125 hooks4 = RhodeCodeUi()
126 hooks4.ui_section = 'hooks'
126 hooks4.ui_section = 'hooks'
127 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
127 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
128 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
128 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
129 Session().add(hooks4)
129 Session().add(hooks4)
130
130
131 notify('installing new pre-pull hook')
131 notify('installing new pre-pull hook')
132 hooks6 = RhodeCodeUi()
132 hooks6 = RhodeCodeUi()
133 hooks6.ui_section = 'hooks'
133 hooks6.ui_section = 'hooks'
134 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
134 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
135 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
135 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
136 Session().add(hooks6)
136 Session().add(hooks6)
137
137
138 notify('installing hgsubversion option')
138 notify('installing hgsubversion option')
139 # enable hgsubversion disabled by default
139 # enable hgsubversion disabled by default
140 hgsubversion = RhodeCodeUi()
140 hgsubversion = RhodeCodeUi()
141 hgsubversion.ui_section = 'extensions'
141 hgsubversion.ui_section = 'extensions'
142 hgsubversion.ui_key = 'hgsubversion'
142 hgsubversion.ui_key = 'hgsubversion'
143 hgsubversion.ui_value = ''
143 hgsubversion.ui_value = ''
144 hgsubversion.ui_active = False
144 hgsubversion.ui_active = False
145 Session().add(hgsubversion)
145 Session().add(hgsubversion)
146
146
147 notify('installing hg git option')
147 notify('installing hg git option')
148 # enable hggit disabled by default
148 # enable hggit disabled by default
149 hggit = RhodeCodeUi()
149 hggit = RhodeCodeUi()
150 hggit.ui_section = 'extensions'
150 hggit.ui_section = 'extensions'
151 hggit.ui_key = 'hggit'
151 hggit.ui_key = 'hggit'
152 hggit.ui_value = ''
152 hggit.ui_value = ''
153 hggit.ui_active = False
153 hggit.ui_active = False
154 Session().add(hggit)
154 Session().add(hggit)
155
155
156 notify('re-check default permissions')
156 notify('re-check default permissions')
157 default_user = User.get_by_username(User.DEFAULT_USER)
157 default_user = User.get_by_username(User.DEFAULT_USER)
158 perm = Permission.get_by_key('hg.fork.repository')
158 perm = Permission.get_by_key('hg.fork.repository')
159 reg_perm = UserToPerm()
159 reg_perm = UserToPerm()
160 reg_perm.user = default_user
160 reg_perm.user = default_user
161 reg_perm.permission = perm
161 reg_perm.permission = perm
162 Session().add(reg_perm)
162 Session().add(reg_perm)
163
163
164 def step_7(self):
164 def step_7(self):
165 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
165 perm_fixes = self.klass.reset_permissions(User.DEFAULT_USER)
166 Session().commit()
166 Session().commit()
167 if perm_fixes:
167 if perm_fixes:
168 notify('There was an inconsistent state of permissions '
168 notify('There was an inconsistent state of permissions '
169 'detected for default user. Permissions are now '
169 'detected for default user. Permissions are now '
170 'reset to the default value for default user. '
170 'reset to the default value for default user. '
171 'Please validate and check default permissions '
171 'Please validate and check default permissions '
172 'in admin panel')
172 'in admin panel')
173
173
174 def step_8(self):
174 def step_8(self):
175 self.klass.create_permissions()
175 self.klass.create_permissions()
176 self.klass.populate_default_permissions()
176 self.klass.populate_default_permissions()
177 self.klass.create_default_options(skip_existing=True)
177 self.klass.create_default_options(skip_existing=True)
178 Session().commit()
178 Session().commit()
179
179
180 def step_9(self):
180 def step_9(self):
181 pass
181 pass
182
182
183 def step_10(self):
183 def step_10(self):
184 pass
184 pass
185
185
186 def step_11(self):
186 def step_11(self):
187 self.klass.update_repo_info()
187 self.klass.update_repo_info()
188
188
189 def step_12(self):
189 def step_12(self):
190 self.klass.create_permissions()
190 self.klass.create_permissions()
191 Session().commit()
191 Session().commit()
192
192
193 self.klass.populate_default_permissions()
193 self.klass.populate_default_permissions()
194 Session().commit()
194 Session().commit()
195
195
196 #fix all usergroups
196 #fix all usergroups
197 ug_model = UserGroupModel()
197 ug_model = UserGroupModel()
198 for ug in UserGroup.get_all():
198 for ug in UserGroup.get_all():
199 perm_obj = ug_model._create_default_perms(ug)
199 perm_obj = ug_model._create_default_perms(ug)
200 Session().add(perm_obj)
200 Session().add(perm_obj)
201 Session().commit()
201 Session().commit()
202
202
203 adm = User.get_first_admin()
203 adm = User.get_first_admin()
204 # fix owners of UserGroup
204 # fix owners of UserGroup
205 for ug in Session().query(UserGroup).all():
205 for ug in Session().query(UserGroup).all():
206 ug.user_id = adm.user_id
206 ug.user_id = adm.user_id
207 Session().add(ug)
207 Session().add(ug)
208 Session().commit()
208 Session().commit()
209
209
210 # fix owners of RepoGroup
210 # fix owners of RepoGroup
211 for ug in Session().query(RepoGroup).all():
211 for ug in Session().query(RepoGroup).all():
212 ug.user_id = adm.user_id
212 ug.user_id = adm.user_id
213 Session().add(ug)
213 Session().add(ug)
214 Session().commit()
214 Session().commit()
215
215
216 def step_13(self):
216 def step_13(self):
217 pass
217 pass
218
218
219
219
220 class DbManage(object):
220 class DbManage(object):
221 def __init__(self, log_sql, dbconf, root, tests=False, cli_args={}):
221 def __init__(self, log_sql, dbconf, root, tests=False, cli_args={}):
222 self.dbname = dbconf.split('/')[-1]
222 self.dbname = dbconf.split('/')[-1]
223 self.tests = tests
223 self.tests = tests
224 self.root = root
224 self.root = root
225 self.dburi = dbconf
225 self.dburi = dbconf
226 self.log_sql = log_sql
226 self.log_sql = log_sql
227 self.db_exists = False
227 self.db_exists = False
228 self.cli_args = cli_args
228 self.cli_args = cli_args
229 self.init_db()
229 self.init_db()
230
230
231 force_ask = self.cli_args.get('force_ask')
231 force_ask = self.cli_args.get('force_ask')
232 if force_ask is not None:
232 if force_ask is not None:
233 global ask_ok
233 global ask_ok
234 ask_ok = lambda *args, **kwargs: force_ask
234 ask_ok = lambda *args, **kwargs: force_ask
235
235
236 def init_db(self):
236 def init_db(self):
237 engine = create_engine(self.dburi, echo=self.log_sql)
237 engine = create_engine(self.dburi, echo=self.log_sql)
238 init_model(engine)
238 init_model(engine)
239 self.sa = Session()
239 self.sa = Session()
240
240
241 def create_tables(self, override=False):
241 def create_tables(self, override=False):
242 """
242 """
243 Create a auth database
243 Create a auth database
244 """
244 """
245
245
246 log.info("Any existing database is going to be destroyed")
246 log.info("Any existing database is going to be destroyed")
247 if self.tests:
247 if self.tests:
248 destroy = True
248 destroy = True
249 else:
249 else:
250 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
250 destroy = ask_ok('Are you sure to destroy old database ? [y/n]')
251 if not destroy:
251 if not destroy:
252 sys.exit('Nothing tables created')
252 sys.exit('Nothing tables created')
253 if destroy:
253 if destroy:
254 Base.metadata.drop_all()
254 Base.metadata.drop_all()
255
255
256 checkfirst = not override
256 checkfirst = not override
257 Base.metadata.create_all(checkfirst=checkfirst)
257 Base.metadata.create_all(checkfirst=checkfirst)
258 log.info('Created tables for %s' % self.dbname)
258 log.info('Created tables for %s' % self.dbname)
259
259
260 def set_db_version(self):
260 def set_db_version(self):
261 ver = DbMigrateVersion()
261 ver = DbMigrateVersion()
262 ver.version = __dbversion__
262 ver.version = __dbversion__
263 ver.repository_id = 'rhodecode_db_migrations'
263 ver.repository_id = 'rhodecode_db_migrations'
264 ver.repository_path = 'versions'
264 ver.repository_path = 'versions'
265 self.sa.add(ver)
265 self.sa.add(ver)
266 log.info('db version set to: %s' % __dbversion__)
266 log.info('db version set to: %s' % __dbversion__)
267
267
268 def upgrade(self):
268 def upgrade(self):
269 """
269 """
270 Upgrades given database schema to given revision following
270 Upgrades given database schema to given revision following
271 all needed steps, to perform the upgrade
271 all needed steps, to perform the upgrade
272
272
273 """
273 """
274
274
275 from rhodecode.lib.dbmigrate.migrate.versioning import api
275 from rhodecode.lib.dbmigrate.migrate.versioning import api
276 from rhodecode.lib.dbmigrate.migrate.exceptions import \
276 from rhodecode.lib.dbmigrate.migrate.exceptions import \
277 DatabaseNotControlledError
277 DatabaseNotControlledError
278
278
279 if 'sqlite' in self.dburi:
279 if 'sqlite' in self.dburi:
280 print (
280 print (
281 '********************** WARNING **********************\n'
281 '********************** WARNING **********************\n'
282 'Make sure your version of sqlite is at least 3.7.X. \n'
282 'Make sure your version of sqlite is at least 3.7.X. \n'
283 'Earlier versions are known to fail on some migrations\n'
283 'Earlier versions are known to fail on some migrations\n'
284 '*****************************************************\n'
284 '*****************************************************\n'
285 )
285 )
286 upgrade = ask_ok('You are about to perform database upgrade, make '
286 upgrade = ask_ok('You are about to perform database upgrade, make '
287 'sure You backed up your database before. '
287 'sure You backed up your database before. '
288 'Continue ? [y/n]')
288 'Continue ? [y/n]')
289 if not upgrade:
289 if not upgrade:
290 sys.exit('No upgrade performed')
290 sys.exit('No upgrade performed')
291
291
292 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
292 repository_path = jn(dn(dn(dn(os.path.realpath(__file__)))),
293 'rhodecode/lib/dbmigrate')
293 'rhodecode/lib/dbmigrate')
294 db_uri = self.dburi
294 db_uri = self.dburi
295
295
296 try:
296 try:
297 curr_version = api.db_version(db_uri, repository_path)
297 curr_version = api.db_version(db_uri, repository_path)
298 msg = ('Found current database under version'
298 msg = ('Found current database under version'
299 ' control with version %s' % curr_version)
299 ' control with version %s' % curr_version)
300
300
301 except (RuntimeError, DatabaseNotControlledError):
301 except (RuntimeError, DatabaseNotControlledError):
302 curr_version = 1
302 curr_version = 1
303 msg = ('Current database is not under version control. Setting'
303 msg = ('Current database is not under version control. Setting'
304 ' as version %s' % curr_version)
304 ' as version %s' % curr_version)
305 api.version_control(db_uri, repository_path, curr_version)
305 api.version_control(db_uri, repository_path, curr_version)
306
306
307 notify(msg)
307 notify(msg)
308
308
309 if curr_version == __dbversion__:
309 if curr_version == __dbversion__:
310 sys.exit('This database is already at the newest version')
310 sys.exit('This database is already at the newest version')
311
311
312 # clear cache keys
312 # clear cache keys
313 log.info("Clearing cache keys now...")
313 log.info("Clearing cache keys now...")
314 CacheInvalidation.clear_cache()
314 CacheInvalidation.clear_cache()
315
315
316 upgrade_steps = range(curr_version + 1, __dbversion__ + 1)
316 upgrade_steps = range(curr_version + 1, __dbversion__ + 1)
317 notify('attempting to do database upgrade from '
317 notify('attempting to do database upgrade from '
318 'version %s to version %s' % (curr_version, __dbversion__))
318 'version %s to version %s' % (curr_version, __dbversion__))
319
319
320 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
320 # CALL THE PROPER ORDER OF STEPS TO PERFORM FULL UPGRADE
321 _step = None
321 _step = None
322 for step in upgrade_steps:
322 for step in upgrade_steps:
323 notify('performing upgrade step %s' % step)
323 notify('performing upgrade step %s' % step)
324 time.sleep(2)
324 time.sleep(2)
325
325
326 api.upgrade(db_uri, repository_path, step)
326 api.upgrade(db_uri, repository_path, step)
327 notify('schema upgrade for step %s completed' % (step,))
327 notify('schema upgrade for step %s completed' % (step,))
328
328
329 fixture = 'step_%s' % step
329 fixture = 'step_%s' % step
330 notify('performing fixture step %s' % fixture)
330 notify('performing fixture step %s' % fixture)
331 getattr(UpgradeSteps(self), fixture)()
331 getattr(UpgradeSteps(self), fixture)()
332 self.sa.commit()
332 self.sa.commit()
333 notify('fixture %s completed' % (fixture,))
333 notify('fixture %s completed' % (fixture,))
334 _step = step
334 _step = step
335
335
336 notify('upgrade to version %s successful' % _step)
336 notify('upgrade to version %s successful' % _step)
337
337
338 def fix_repo_paths(self):
338 def fix_repo_paths(self):
339 """
339 """
340 Fixes a old rhodecode version path into new one without a '*'
340 Fixes a old rhodecode version path into new one without a '*'
341 """
341 """
342
342
343 paths = self.sa.query(RhodeCodeUi)\
343 paths = self.sa.query(RhodeCodeUi)\
344 .filter(RhodeCodeUi.ui_key == '/')\
344 .filter(RhodeCodeUi.ui_key == '/')\
345 .scalar()
345 .scalar()
346
346
347 paths.ui_value = paths.ui_value.replace('*', '')
347 paths.ui_value = paths.ui_value.replace('*', '')
348
348
349 try:
349 try:
350 self.sa.add(paths)
350 self.sa.add(paths)
351 self.sa.commit()
351 self.sa.commit()
352 except Exception:
352 except Exception:
353 self.sa.rollback()
353 self.sa.rollback()
354 raise
354 raise
355
355
356 def fix_default_user(self):
356 def fix_default_user(self):
357 """
357 """
358 Fixes a old default user with some 'nicer' default values,
358 Fixes a old default user with some 'nicer' default values,
359 used mostly for anonymous access
359 used mostly for anonymous access
360 """
360 """
361 def_user = self.sa.query(User)\
361 def_user = self.sa.query(User)\
362 .filter(User.username == 'default')\
362 .filter(User.username == 'default')\
363 .one()
363 .one()
364
364
365 def_user.name = 'Anonymous'
365 def_user.name = 'Anonymous'
366 def_user.lastname = 'User'
366 def_user.lastname = 'User'
367 def_user.email = 'anonymous@rhodecode.org'
367 def_user.email = 'anonymous@rhodecode.org'
368
368
369 try:
369 try:
370 self.sa.add(def_user)
370 self.sa.add(def_user)
371 self.sa.commit()
371 self.sa.commit()
372 except Exception:
372 except Exception:
373 self.sa.rollback()
373 self.sa.rollback()
374 raise
374 raise
375
375
376 def fix_settings(self):
376 def fix_settings(self):
377 """
377 """
378 Fixes rhodecode settings adds ga_code key for google analytics
378 Fixes rhodecode settings adds ga_code key for google analytics
379 """
379 """
380
380
381 hgsettings3 = RhodeCodeSetting('ga_code', '')
381 hgsettings3 = RhodeCodeSetting('ga_code', '')
382
382
383 try:
383 try:
384 self.sa.add(hgsettings3)
384 self.sa.add(hgsettings3)
385 self.sa.commit()
385 self.sa.commit()
386 except Exception:
386 except Exception:
387 self.sa.rollback()
387 self.sa.rollback()
388 raise
388 raise
389
389
390 def admin_prompt(self, second=False):
390 def admin_prompt(self, second=False):
391 if not self.tests:
391 if not self.tests:
392 import getpass
392 import getpass
393
393
394 # defaults
394 # defaults
395 defaults = self.cli_args
395 defaults = self.cli_args
396 username = defaults.get('username')
396 username = defaults.get('username')
397 password = defaults.get('password')
397 password = defaults.get('password')
398 email = defaults.get('email')
398 email = defaults.get('email')
399
399
400 def get_password():
400 def get_password():
401 password = getpass.getpass('Specify admin password '
401 password = getpass.getpass('Specify admin password '
402 '(min 6 chars):')
402 '(min 6 chars):')
403 confirm = getpass.getpass('Confirm password:')
403 confirm = getpass.getpass('Confirm password:')
404
404
405 if password != confirm:
405 if password != confirm:
406 log.error('passwords mismatch')
406 log.error('passwords mismatch')
407 return False
407 return False
408 if len(password) < 6:
408 if len(password) < 6:
409 log.error('password is to short use at least 6 characters')
409 log.error('password is to short use at least 6 characters')
410 return False
410 return False
411
411
412 return password
412 return password
413 if username is None:
413 if username is None:
414 username = raw_input('Specify admin username:')
414 username = raw_input('Specify admin username:')
415 if password is None:
415 if password is None:
416 password = get_password()
416 password = get_password()
417 if not password:
417 if not password:
418 #second try
418 #second try
419 password = get_password()
419 password = get_password()
420 if not password:
420 if not password:
421 sys.exit()
421 sys.exit()
422 if email is None:
422 if email is None:
423 email = raw_input('Specify admin email:')
423 email = raw_input('Specify admin email:')
424 self.create_user(username, password, email, True)
424 self.create_user(username, password, email, True)
425 else:
425 else:
426 log.info('creating admin and regular test users')
426 log.info('creating admin and regular test users')
427 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
427 from rhodecode.tests import TEST_USER_ADMIN_LOGIN, \
428 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
428 TEST_USER_ADMIN_PASS, TEST_USER_ADMIN_EMAIL, \
429 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
429 TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS, \
430 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
430 TEST_USER_REGULAR_EMAIL, TEST_USER_REGULAR2_LOGIN, \
431 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
431 TEST_USER_REGULAR2_PASS, TEST_USER_REGULAR2_EMAIL
432
432
433 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
433 self.create_user(TEST_USER_ADMIN_LOGIN, TEST_USER_ADMIN_PASS,
434 TEST_USER_ADMIN_EMAIL, True)
434 TEST_USER_ADMIN_EMAIL, True)
435
435
436 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
436 self.create_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
437 TEST_USER_REGULAR_EMAIL, False)
437 TEST_USER_REGULAR_EMAIL, False)
438
438
439 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
439 self.create_user(TEST_USER_REGULAR2_LOGIN, TEST_USER_REGULAR2_PASS,
440 TEST_USER_REGULAR2_EMAIL, False)
440 TEST_USER_REGULAR2_EMAIL, False)
441
441
442 def create_ui_settings(self):
442 def create_ui_settings(self):
443 """
443 """
444 Creates ui settings, fills out hooks
444 Creates ui settings, fills out hooks
445 and disables dotencode
445 and disables dotencode
446 """
446 """
447
447
448 #HOOKS
448 #HOOKS
449 hooks1_key = RhodeCodeUi.HOOK_UPDATE
449 hooks1_key = RhodeCodeUi.HOOK_UPDATE
450 hooks1_ = self.sa.query(RhodeCodeUi)\
450 hooks1_ = self.sa.query(RhodeCodeUi)\
451 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
451 .filter(RhodeCodeUi.ui_key == hooks1_key).scalar()
452
452
453 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
453 hooks1 = RhodeCodeUi() if hooks1_ is None else hooks1_
454 hooks1.ui_section = 'hooks'
454 hooks1.ui_section = 'hooks'
455 hooks1.ui_key = hooks1_key
455 hooks1.ui_key = hooks1_key
456 hooks1.ui_value = 'hg update >&2'
456 hooks1.ui_value = 'hg update >&2'
457 hooks1.ui_active = False
457 hooks1.ui_active = False
458 self.sa.add(hooks1)
458 self.sa.add(hooks1)
459
459
460 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
460 hooks2_key = RhodeCodeUi.HOOK_REPO_SIZE
461 hooks2_ = self.sa.query(RhodeCodeUi)\
461 hooks2_ = self.sa.query(RhodeCodeUi)\
462 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
462 .filter(RhodeCodeUi.ui_key == hooks2_key).scalar()
463 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
463 hooks2 = RhodeCodeUi() if hooks2_ is None else hooks2_
464 hooks2.ui_section = 'hooks'
464 hooks2.ui_section = 'hooks'
465 hooks2.ui_key = hooks2_key
465 hooks2.ui_key = hooks2_key
466 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
466 hooks2.ui_value = 'python:rhodecode.lib.hooks.repo_size'
467 self.sa.add(hooks2)
467 self.sa.add(hooks2)
468
468
469 hooks3 = RhodeCodeUi()
469 hooks3 = RhodeCodeUi()
470 hooks3.ui_section = 'hooks'
470 hooks3.ui_section = 'hooks'
471 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
471 hooks3.ui_key = RhodeCodeUi.HOOK_PUSH
472 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
472 hooks3.ui_value = 'python:rhodecode.lib.hooks.log_push_action'
473 self.sa.add(hooks3)
473 self.sa.add(hooks3)
474
474
475 hooks4 = RhodeCodeUi()
475 hooks4 = RhodeCodeUi()
476 hooks4.ui_section = 'hooks'
476 hooks4.ui_section = 'hooks'
477 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
477 hooks4.ui_key = RhodeCodeUi.HOOK_PRE_PUSH
478 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
478 hooks4.ui_value = 'python:rhodecode.lib.hooks.pre_push'
479 self.sa.add(hooks4)
479 self.sa.add(hooks4)
480
480
481 hooks5 = RhodeCodeUi()
481 hooks5 = RhodeCodeUi()
482 hooks5.ui_section = 'hooks'
482 hooks5.ui_section = 'hooks'
483 hooks5.ui_key = RhodeCodeUi.HOOK_PULL
483 hooks5.ui_key = RhodeCodeUi.HOOK_PULL
484 hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
484 hooks5.ui_value = 'python:rhodecode.lib.hooks.log_pull_action'
485 self.sa.add(hooks5)
485 self.sa.add(hooks5)
486
486
487 hooks6 = RhodeCodeUi()
487 hooks6 = RhodeCodeUi()
488 hooks6.ui_section = 'hooks'
488 hooks6.ui_section = 'hooks'
489 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
489 hooks6.ui_key = RhodeCodeUi.HOOK_PRE_PULL
490 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
490 hooks6.ui_value = 'python:rhodecode.lib.hooks.pre_pull'
491 self.sa.add(hooks6)
491 self.sa.add(hooks6)
492
492
493 # enable largefiles
493 # enable largefiles
494 largefiles = RhodeCodeUi()
494 largefiles = RhodeCodeUi()
495 largefiles.ui_section = 'extensions'
495 largefiles.ui_section = 'extensions'
496 largefiles.ui_key = 'largefiles'
496 largefiles.ui_key = 'largefiles'
497 largefiles.ui_value = ''
497 largefiles.ui_value = ''
498 self.sa.add(largefiles)
498 self.sa.add(largefiles)
499
499
500 # enable hgsubversion disabled by default
500 # enable hgsubversion disabled by default
501 hgsubversion = RhodeCodeUi()
501 hgsubversion = RhodeCodeUi()
502 hgsubversion.ui_section = 'extensions'
502 hgsubversion.ui_section = 'extensions'
503 hgsubversion.ui_key = 'hgsubversion'
503 hgsubversion.ui_key = 'hgsubversion'
504 hgsubversion.ui_value = ''
504 hgsubversion.ui_value = ''
505 hgsubversion.ui_active = False
505 hgsubversion.ui_active = False
506 self.sa.add(hgsubversion)
506 self.sa.add(hgsubversion)
507
507
508 # enable hggit disabled by default
508 # enable hggit disabled by default
509 hggit = RhodeCodeUi()
509 hggit = RhodeCodeUi()
510 hggit.ui_section = 'extensions'
510 hggit.ui_section = 'extensions'
511 hggit.ui_key = 'hggit'
511 hggit.ui_key = 'hggit'
512 hggit.ui_value = ''
512 hggit.ui_value = ''
513 hggit.ui_active = False
513 hggit.ui_active = False
514 self.sa.add(hggit)
514 self.sa.add(hggit)
515
515
516 def create_ldap_options(self, skip_existing=False):
516 def create_ldap_options(self, skip_existing=False):
517 """Creates ldap settings"""
517 """Creates ldap settings"""
518
518
519 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
519 for k, v in [('ldap_active', 'false'), ('ldap_host', ''),
520 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
520 ('ldap_port', '389'), ('ldap_tls_kind', 'PLAIN'),
521 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
521 ('ldap_tls_reqcert', ''), ('ldap_dn_user', ''),
522 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
522 ('ldap_dn_pass', ''), ('ldap_base_dn', ''),
523 ('ldap_filter', ''), ('ldap_search_scope', ''),
523 ('ldap_filter', ''), ('ldap_search_scope', ''),
524 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
524 ('ldap_attr_login', ''), ('ldap_attr_firstname', ''),
525 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
525 ('ldap_attr_lastname', ''), ('ldap_attr_email', '')]:
526
526
527 if skip_existing and RhodeCodeSetting.get_by_name(k) is not None:
527 if skip_existing and RhodeCodeSetting.get_by_name(k) is not None:
528 log.debug('Skipping option %s' % k)
528 log.debug('Skipping option %s' % k)
529 continue
529 continue
530 setting = RhodeCodeSetting(k, v)
530 setting = RhodeCodeSetting(k, v)
531 self.sa.add(setting)
531 self.sa.add(setting)
532
532
533 def create_default_options(self, skip_existing=False):
533 def create_default_options(self, skip_existing=False):
534 """Creates default settings"""
534 """Creates default settings"""
535
535
536 for k, v in [
536 for k, v in [
537 ('default_repo_enable_locking', False),
537 ('default_repo_enable_locking', False),
538 ('default_repo_enable_downloads', False),
538 ('default_repo_enable_downloads', False),
539 ('default_repo_enable_statistics', False),
539 ('default_repo_enable_statistics', False),
540 ('default_repo_private', False),
540 ('default_repo_private', False),
541 ('default_repo_type', 'hg')]:
541 ('default_repo_type', 'hg')]:
542
542
543 if skip_existing and RhodeCodeSetting.get_by_name(k) is not None:
543 if skip_existing and RhodeCodeSetting.get_by_name(k) is not None:
544 log.debug('Skipping option %s' % k)
544 log.debug('Skipping option %s' % k)
545 continue
545 continue
546 setting = RhodeCodeSetting(k, v)
546 setting = RhodeCodeSetting(k, v)
547 self.sa.add(setting)
547 self.sa.add(setting)
548
548
549 def fixup_groups(self):
549 def fixup_groups(self):
550 def_usr = User.get_default_user()
550 def_usr = User.get_default_user()
551 for g in RepoGroup.query().all():
551 for g in RepoGroup.query().all():
552 g.group_name = g.get_new_name(g.name)
552 g.group_name = g.get_new_name(g.name)
553 self.sa.add(g)
553 self.sa.add(g)
554 # get default perm
554 # get default perm
555 default = UserRepoGroupToPerm.query()\
555 default = UserRepoGroupToPerm.query()\
556 .filter(UserRepoGroupToPerm.group == g)\
556 .filter(UserRepoGroupToPerm.group == g)\
557 .filter(UserRepoGroupToPerm.user == def_usr)\
557 .filter(UserRepoGroupToPerm.user == def_usr)\
558 .scalar()
558 .scalar()
559
559
560 if default is None:
560 if default is None:
561 log.debug('missing default permission for group %s adding' % g)
561 log.debug('missing default permission for group %s adding' % g)
562 perm_obj = ReposGroupModel()._create_default_perms(g)
562 perm_obj = ReposGroupModel()._create_default_perms(g)
563 self.sa.add(perm_obj)
563 self.sa.add(perm_obj)
564
564
565 def reset_permissions(self, username):
565 def reset_permissions(self, username):
566 """
566 """
567 Resets permissions to default state, usefull when old systems had
567 Resets permissions to default state, usefull when old systems had
568 bad permissions, we must clean them up
568 bad permissions, we must clean them up
569
569
570 :param username:
570 :param username:
571 """
571 """
572 default_user = User.get_by_username(username)
572 default_user = User.get_by_username(username)
573 if not default_user:
573 if not default_user:
574 return
574 return
575
575
576 u2p = UserToPerm.query()\
576 u2p = UserToPerm.query()\
577 .filter(UserToPerm.user == default_user).all()
577 .filter(UserToPerm.user == default_user).all()
578 fixed = False
578 fixed = False
579 if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
579 if len(u2p) != len(Permission.DEFAULT_USER_PERMISSIONS):
580 for p in u2p:
580 for p in u2p:
581 Session().delete(p)
581 Session().delete(p)
582 fixed = True
582 fixed = True
583 self.populate_default_permissions()
583 self.populate_default_permissions()
584 return fixed
584 return fixed
585
585
586 def update_repo_info(self):
586 def update_repo_info(self):
587 RepoModel.update_repoinfo()
587 RepoModel.update_repoinfo()
588
588
589 def config_prompt(self, test_repo_path='', retries=3):
589 def config_prompt(self, test_repo_path='', retries=3):
590 defaults = self.cli_args
590 defaults = self.cli_args
591 _path = defaults.get('repos_location')
591 _path = defaults.get('repos_location')
592 if retries == 3:
592 if retries == 3:
593 log.info('Setting up repositories config')
593 log.info('Setting up repositories config')
594
594
595 if _path is not None:
595 if _path is not None:
596 path = _path
596 path = _path
597 elif not self.tests and not test_repo_path:
597 elif not self.tests and not test_repo_path:
598 path = raw_input(
598 path = raw_input(
599 'Enter a valid absolute path to store repositories. '
599 'Enter a valid absolute path to store repositories. '
600 'All repositories in that path will be added automatically:'
600 'All repositories in that path will be added automatically:'
601 )
601 )
602 else:
602 else:
603 path = test_repo_path
603 path = test_repo_path
604 path_ok = True
604 path_ok = True
605
605
606 # check proper dir
606 # check proper dir
607 if not os.path.isdir(path):
607 if not os.path.isdir(path):
608 path_ok = False
608 path_ok = False
609 log.error('Given path %s is not a valid directory' % path)
609 log.error('Given path %s is not a valid directory' % path)
610
610
611 elif not os.path.isabs(path):
611 elif not os.path.isabs(path):
612 path_ok = False
612 path_ok = False
613 log.error('Given path %s is not an absolute path' % path)
613 log.error('Given path %s is not an absolute path' % path)
614
614
615 # check write access
615 # check write access
616 elif not os.access(path, os.W_OK) and path_ok:
616 elif not os.access(path, os.W_OK) and path_ok:
617 path_ok = False
617 path_ok = False
618 log.error('No write permission to given path %s' % path)
618 log.error('No write permission to given path %s' % path)
619
619
620 if retries == 0:
620 if retries == 0:
621 sys.exit('max retries reached')
621 sys.exit('max retries reached')
622 if not path_ok:
622 if not path_ok:
623 retries -= 1
623 retries -= 1
624 return self.config_prompt(test_repo_path, retries)
624 return self.config_prompt(test_repo_path, retries)
625
625
626 real_path = os.path.normpath(os.path.realpath(path))
626 real_path = os.path.normpath(os.path.realpath(path))
627
627
628 if real_path != os.path.normpath(path):
628 if real_path != os.path.normpath(path):
629 if not ask_ok(('Path looks like a symlink, Rhodecode will store '
629 if not ask_ok(('Path looks like a symlink, Rhodecode will store '
630 'given path as %s ? [y/n]') % (real_path)):
630 'given path as %s ? [y/n]') % (real_path)):
631 log.error('Canceled by user')
631 log.error('Canceled by user')
632 sys.exit(-1)
632 sys.exit(-1)
633
633
634 return real_path
634 return real_path
635
635
636 def create_settings(self, path):
636 def create_settings(self, path):
637
637
638 self.create_ui_settings()
638 self.create_ui_settings()
639
639
640 ui_config = [
640 ui_config = [
641 ('web', 'push_ssl', 'false'),
641 ('web', 'push_ssl', 'false'),
642 ('web', 'allow_archive', 'gz zip bz2'),
642 ('web', 'allow_archive', 'gz zip bz2'),
643 ('web', 'allow_push', '*'),
643 ('web', 'allow_push', '*'),
644 ('web', 'baseurl', '/'),
644 ('web', 'baseurl', '/'),
645 ('paths', '/', path),
645 ('paths', '/', path),
646 #('phases', 'publish', 'false')
646 #('phases', 'publish', 'false')
647 ]
647 ]
648 for section,key,value in ui_config:
648 for section,key,value in ui_config:
649 ui_conf = RhodeCodeUi()
649 ui_conf = RhodeCodeUi()
650 setattr(ui_conf, 'ui_section', section)
650 setattr(ui_conf, 'ui_section', section)
651 setattr(ui_conf, 'ui_key', key)
651 setattr(ui_conf, 'ui_key', key)
652 setattr(ui_conf, 'ui_value', value)
652 setattr(ui_conf, 'ui_value', value)
653
653
654 settings = [
654 settings = [
655 ('realm', 'RhodeCode authentication', unicode),
655 ('realm', 'RhodeCode authentication', unicode),
656 ('title', 'RhodeCode', unicode),
656 ('title', 'RhodeCode', unicode),
657 ('ga_code', '', unicode),
657 ('ga_code', '', unicode),
658 ('show_public_icon', True, bool),
658 ('show_public_icon', True, bool),
659 ('show_private_icon', True, bool),
659 ('show_private_icon', True, bool),
660 ('stylify_metatags', False, bool),
660 ('stylify_metatags', False, bool),
661 ('dashboard_items', 100, int),
661 ('dashboard_items', 100, int),
662 ('show_version', True, bool)
662 ]
663 ]
663 for key, val, type_ in settings:
664 for key, val, type_ in settings:
664 sett = RhodeCodeSetting(key, val)
665 sett = RhodeCodeSetting(key, val)
665 self.sa.add(sett)
666 self.sa.add(sett)
666
667
667 self.create_ldap_options()
668 self.create_ldap_options()
668 self.create_default_options()
669 self.create_default_options()
669
670
670 log.info('created ui config')
671 log.info('created ui config')
671
672
672 def create_user(self, username, password, email='', admin=False):
673 def create_user(self, username, password, email='', admin=False):
673 log.info('creating user %s' % username)
674 log.info('creating user %s' % username)
674 UserModel().create_or_update(username, password, email,
675 UserModel().create_or_update(username, password, email,
675 firstname='RhodeCode', lastname='Admin',
676 firstname='RhodeCode', lastname='Admin',
676 active=True, admin=admin)
677 active=True, admin=admin)
677
678
678 def create_default_user(self):
679 def create_default_user(self):
679 log.info('creating default user')
680 log.info('creating default user')
680 # create default user for handling default permissions.
681 # create default user for handling default permissions.
681 UserModel().create_or_update(username='default',
682 UserModel().create_or_update(username='default',
682 password=str(uuid.uuid1())[:8],
683 password=str(uuid.uuid1())[:8],
683 email='anonymous@rhodecode.org',
684 email='anonymous@rhodecode.org',
684 firstname='Anonymous', lastname='User')
685 firstname='Anonymous', lastname='User')
685
686
686 def create_permissions(self):
687 def create_permissions(self):
687 """
688 """
688 Creates all permissions defined in the system
689 Creates all permissions defined in the system
689 """
690 """
690 # module.(access|create|change|delete)_[name]
691 # module.(access|create|change|delete)_[name]
691 # module.(none|read|write|admin)
692 # module.(none|read|write|admin)
692 log.info('creating permissions')
693 log.info('creating permissions')
693 PermissionModel(self.sa).create_permissions()
694 PermissionModel(self.sa).create_permissions()
694
695
695 def populate_default_permissions(self):
696 def populate_default_permissions(self):
696 """
697 """
697 Populate default permissions. It will create only the default
698 Populate default permissions. It will create only the default
698 permissions that are missing, and not alter already defined ones
699 permissions that are missing, and not alter already defined ones
699 """
700 """
700 log.info('creating default user permissions')
701 log.info('creating default user permissions')
701 PermissionModel(self.sa).create_default_permissions(user=User.DEFAULT_USER)
702 PermissionModel(self.sa).create_default_permissions(user=User.DEFAULT_USER)
702
703
703 @staticmethod
704 @staticmethod
704 def check_waitress():
705 def check_waitress():
705 """
706 """
706 Function executed at the end of setup
707 Function executed at the end of setup
707 """
708 """
708 if not __py_version__ >= (2, 6):
709 if not __py_version__ >= (2, 6):
709 notify('Python2.5 detected, please switch '
710 notify('Python2.5 detected, please switch '
710 'egg:waitress#main -> egg:Paste#http '
711 'egg:waitress#main -> egg:Paste#http '
711 'in your .ini file')
712 'in your .ini file')
@@ -1,437 +1,438 b''
1 """ this is forms validation classes
1 """ this is forms validation classes
2 http://formencode.org/module-formencode.validators.html
2 http://formencode.org/module-formencode.validators.html
3 for list off all availible validators
3 for list off all availible validators
4
4
5 we can create our own validators
5 we can create our own validators
6
6
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
7 The table below outlines the options which can be used in a schema in addition to the validators themselves
8 pre_validators [] These validators will be applied before the schema
8 pre_validators [] These validators will be applied before the schema
9 chained_validators [] These validators will be applied after the schema
9 chained_validators [] These validators will be applied after the schema
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
10 allow_extra_fields False If True, then it is not an error when keys that aren't associated with a validator are present
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
11 filter_extra_fields False If True, then keys that aren't associated with a validator are removed
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
12 if_key_missing NoDefault If this is given, then any keys that aren't available but are expected will be replaced with this value (and then validated). This does not override a present .if_missing attribute on validators. NoDefault is a special FormEncode class to mean that no default values has been specified and therefore missing keys shouldn't take a default value.
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
13 ignore_key_missing False If True, then missing keys will be missing in the result, if the validator doesn't have .if_missing on it already
14
14
15
15
16 <name> = formencode.validators.<name of validator>
16 <name> = formencode.validators.<name of validator>
17 <name> must equal form name
17 <name> must equal form name
18 list=[1,2,3,4,5]
18 list=[1,2,3,4,5]
19 for SELECT use formencode.All(OneOf(list), Int())
19 for SELECT use formencode.All(OneOf(list), Int())
20
20
21 """
21 """
22 import logging
22 import logging
23
23
24 import formencode
24 import formencode
25 from formencode import All
25 from formencode import All
26
26
27 from pylons.i18n.translation import _
27 from pylons.i18n.translation import _
28
28
29 from rhodecode.model import validators as v
29 from rhodecode.model import validators as v
30 from rhodecode import BACKENDS
30 from rhodecode import BACKENDS
31
31
32 log = logging.getLogger(__name__)
32 log = logging.getLogger(__name__)
33
33
34
34
35 class LoginForm(formencode.Schema):
35 class LoginForm(formencode.Schema):
36 allow_extra_fields = True
36 allow_extra_fields = True
37 filter_extra_fields = True
37 filter_extra_fields = True
38 username = v.UnicodeString(
38 username = v.UnicodeString(
39 strip=True,
39 strip=True,
40 min=1,
40 min=1,
41 not_empty=True,
41 not_empty=True,
42 messages={
42 messages={
43 'empty': _(u'Please enter a login'),
43 'empty': _(u'Please enter a login'),
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
44 'tooShort': _(u'Enter a value %(min)i characters long or more')}
45 )
45 )
46
46
47 password = v.UnicodeString(
47 password = v.UnicodeString(
48 strip=False,
48 strip=False,
49 min=3,
49 min=3,
50 not_empty=True,
50 not_empty=True,
51 messages={
51 messages={
52 'empty': _(u'Please enter a password'),
52 'empty': _(u'Please enter a password'),
53 'tooShort': _(u'Enter %(min)i characters or more')}
53 'tooShort': _(u'Enter %(min)i characters or more')}
54 )
54 )
55
55
56 remember = v.StringBoolean(if_missing=False)
56 remember = v.StringBoolean(if_missing=False)
57
57
58 chained_validators = [v.ValidAuth()]
58 chained_validators = [v.ValidAuth()]
59
59
60
60
61 def UserForm(edit=False, old_data={}):
61 def UserForm(edit=False, old_data={}):
62 class _UserForm(formencode.Schema):
62 class _UserForm(formencode.Schema):
63 allow_extra_fields = True
63 allow_extra_fields = True
64 filter_extra_fields = True
64 filter_extra_fields = True
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
65 username = All(v.UnicodeString(strip=True, min=1, not_empty=True),
66 v.ValidUsername(edit, old_data))
66 v.ValidUsername(edit, old_data))
67 if edit:
67 if edit:
68 new_password = All(
68 new_password = All(
69 v.ValidPassword(),
69 v.ValidPassword(),
70 v.UnicodeString(strip=False, min=6, not_empty=False)
70 v.UnicodeString(strip=False, min=6, not_empty=False)
71 )
71 )
72 password_confirmation = All(
72 password_confirmation = All(
73 v.ValidPassword(),
73 v.ValidPassword(),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
74 v.UnicodeString(strip=False, min=6, not_empty=False),
75 )
75 )
76 admin = v.StringBoolean(if_missing=False)
76 admin = v.StringBoolean(if_missing=False)
77 else:
77 else:
78 password = All(
78 password = All(
79 v.ValidPassword(),
79 v.ValidPassword(),
80 v.UnicodeString(strip=False, min=6, not_empty=True)
80 v.UnicodeString(strip=False, min=6, not_empty=True)
81 )
81 )
82 password_confirmation = All(
82 password_confirmation = All(
83 v.ValidPassword(),
83 v.ValidPassword(),
84 v.UnicodeString(strip=False, min=6, not_empty=False)
84 v.UnicodeString(strip=False, min=6, not_empty=False)
85 )
85 )
86
86
87 active = v.StringBoolean(if_missing=False)
87 active = v.StringBoolean(if_missing=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
88 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
89 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
90 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
91
91
92 chained_validators = [v.ValidPasswordsMatch()]
92 chained_validators = [v.ValidPasswordsMatch()]
93
93
94 return _UserForm
94 return _UserForm
95
95
96
96
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
97 def UserGroupForm(edit=False, old_data={}, available_members=[]):
98 class _UserGroupForm(formencode.Schema):
98 class _UserGroupForm(formencode.Schema):
99 allow_extra_fields = True
99 allow_extra_fields = True
100 filter_extra_fields = True
100 filter_extra_fields = True
101
101
102 users_group_name = All(
102 users_group_name = All(
103 v.UnicodeString(strip=True, min=1, not_empty=True),
103 v.UnicodeString(strip=True, min=1, not_empty=True),
104 v.ValidUserGroup(edit, old_data)
104 v.ValidUserGroup(edit, old_data)
105 )
105 )
106
106
107 users_group_active = v.StringBoolean(if_missing=False)
107 users_group_active = v.StringBoolean(if_missing=False)
108
108
109 if edit:
109 if edit:
110 users_group_members = v.OneOf(
110 users_group_members = v.OneOf(
111 available_members, hideList=False, testValueList=True,
111 available_members, hideList=False, testValueList=True,
112 if_missing=None, not_empty=False
112 if_missing=None, not_empty=False
113 )
113 )
114
114
115 return _UserGroupForm
115 return _UserGroupForm
116
116
117
117
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
118 def ReposGroupForm(edit=False, old_data={}, available_groups=[],
119 can_create_in_root=False):
119 can_create_in_root=False):
120 class _ReposGroupForm(formencode.Schema):
120 class _ReposGroupForm(formencode.Schema):
121 allow_extra_fields = True
121 allow_extra_fields = True
122 filter_extra_fields = False
122 filter_extra_fields = False
123
123
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
124 group_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
125 v.SlugifyName())
125 v.SlugifyName())
126 group_description = v.UnicodeString(strip=True, min=1,
126 group_description = v.UnicodeString(strip=True, min=1,
127 not_empty=False)
127 not_empty=False)
128 if edit:
128 if edit:
129 #FIXME: do a special check that we cannot move a group to one of
129 #FIXME: do a special check that we cannot move a group to one of
130 #it's children
130 #it's children
131 pass
131 pass
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
132 group_parent_id = All(v.CanCreateGroup(can_create_in_root),
133 v.OneOf(available_groups, hideList=False,
133 v.OneOf(available_groups, hideList=False,
134 testValueList=True,
134 testValueList=True,
135 if_missing=None, not_empty=True))
135 if_missing=None, not_empty=True))
136 enable_locking = v.StringBoolean(if_missing=False)
136 enable_locking = v.StringBoolean(if_missing=False)
137 chained_validators = [v.ValidReposGroup(edit, old_data)]
137 chained_validators = [v.ValidReposGroup(edit, old_data)]
138
138
139 return _ReposGroupForm
139 return _ReposGroupForm
140
140
141
141
142 def RegisterForm(edit=False, old_data={}):
142 def RegisterForm(edit=False, old_data={}):
143 class _RegisterForm(formencode.Schema):
143 class _RegisterForm(formencode.Schema):
144 allow_extra_fields = True
144 allow_extra_fields = True
145 filter_extra_fields = True
145 filter_extra_fields = True
146 username = All(
146 username = All(
147 v.ValidUsername(edit, old_data),
147 v.ValidUsername(edit, old_data),
148 v.UnicodeString(strip=True, min=1, not_empty=True)
148 v.UnicodeString(strip=True, min=1, not_empty=True)
149 )
149 )
150 password = All(
150 password = All(
151 v.ValidPassword(),
151 v.ValidPassword(),
152 v.UnicodeString(strip=False, min=6, not_empty=True)
152 v.UnicodeString(strip=False, min=6, not_empty=True)
153 )
153 )
154 password_confirmation = All(
154 password_confirmation = All(
155 v.ValidPassword(),
155 v.ValidPassword(),
156 v.UnicodeString(strip=False, min=6, not_empty=True)
156 v.UnicodeString(strip=False, min=6, not_empty=True)
157 )
157 )
158 active = v.StringBoolean(if_missing=False)
158 active = v.StringBoolean(if_missing=False)
159 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
159 firstname = v.UnicodeString(strip=True, min=1, not_empty=False)
160 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
160 lastname = v.UnicodeString(strip=True, min=1, not_empty=False)
161 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
161 email = All(v.Email(not_empty=True), v.UniqSystemEmail(old_data))
162
162
163 chained_validators = [v.ValidPasswordsMatch()]
163 chained_validators = [v.ValidPasswordsMatch()]
164
164
165 return _RegisterForm
165 return _RegisterForm
166
166
167
167
168 def PasswordResetForm():
168 def PasswordResetForm():
169 class _PasswordResetForm(formencode.Schema):
169 class _PasswordResetForm(formencode.Schema):
170 allow_extra_fields = True
170 allow_extra_fields = True
171 filter_extra_fields = True
171 filter_extra_fields = True
172 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
172 email = All(v.ValidSystemEmail(), v.Email(not_empty=True))
173 return _PasswordResetForm
173 return _PasswordResetForm
174
174
175
175
176 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
176 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
177 repo_groups=[], landing_revs=[]):
177 repo_groups=[], landing_revs=[]):
178 class _RepoForm(formencode.Schema):
178 class _RepoForm(formencode.Schema):
179 allow_extra_fields = True
179 allow_extra_fields = True
180 filter_extra_fields = False
180 filter_extra_fields = False
181 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
181 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
182 v.SlugifyName())
182 v.SlugifyName())
183 repo_group = All(v.CanWriteGroup(old_data),
183 repo_group = All(v.CanWriteGroup(old_data),
184 v.OneOf(repo_groups, hideList=True))
184 v.OneOf(repo_groups, hideList=True))
185 repo_type = v.OneOf(supported_backends, required=False,
185 repo_type = v.OneOf(supported_backends, required=False,
186 if_missing=old_data.get('repo_type'))
186 if_missing=old_data.get('repo_type'))
187 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
187 repo_description = v.UnicodeString(strip=True, min=1, not_empty=False)
188 repo_private = v.StringBoolean(if_missing=False)
188 repo_private = v.StringBoolean(if_missing=False)
189 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
189 repo_landing_rev = v.OneOf(landing_revs, hideList=True)
190 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
190 clone_uri = All(v.UnicodeString(strip=True, min=1, not_empty=False))
191
191
192 repo_enable_statistics = v.StringBoolean(if_missing=False)
192 repo_enable_statistics = v.StringBoolean(if_missing=False)
193 repo_enable_downloads = v.StringBoolean(if_missing=False)
193 repo_enable_downloads = v.StringBoolean(if_missing=False)
194 repo_enable_locking = v.StringBoolean(if_missing=False)
194 repo_enable_locking = v.StringBoolean(if_missing=False)
195
195
196 if edit:
196 if edit:
197 #this is repo owner
197 #this is repo owner
198 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
198 user = All(v.UnicodeString(not_empty=True), v.ValidRepoUser())
199
199
200 chained_validators = [v.ValidCloneUri(),
200 chained_validators = [v.ValidCloneUri(),
201 v.ValidRepoName(edit, old_data)]
201 v.ValidRepoName(edit, old_data)]
202 return _RepoForm
202 return _RepoForm
203
203
204
204
205 def RepoPermsForm():
205 def RepoPermsForm():
206 class _RepoPermsForm(formencode.Schema):
206 class _RepoPermsForm(formencode.Schema):
207 allow_extra_fields = True
207 allow_extra_fields = True
208 filter_extra_fields = False
208 filter_extra_fields = False
209 chained_validators = [v.ValidPerms(type_='repo')]
209 chained_validators = [v.ValidPerms(type_='repo')]
210 return _RepoPermsForm
210 return _RepoPermsForm
211
211
212
212
213 def RepoGroupPermsForm():
213 def RepoGroupPermsForm():
214 class _RepoGroupPermsForm(formencode.Schema):
214 class _RepoGroupPermsForm(formencode.Schema):
215 allow_extra_fields = True
215 allow_extra_fields = True
216 filter_extra_fields = False
216 filter_extra_fields = False
217 recursive = v.StringBoolean(if_missing=False)
217 recursive = v.StringBoolean(if_missing=False)
218 chained_validators = [v.ValidPerms(type_='repo_group')]
218 chained_validators = [v.ValidPerms(type_='repo_group')]
219 return _RepoGroupPermsForm
219 return _RepoGroupPermsForm
220
220
221
221
222 def UserGroupPermsForm():
222 def UserGroupPermsForm():
223 class _UserPermsForm(formencode.Schema):
223 class _UserPermsForm(formencode.Schema):
224 allow_extra_fields = True
224 allow_extra_fields = True
225 filter_extra_fields = False
225 filter_extra_fields = False
226 chained_validators = [v.ValidPerms(type_='user_group')]
226 chained_validators = [v.ValidPerms(type_='user_group')]
227 return _UserPermsForm
227 return _UserPermsForm
228
228
229
229
230 def RepoFieldForm():
230 def RepoFieldForm():
231 class _RepoFieldForm(formencode.Schema):
231 class _RepoFieldForm(formencode.Schema):
232 filter_extra_fields = True
232 filter_extra_fields = True
233 allow_extra_fields = True
233 allow_extra_fields = True
234
234
235 new_field_key = All(v.FieldKey(),
235 new_field_key = All(v.FieldKey(),
236 v.UnicodeString(strip=True, min=3, not_empty=True))
236 v.UnicodeString(strip=True, min=3, not_empty=True))
237 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
237 new_field_value = v.UnicodeString(not_empty=False, if_missing='')
238 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
238 new_field_type = v.OneOf(['str', 'unicode', 'list', 'tuple'],
239 if_missing='str')
239 if_missing='str')
240 new_field_label = v.UnicodeString(not_empty=False)
240 new_field_label = v.UnicodeString(not_empty=False)
241 new_field_desc = v.UnicodeString(not_empty=False)
241 new_field_desc = v.UnicodeString(not_empty=False)
242
242
243 return _RepoFieldForm
243 return _RepoFieldForm
244
244
245
245
246 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
246 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
247 repo_groups=[], landing_revs=[]):
247 repo_groups=[], landing_revs=[]):
248 class _RepoForkForm(formencode.Schema):
248 class _RepoForkForm(formencode.Schema):
249 allow_extra_fields = True
249 allow_extra_fields = True
250 filter_extra_fields = False
250 filter_extra_fields = False
251 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
251 repo_name = All(v.UnicodeString(strip=True, min=1, not_empty=True),
252 v.SlugifyName())
252 v.SlugifyName())
253 repo_group = All(v.CanWriteGroup(),
253 repo_group = All(v.CanWriteGroup(),
254 v.OneOf(repo_groups, hideList=True))
254 v.OneOf(repo_groups, hideList=True))
255 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
255 repo_type = All(v.ValidForkType(old_data), v.OneOf(supported_backends))
256 description = v.UnicodeString(strip=True, min=1, not_empty=True)
256 description = v.UnicodeString(strip=True, min=1, not_empty=True)
257 private = v.StringBoolean(if_missing=False)
257 private = v.StringBoolean(if_missing=False)
258 copy_permissions = v.StringBoolean(if_missing=False)
258 copy_permissions = v.StringBoolean(if_missing=False)
259 update_after_clone = v.StringBoolean(if_missing=False)
259 update_after_clone = v.StringBoolean(if_missing=False)
260 fork_parent_id = v.UnicodeString()
260 fork_parent_id = v.UnicodeString()
261 chained_validators = [v.ValidForkName(edit, old_data)]
261 chained_validators = [v.ValidForkName(edit, old_data)]
262 landing_rev = v.OneOf(landing_revs, hideList=True)
262 landing_rev = v.OneOf(landing_revs, hideList=True)
263
263
264 return _RepoForkForm
264 return _RepoForkForm
265
265
266
266
267 def ApplicationSettingsForm():
267 def ApplicationSettingsForm():
268 class _ApplicationSettingsForm(formencode.Schema):
268 class _ApplicationSettingsForm(formencode.Schema):
269 allow_extra_fields = True
269 allow_extra_fields = True
270 filter_extra_fields = False
270 filter_extra_fields = False
271 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
271 rhodecode_title = v.UnicodeString(strip=True, min=1, not_empty=True)
272 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
272 rhodecode_realm = v.UnicodeString(strip=True, min=1, not_empty=True)
273 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
273 rhodecode_ga_code = v.UnicodeString(strip=True, min=1, not_empty=False)
274
274
275 return _ApplicationSettingsForm
275 return _ApplicationSettingsForm
276
276
277
277
278 def ApplicationVisualisationForm():
278 def ApplicationVisualisationForm():
279 class _ApplicationVisualisationForm(formencode.Schema):
279 class _ApplicationVisualisationForm(formencode.Schema):
280 allow_extra_fields = True
280 allow_extra_fields = True
281 filter_extra_fields = False
281 filter_extra_fields = False
282 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
282 rhodecode_show_public_icon = v.StringBoolean(if_missing=False)
283 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
283 rhodecode_show_private_icon = v.StringBoolean(if_missing=False)
284 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
284 rhodecode_stylify_metatags = v.StringBoolean(if_missing=False)
285
285
286 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
286 rhodecode_repository_fields = v.StringBoolean(if_missing=False)
287 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
287 rhodecode_lightweight_journal = v.StringBoolean(if_missing=False)
288 rhodecode_dashboard_items = v.UnicodeString()
288 rhodecode_dashboard_items = v.UnicodeString()
289 rhodecode_show_version = v.StringBoolean(if_missing=False)
289
290
290 return _ApplicationVisualisationForm
291 return _ApplicationVisualisationForm
291
292
292
293
293 def ApplicationUiSettingsForm():
294 def ApplicationUiSettingsForm():
294 class _ApplicationUiSettingsForm(formencode.Schema):
295 class _ApplicationUiSettingsForm(formencode.Schema):
295 allow_extra_fields = True
296 allow_extra_fields = True
296 filter_extra_fields = False
297 filter_extra_fields = False
297 web_push_ssl = v.StringBoolean(if_missing=False)
298 web_push_ssl = v.StringBoolean(if_missing=False)
298 paths_root_path = All(
299 paths_root_path = All(
299 v.ValidPath(),
300 v.ValidPath(),
300 v.UnicodeString(strip=True, min=1, not_empty=True)
301 v.UnicodeString(strip=True, min=1, not_empty=True)
301 )
302 )
302 hooks_changegroup_update = v.StringBoolean(if_missing=False)
303 hooks_changegroup_update = v.StringBoolean(if_missing=False)
303 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
304 hooks_changegroup_repo_size = v.StringBoolean(if_missing=False)
304 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
305 hooks_changegroup_push_logger = v.StringBoolean(if_missing=False)
305 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
306 hooks_outgoing_pull_logger = v.StringBoolean(if_missing=False)
306
307
307 extensions_largefiles = v.StringBoolean(if_missing=False)
308 extensions_largefiles = v.StringBoolean(if_missing=False)
308 extensions_hgsubversion = v.StringBoolean(if_missing=False)
309 extensions_hgsubversion = v.StringBoolean(if_missing=False)
309 extensions_hggit = v.StringBoolean(if_missing=False)
310 extensions_hggit = v.StringBoolean(if_missing=False)
310
311
311 return _ApplicationUiSettingsForm
312 return _ApplicationUiSettingsForm
312
313
313
314
314 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
315 def DefaultPermissionsForm(repo_perms_choices, group_perms_choices,
315 user_group_perms_choices, create_choices,
316 user_group_perms_choices, create_choices,
316 repo_group_create_choices, user_group_create_choices,
317 repo_group_create_choices, user_group_create_choices,
317 fork_choices, register_choices, extern_activate_choices):
318 fork_choices, register_choices, extern_activate_choices):
318 class _DefaultPermissionsForm(formencode.Schema):
319 class _DefaultPermissionsForm(formencode.Schema):
319 allow_extra_fields = True
320 allow_extra_fields = True
320 filter_extra_fields = True
321 filter_extra_fields = True
321 overwrite_default_repo = v.StringBoolean(if_missing=False)
322 overwrite_default_repo = v.StringBoolean(if_missing=False)
322 overwrite_default_group = v.StringBoolean(if_missing=False)
323 overwrite_default_group = v.StringBoolean(if_missing=False)
323 overwrite_default_user_group = v.StringBoolean(if_missing=False)
324 overwrite_default_user_group = v.StringBoolean(if_missing=False)
324 anonymous = v.StringBoolean(if_missing=False)
325 anonymous = v.StringBoolean(if_missing=False)
325 default_repo_perm = v.OneOf(repo_perms_choices)
326 default_repo_perm = v.OneOf(repo_perms_choices)
326 default_group_perm = v.OneOf(group_perms_choices)
327 default_group_perm = v.OneOf(group_perms_choices)
327 default_user_group_perm = v.OneOf(user_group_perms_choices)
328 default_user_group_perm = v.OneOf(user_group_perms_choices)
328
329
329 default_repo_create = v.OneOf(create_choices)
330 default_repo_create = v.OneOf(create_choices)
330 default_user_group_create = v.OneOf(user_group_create_choices)
331 default_user_group_create = v.OneOf(user_group_create_choices)
331 #default_repo_group_create = v.OneOf(repo_group_create_choices) #not impl. yet
332 #default_repo_group_create = v.OneOf(repo_group_create_choices) #not impl. yet
332 default_fork = v.OneOf(fork_choices)
333 default_fork = v.OneOf(fork_choices)
333
334
334 default_register = v.OneOf(register_choices)
335 default_register = v.OneOf(register_choices)
335 default_extern_activate = v.OneOf(extern_activate_choices)
336 default_extern_activate = v.OneOf(extern_activate_choices)
336 return _DefaultPermissionsForm
337 return _DefaultPermissionsForm
337
338
338
339
339 def CustomDefaultPermissionsForm():
340 def CustomDefaultPermissionsForm():
340 class _CustomDefaultPermissionsForm(formencode.Schema):
341 class _CustomDefaultPermissionsForm(formencode.Schema):
341 filter_extra_fields = True
342 filter_extra_fields = True
342 allow_extra_fields = True
343 allow_extra_fields = True
343 inherit_default_permissions = v.StringBoolean(if_missing=False)
344 inherit_default_permissions = v.StringBoolean(if_missing=False)
344
345
345 create_repo_perm = v.StringBoolean(if_missing=False)
346 create_repo_perm = v.StringBoolean(if_missing=False)
346 create_user_group_perm = v.StringBoolean(if_missing=False)
347 create_user_group_perm = v.StringBoolean(if_missing=False)
347 #create_repo_group_perm Impl. later
348 #create_repo_group_perm Impl. later
348
349
349 fork_repo_perm = v.StringBoolean(if_missing=False)
350 fork_repo_perm = v.StringBoolean(if_missing=False)
350
351
351 return _CustomDefaultPermissionsForm
352 return _CustomDefaultPermissionsForm
352
353
353
354
354 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
355 def DefaultsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
355 class _DefaultsForm(formencode.Schema):
356 class _DefaultsForm(formencode.Schema):
356 allow_extra_fields = True
357 allow_extra_fields = True
357 filter_extra_fields = True
358 filter_extra_fields = True
358 default_repo_type = v.OneOf(supported_backends)
359 default_repo_type = v.OneOf(supported_backends)
359 default_repo_private = v.StringBoolean(if_missing=False)
360 default_repo_private = v.StringBoolean(if_missing=False)
360 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
361 default_repo_enable_statistics = v.StringBoolean(if_missing=False)
361 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
362 default_repo_enable_downloads = v.StringBoolean(if_missing=False)
362 default_repo_enable_locking = v.StringBoolean(if_missing=False)
363 default_repo_enable_locking = v.StringBoolean(if_missing=False)
363
364
364 return _DefaultsForm
365 return _DefaultsForm
365
366
366
367
367 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
368 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices,
368 tls_kind_choices):
369 tls_kind_choices):
369 class _LdapSettingsForm(formencode.Schema):
370 class _LdapSettingsForm(formencode.Schema):
370 allow_extra_fields = True
371 allow_extra_fields = True
371 filter_extra_fields = True
372 filter_extra_fields = True
372 #pre_validators = [LdapLibValidator]
373 #pre_validators = [LdapLibValidator]
373 ldap_active = v.StringBoolean(if_missing=False)
374 ldap_active = v.StringBoolean(if_missing=False)
374 ldap_host = v.UnicodeString(strip=True,)
375 ldap_host = v.UnicodeString(strip=True,)
375 ldap_port = v.Number(strip=True,)
376 ldap_port = v.Number(strip=True,)
376 ldap_tls_kind = v.OneOf(tls_kind_choices)
377 ldap_tls_kind = v.OneOf(tls_kind_choices)
377 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
378 ldap_tls_reqcert = v.OneOf(tls_reqcert_choices)
378 ldap_dn_user = v.UnicodeString(strip=True,)
379 ldap_dn_user = v.UnicodeString(strip=True,)
379 ldap_dn_pass = v.UnicodeString(strip=True,)
380 ldap_dn_pass = v.UnicodeString(strip=True,)
380 ldap_base_dn = v.UnicodeString(strip=True,)
381 ldap_base_dn = v.UnicodeString(strip=True,)
381 ldap_filter = v.UnicodeString(strip=True,)
382 ldap_filter = v.UnicodeString(strip=True,)
382 ldap_search_scope = v.OneOf(search_scope_choices)
383 ldap_search_scope = v.OneOf(search_scope_choices)
383 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
384 ldap_attr_login = v.AttrLoginValidator()(not_empty=True)
384 ldap_attr_firstname = v.UnicodeString(strip=True,)
385 ldap_attr_firstname = v.UnicodeString(strip=True,)
385 ldap_attr_lastname = v.UnicodeString(strip=True,)
386 ldap_attr_lastname = v.UnicodeString(strip=True,)
386 ldap_attr_email = v.UnicodeString(strip=True,)
387 ldap_attr_email = v.UnicodeString(strip=True,)
387
388
388 return _LdapSettingsForm
389 return _LdapSettingsForm
389
390
390
391
391 def UserExtraEmailForm():
392 def UserExtraEmailForm():
392 class _UserExtraEmailForm(formencode.Schema):
393 class _UserExtraEmailForm(formencode.Schema):
393 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
394 email = All(v.UniqSystemEmail(), v.Email(not_empty=True))
394 return _UserExtraEmailForm
395 return _UserExtraEmailForm
395
396
396
397
397 def UserExtraIpForm():
398 def UserExtraIpForm():
398 class _UserExtraIpForm(formencode.Schema):
399 class _UserExtraIpForm(formencode.Schema):
399 ip = v.ValidIp()(not_empty=True)
400 ip = v.ValidIp()(not_empty=True)
400 return _UserExtraIpForm
401 return _UserExtraIpForm
401
402
402
403
403 def PullRequestForm(repo_id):
404 def PullRequestForm(repo_id):
404 class _PullRequestForm(formencode.Schema):
405 class _PullRequestForm(formencode.Schema):
405 allow_extra_fields = True
406 allow_extra_fields = True
406 filter_extra_fields = True
407 filter_extra_fields = True
407
408
408 user = v.UnicodeString(strip=True, required=True)
409 user = v.UnicodeString(strip=True, required=True)
409 org_repo = v.UnicodeString(strip=True, required=True)
410 org_repo = v.UnicodeString(strip=True, required=True)
410 org_ref = v.UnicodeString(strip=True, required=True)
411 org_ref = v.UnicodeString(strip=True, required=True)
411 other_repo = v.UnicodeString(strip=True, required=True)
412 other_repo = v.UnicodeString(strip=True, required=True)
412 other_ref = v.UnicodeString(strip=True, required=True)
413 other_ref = v.UnicodeString(strip=True, required=True)
413 revisions = All(#v.NotReviewedRevisions(repo_id)(),
414 revisions = All(#v.NotReviewedRevisions(repo_id)(),
414 v.UniqueList(not_empty=True))
415 v.UniqueList(not_empty=True))
415 review_members = v.UniqueList(not_empty=True)
416 review_members = v.UniqueList(not_empty=True)
416
417
417 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
418 pullrequest_title = v.UnicodeString(strip=True, required=True, min=3)
418 pullrequest_desc = v.UnicodeString(strip=True, required=False)
419 pullrequest_desc = v.UnicodeString(strip=True, required=False)
419
420
420 ancestor_rev = v.UnicodeString(strip=True, required=True)
421 ancestor_rev = v.UnicodeString(strip=True, required=True)
421 merge_rev = v.UnicodeString(strip=True, required=True)
422 merge_rev = v.UnicodeString(strip=True, required=True)
422
423
423 return _PullRequestForm
424 return _PullRequestForm
424
425
425
426
426 def GistForm(lifetime_options):
427 def GistForm(lifetime_options):
427 class _GistForm(formencode.Schema):
428 class _GistForm(formencode.Schema):
428
429
429 filename = All(v.BasePath()(),
430 filename = All(v.BasePath()(),
430 v.UnicodeString(strip=True, required=False))
431 v.UnicodeString(strip=True, required=False))
431 description = v.UnicodeString(required=False, if_missing='')
432 description = v.UnicodeString(required=False, if_missing='')
432 lifetime = v.OneOf(lifetime_options)
433 lifetime = v.OneOf(lifetime_options)
433 content = v.UnicodeString(required=True, not_empty=True)
434 content = v.UnicodeString(required=True, not_empty=True)
434 public = v.UnicodeString(required=False, if_missing='')
435 public = v.UnicodeString(required=False, if_missing='')
435 private = v.UnicodeString(required=False, if_missing='')
436 private = v.UnicodeString(required=False, if_missing='')
436
437
437 return _GistForm
438 return _GistForm
@@ -1,351 +1,356 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Settings administration')} &middot; ${c.rhodecode_name}
5 ${_('Settings administration')} &middot; ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${_('Settings')}
11 ${_('Settings')}
12 </%def>
12 </%def>
13
13
14 <%def name="page_nav()">
14 <%def name="page_nav()">
15 ${self.menu('admin')}
15 ${self.menu('admin')}
16 </%def>
16 </%def>
17
17
18 <%def name="main()">
18 <%def name="main()">
19 <div class="box">
19 <div class="box">
20 <!-- box / title -->
20 <!-- box / title -->
21 <div class="title">
21 <div class="title">
22 ${self.breadcrumbs()}
22 ${self.breadcrumbs()}
23 </div>
23 </div>
24 <!-- end box / title -->
24 <!-- end box / title -->
25
25
26 <h3>${_('Remap and rescan repositories')}</h3>
26 <h3>${_('Remap and rescan repositories')}</h3>
27 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
27 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
28 <div class="form">
28 <div class="form">
29 <!-- fields -->
29 <!-- fields -->
30
30
31 <div class="fields">
31 <div class="fields">
32 <div class="field">
32 <div class="field">
33 <div class="label label-checkbox">
33 <div class="label label-checkbox">
34 <label for="destroy">${_('Rescan option')}:</label>
34 <label for="destroy">${_('Rescan option')}:</label>
35 </div>
35 </div>
36 <div class="checkboxes">
36 <div class="checkboxes">
37 <div class="checkbox">
37 <div class="checkbox">
38 ${h.checkbox('destroy',True)}
38 ${h.checkbox('destroy',True)}
39 <label for="destroy">
39 <label for="destroy">
40 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
40 <span class="tooltip" title="${h.tooltip(_('In case a repository was deleted from filesystem and there are leftovers in the database check this option to scan obsolete data in database and remove it.'))}">
41 ${_('Destroy old data')}</span> </label>
41 ${_('Destroy old data')}</span> </label>
42 </div>
42 </div>
43 <span class="help-block">${_('Rescan repositories location for new repositories. Also deletes obsolete if `destroy` flag is checked ')}</span>
43 <span class="help-block">${_('Rescan repositories location for new repositories. Also deletes obsolete if `destroy` flag is checked ')}</span>
44 </div>
44 </div>
45 </div>
45 </div>
46
46
47 <div class="buttons">
47 <div class="buttons">
48 ${h.submit('rescan',_('Rescan repositories'),class_="ui-btn large")}
48 ${h.submit('rescan',_('Rescan repositories'),class_="ui-btn large")}
49 </div>
49 </div>
50 </div>
50 </div>
51 </div>
51 </div>
52 ${h.end_form()}
52 ${h.end_form()}
53
53
54 <h3>${_('Whoosh indexing')}</h3>
54 <h3>${_('Whoosh indexing')}</h3>
55 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
55 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
56 <div class="form">
56 <div class="form">
57 <!-- fields -->
57 <!-- fields -->
58
58
59 <div class="fields">
59 <div class="fields">
60 <div class="field">
60 <div class="field">
61 <div class="label label-checkbox">
61 <div class="label label-checkbox">
62 <label>${_('Index build option')}:</label>
62 <label>${_('Index build option')}:</label>
63 </div>
63 </div>
64 <div class="checkboxes">
64 <div class="checkboxes">
65 <div class="checkbox">
65 <div class="checkbox">
66 ${h.checkbox('full_index',True)}
66 ${h.checkbox('full_index',True)}
67 <label for="full_index">${_('Build from scratch')}</label>
67 <label for="full_index">${_('Build from scratch')}</label>
68 </div>
68 </div>
69 </div>
69 </div>
70 </div>
70 </div>
71
71
72 <div class="buttons">
72 <div class="buttons">
73 ${h.submit('reindex',_('Reindex'),class_="ui-btn large")}
73 ${h.submit('reindex',_('Reindex'),class_="ui-btn large")}
74 </div>
74 </div>
75 </div>
75 </div>
76 </div>
76 </div>
77 ${h.end_form()}
77 ${h.end_form()}
78
78
79 <h3>${_('Global application settings')}</h3>
79 <h3>${_('Global application settings')}</h3>
80 ${h.form(url('admin_setting', setting_id='global'),method='put')}
80 ${h.form(url('admin_setting', setting_id='global'),method='put')}
81 <div class="form">
81 <div class="form">
82 <!-- fields -->
82 <!-- fields -->
83
83
84 <div class="fields">
84 <div class="fields">
85
85
86 <div class="field">
86 <div class="field">
87 <div class="label">
87 <div class="label">
88 <label for="rhodecode_title">${_('Site branding')}:</label>
88 <label for="rhodecode_title">${_('Site branding')}:</label>
89 </div>
89 </div>
90 <div class="input">
90 <div class="input">
91 ${h.text('rhodecode_title',size=30)}
91 ${h.text('rhodecode_title',size=30)}
92 </div>
92 </div>
93 </div>
93 </div>
94
94
95 <div class="field">
95 <div class="field">
96 <div class="label">
96 <div class="label">
97 <label for="rhodecode_realm">${_('HTTP authentication realm')}:</label>
97 <label for="rhodecode_realm">${_('HTTP authentication realm')}:</label>
98 </div>
98 </div>
99 <div class="input">
99 <div class="input">
100 ${h.text('rhodecode_realm',size=30)}
100 ${h.text('rhodecode_realm',size=30)}
101 </div>
101 </div>
102 </div>
102 </div>
103
103
104 <div class="field">
104 <div class="field">
105 <div class="label">
105 <div class="label">
106 <label for="rhodecode_ga_code">${_('Google Analytics code')}:</label>
106 <label for="rhodecode_ga_code">${_('Google Analytics code')}:</label>
107 </div>
107 </div>
108 <div class="input">
108 <div class="input">
109 ${h.text('rhodecode_ga_code',size=30)}
109 ${h.text('rhodecode_ga_code',size=30)}
110 </div>
110 </div>
111 </div>
111 </div>
112
112
113 <div class="buttons">
113 <div class="buttons">
114 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
114 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
115 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
115 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
116 </div>
116 </div>
117 </div>
117 </div>
118 </div>
118 </div>
119 ${h.end_form()}
119 ${h.end_form()}
120
120
121 <h3>${_('Visualisation settings')}</h3>
121 <h3>${_('Visualisation settings')}</h3>
122 ${h.form(url('admin_setting', setting_id='visual'),method='put')}
122 ${h.form(url('admin_setting', setting_id='visual'),method='put')}
123 <div class="form">
123 <div class="form">
124 <!-- fields -->
124 <!-- fields -->
125
125
126 <div class="fields">
126 <div class="fields">
127 <div class="field">
127 <div class="field">
128 <div class="label label-checkbox">
128 <div class="label label-checkbox">
129 <label>${_('General')}:</label>
129 <label>${_('General')}:</label>
130 </div>
130 </div>
131 <div class="checkboxes">
131 <div class="checkboxes">
132 <div class="checkbox">
132 <div class="checkbox">
133 ${h.checkbox('rhodecode_repository_fields','True')}
133 ${h.checkbox('rhodecode_repository_fields','True')}
134 <label for="rhodecode_repository_fields">${_('Use repository extra fields')}</label>
134 <label for="rhodecode_repository_fields">${_('Use repository extra fields')}</label>
135 </div>
135 </div>
136 <span class="help-block">${_('Allows storing additional customized fields per repository.')}</span>
136 <span class="help-block">${_('Allows storing additional customized fields per repository.')}</span>
137 <div class="checkbox">
138 ${h.checkbox('rhodecode_show_version','True')}
139 <label for="rhodecode_show_version">${_('Show RhodeCode version')}</label>
140 </div>
141 <span class="help-block">${_('Shows or hides displayed version of RhodeCode in the footer')}</span>
137 </div>
142 </div>
138 </div>
143 </div>
139 <div class="field">
144 <div class="field">
140 <div class="label">
145 <div class="label">
141 <label for="rhodecode_realm">${_('Dashboard items')}:</label>
146 <label for="rhodecode_realm">${_('Dashboard items')}:</label>
142 </div>
147 </div>
143 <div class="input">
148 <div class="input">
144 ${h.text('rhodecode_dashboard_items',size=5)}
149 ${h.text('rhodecode_dashboard_items',size=5)}
145 <span class="help-block">${_('Number of items displayed in lightweight dashboard before pagination is shown.')}</span>
150 <span class="help-block">${_('Number of items displayed in lightweight dashboard before pagination is shown.')}</span>
146 </div>
151 </div>
147 </div>
152 </div>
148 <div class="field">
153 <div class="field">
149 <div class="label label-checkbox">
154 <div class="label label-checkbox">
150 <label>${_('Icons')}:</label>
155 <label>${_('Icons')}:</label>
151 </div>
156 </div>
152 <div class="checkboxes">
157 <div class="checkboxes">
153 <div class="checkbox">
158 <div class="checkbox">
154 ${h.checkbox('rhodecode_show_public_icon','True')}
159 ${h.checkbox('rhodecode_show_public_icon','True')}
155 <label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label>
160 <label for="rhodecode_show_public_icon">${_('Show public repo icon on repositories')}</label>
156 </div>
161 </div>
157 <div class="checkbox">
162 <div class="checkbox">
158 ${h.checkbox('rhodecode_show_private_icon','True')}
163 ${h.checkbox('rhodecode_show_private_icon','True')}
159 <label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label>
164 <label for="rhodecode_show_private_icon">${_('Show private repo icon on repositories')}</label>
160 </div>
165 </div>
161 <span class="help-block">${_('Show public/private icons next to repositories names')}</span>
166 <span class="help-block">${_('Show public/private icons next to repositories names')}</span>
162 </div>
167 </div>
163 </div>
168 </div>
164
169
165 <div class="field">
170 <div class="field">
166 <div class="label label-checkbox">
171 <div class="label label-checkbox">
167 <label>${_('Meta-Tagging')}:</label>
172 <label>${_('Meta-Tagging')}:</label>
168 </div>
173 </div>
169 <div class="checkboxes">
174 <div class="checkboxes">
170 <div class="checkbox">
175 <div class="checkbox">
171 ${h.checkbox('rhodecode_stylify_metatags','True')}
176 ${h.checkbox('rhodecode_stylify_metatags','True')}
172 <label for="rhodecode_stylify_metatags">${_('Stylify recognised metatags:')}</label>
177 <label for="rhodecode_stylify_metatags">${_('Stylify recognised metatags:')}</label>
173 </div>
178 </div>
174 <div style="padding-left: 20px;">
179 <div style="padding-left: 20px;">
175 <ul> <!-- Fix style here -->
180 <ul> <!-- Fix style here -->
176 <li>[featured] <span class="metatag" tag="featured">featured</span></li>
181 <li>[featured] <span class="metatag" tag="featured">featured</span></li>
177 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
182 <li>[stale] <span class="metatag" tag="stale">stale</span></li>
178 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
183 <li>[dead] <span class="metatag" tag="dead">dead</span></li>
179 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
184 <li>[lang =&gt; lang] <span class="metatag" tag="lang" >lang</span></li>
180 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
185 <li>[license =&gt; License] <span class="metatag" tag="license"><a href="http://www.opensource.org/licenses/License" >License</a></span></li>
181 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
186 <li>[requires =&gt; Repo] <span class="metatag" tag="requires" >requires =&gt; <a href="#" >Repo</a></span></li>
182 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
187 <li>[recommends =&gt; Repo] <span class="metatag" tag="recommends" >recommends =&gt; <a href="#" >Repo</a></span></li>
183 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
188 <li>[see =&gt; URI] <span class="metatag" tag="see">see =&gt; <a href="#">URI</a> </span></li>
184 </ul>
189 </ul>
185 </div>
190 </div>
186 </div>
191 </div>
187 </div>
192 </div>
188
193
189 <div class="buttons">
194 <div class="buttons">
190 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
195 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
191 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
196 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
192 </div>
197 </div>
193
198
194 </div>
199 </div>
195 </div>
200 </div>
196 ${h.end_form()}
201 ${h.end_form()}
197
202
198
203
199 <h3>${_('VCS settings')}</h3>
204 <h3>${_('VCS settings')}</h3>
200 ${h.form(url('admin_setting', setting_id='vcs'),method='put')}
205 ${h.form(url('admin_setting', setting_id='vcs'),method='put')}
201 <div class="form">
206 <div class="form">
202 <!-- fields -->
207 <!-- fields -->
203
208
204 <div class="fields">
209 <div class="fields">
205
210
206 <div class="field">
211 <div class="field">
207 <div class="label label-checkbox">
212 <div class="label label-checkbox">
208 <label>${_('Web')}:</label>
213 <label>${_('Web')}:</label>
209 </div>
214 </div>
210 <div class="checkboxes">
215 <div class="checkboxes">
211 <div class="checkbox">
216 <div class="checkbox">
212 ${h.checkbox('web_push_ssl', 'True')}
217 ${h.checkbox('web_push_ssl', 'True')}
213 <label for="web_push_ssl">${_('Require SSL for vcs operations')}</label>
218 <label for="web_push_ssl">${_('Require SSL for vcs operations')}</label>
214 </div>
219 </div>
215 <span class="help-block">${_('RhodeCode will require SSL for pushing or pulling. If SSL is missing it will return HTTP Error 406: Not Acceptable')}</span>
220 <span class="help-block">${_('RhodeCode will require SSL for pushing or pulling. If SSL is missing it will return HTTP Error 406: Not Acceptable')}</span>
216 </div>
221 </div>
217 </div>
222 </div>
218
223
219 <div class="field">
224 <div class="field">
220 <div class="label label-checkbox">
225 <div class="label label-checkbox">
221 <label>${_('Hooks')}:</label>
226 <label>${_('Hooks')}:</label>
222 </div>
227 </div>
223 <div class="checkboxes">
228 <div class="checkboxes">
224 <div class="checkbox">
229 <div class="checkbox">
225 ${h.checkbox('hooks_changegroup_update','True')}
230 ${h.checkbox('hooks_changegroup_update','True')}
226 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
231 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
227 </div>
232 </div>
228 <div class="checkbox">
233 <div class="checkbox">
229 ${h.checkbox('hooks_changegroup_repo_size','True')}
234 ${h.checkbox('hooks_changegroup_repo_size','True')}
230 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
235 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
231 </div>
236 </div>
232 <div class="checkbox">
237 <div class="checkbox">
233 ${h.checkbox('hooks_changegroup_push_logger','True')}
238 ${h.checkbox('hooks_changegroup_push_logger','True')}
234 <label for="hooks_changegroup_push_logger">${_('Log user push commands')}</label>
239 <label for="hooks_changegroup_push_logger">${_('Log user push commands')}</label>
235 </div>
240 </div>
236 <div class="checkbox">
241 <div class="checkbox">
237 ${h.checkbox('hooks_outgoing_pull_logger','True')}
242 ${h.checkbox('hooks_outgoing_pull_logger','True')}
238 <label for="hooks_outgoing_pull_logger">${_('Log user pull commands')}</label>
243 <label for="hooks_outgoing_pull_logger">${_('Log user pull commands')}</label>
239 </div>
244 </div>
240 </div>
245 </div>
241 <div class="input" style="margin-top:10px">
246 <div class="input" style="margin-top:10px">
242 ${h.link_to(_('Advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
247 ${h.link_to(_('Advanced setup'),url('admin_edit_setting',setting_id='hooks'))}
243 </div>
248 </div>
244 </div>
249 </div>
245 <div class="field">
250 <div class="field">
246 <div class="label label-checkbox">
251 <div class="label label-checkbox">
247 <label>${_('Mercurial Extensions')}:</label>
252 <label>${_('Mercurial Extensions')}:</label>
248 </div>
253 </div>
249 <div class="checkboxes">
254 <div class="checkboxes">
250 <div class="checkbox">
255 <div class="checkbox">
251 ${h.checkbox('extensions_largefiles','True')}
256 ${h.checkbox('extensions_largefiles','True')}
252 <label for="extensions_largefiles">${_('Enable largefiles extension')}</label>
257 <label for="extensions_largefiles">${_('Enable largefiles extension')}</label>
253 </div>
258 </div>
254 <div class="checkbox">
259 <div class="checkbox">
255 ${h.checkbox('extensions_hgsubversion','True')}
260 ${h.checkbox('extensions_hgsubversion','True')}
256 <label for="extensions_hgsubversion">${_('Enable hgsubversion extension')}</label>
261 <label for="extensions_hgsubversion">${_('Enable hgsubversion extension')}</label>
257 </div>
262 </div>
258 <span class="help-block">${_('Requires hgsubversion library installed. Allows cloning from svn remote locations')}</span>
263 <span class="help-block">${_('Requires hgsubversion library installed. Allows cloning from svn remote locations')}</span>
259 ##<div class="checkbox">
264 ##<div class="checkbox">
260 ## ${h.checkbox('extensions_hggit','True')}
265 ## ${h.checkbox('extensions_hggit','True')}
261 ## <label for="extensions_hggit">${_('Enable hg-git extension')}</label>
266 ## <label for="extensions_hggit">${_('Enable hg-git extension')}</label>
262 ##</div>
267 ##</div>
263 ##<span class="help-block">${_('Requires hg-git library installed. Allows cloning from git remote locations')}</span>
268 ##<span class="help-block">${_('Requires hg-git library installed. Allows cloning from git remote locations')}</span>
264 </div>
269 </div>
265 </div>
270 </div>
266 <div class="field">
271 <div class="field">
267 <div class="label">
272 <div class="label">
268 <label for="paths_root_path">${_('Repositories location')}:</label>
273 <label for="paths_root_path">${_('Repositories location')}:</label>
269 </div>
274 </div>
270 <div class="input">
275 <div class="input">
271 ${h.text('paths_root_path',size=30,readonly="readonly")}
276 ${h.text('paths_root_path',size=30,readonly="readonly")}
272 <span id="path_unlock" class="tooltip"
277 <span id="path_unlock" class="tooltip"
273 title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
278 title="${h.tooltip(_('This a crucial application setting. If you are really sure you need to change this, you must restart application in order to make this setting take effect. Click this label to unlock.'))}">
274 ${_('Unlock')}
279 ${_('Unlock')}
275 </span>
280 </span>
276 <span class="help-block">${_('Location where repositories are stored. After changing this value a restart, and rescan is required')}</span>
281 <span class="help-block">${_('Location where repositories are stored. After changing this value a restart, and rescan is required')}</span>
277 </div>
282 </div>
278 </div>
283 </div>
279
284
280 <div class="buttons">
285 <div class="buttons">
281 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
286 ${h.submit('save',_('Save settings'),class_="ui-btn large")}
282 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
287 ${h.reset('reset',_('Reset'),class_="ui-btn large")}
283 </div>
288 </div>
284 </div>
289 </div>
285 </div>
290 </div>
286 ${h.end_form()}
291 ${h.end_form()}
287
292
288 <script type="text/javascript">
293 <script type="text/javascript">
289 YAHOO.util.Event.onDOMReady(function(){
294 YAHOO.util.Event.onDOMReady(function(){
290 YAHOO.util.Event.addListener('path_unlock','click',function(){
295 YAHOO.util.Event.addListener('path_unlock','click',function(){
291 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
296 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
292 });
297 });
293 });
298 });
294 </script>
299 </script>
295
300
296 <h3>${_('Test Email')}</h3>
301 <h3>${_('Test Email')}</h3>
297 ${h.form(url('admin_setting', setting_id='email'),method='put')}
302 ${h.form(url('admin_setting', setting_id='email'),method='put')}
298 <div class="form">
303 <div class="form">
299 <!-- fields -->
304 <!-- fields -->
300
305
301 <div class="fields">
306 <div class="fields">
302 <div class="field">
307 <div class="field">
303 <div class="label">
308 <div class="label">
304 <label for="test_email">${_('Email to')}:</label>
309 <label for="test_email">${_('Email to')}:</label>
305 </div>
310 </div>
306 <div class="input">
311 <div class="input">
307 ${h.text('test_email',size=30)}
312 ${h.text('test_email',size=30)}
308 </div>
313 </div>
309 </div>
314 </div>
310
315
311 <div class="buttons">
316 <div class="buttons">
312 ${h.submit('send',_('Send'),class_="ui-btn large")}
317 ${h.submit('send',_('Send'),class_="ui-btn large")}
313 </div>
318 </div>
314 </div>
319 </div>
315 </div>
320 </div>
316 ${h.end_form()}
321 ${h.end_form()}
317
322
318 <h3>${_('System Info and Packages')}</h3>
323 <h3>${_('System Info and Packages')}</h3>
319 <div class="form">
324 <div class="form">
320 <div>
325 <div>
321 <h5 id="expand_modules" style="cursor: pointer">&darr; ${_('Show')} &darr;</h5>
326 <h5 id="expand_modules" style="cursor: pointer">&darr; ${_('Show')} &darr;</h5>
322 </div>
327 </div>
323 <div id="expand_modules_table" style="display:none">
328 <div id="expand_modules_table" style="display:none">
324 <h5>Python - ${c.py_version}</h5>
329 <h5>Python - ${c.py_version}</h5>
325 <h5>System - ${c.platform}</h5>
330 <h5>System - ${c.platform}</h5>
326
331
327 <table class="table" style="margin:0px 0px 0px 20px">
332 <table class="table" style="margin:0px 0px 0px 20px">
328 <colgroup>
333 <colgroup>
329 <col style="width:220px">
334 <col style="width:220px">
330 </colgroup>
335 </colgroup>
331 <tbody>
336 <tbody>
332 %for key, value in c.modules:
337 %for key, value in c.modules:
333 <tr>
338 <tr>
334 <th style="text-align: right;padding-right:5px;">${key}</th>
339 <th style="text-align: right;padding-right:5px;">${key}</th>
335 <td>${value}</td>
340 <td>${value}</td>
336 </tr>
341 </tr>
337 %endfor
342 %endfor
338 </tbody>
343 </tbody>
339 </table>
344 </table>
340 </div>
345 </div>
341 </div>
346 </div>
342
347
343 <script type="text/javascript">
348 <script type="text/javascript">
344 YUE.on('expand_modules','click',function(e){
349 YUE.on('expand_modules','click',function(e){
345 YUD.setStyle('expand_modules_table','display','');
350 YUD.setStyle('expand_modules_table','display','');
346 YUD.setStyle('expand_modules','display','none');
351 YUD.setStyle('expand_modules','display','none');
347 })
352 })
348 </script>
353 </script>
349
354
350 </div>
355 </div>
351 </%def>
356 </%def>
@@ -1,358 +1,363 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="root.html"/>
2 <%inherit file="root.html"/>
3
3
4 <!-- HEADER -->
4 <!-- HEADER -->
5 <div id="header-dd"></div>
5 <div id="header-dd"></div>
6 <div id="header">
6 <div id="header">
7 <div id="header-inner" class="title">
7 <div id="header-inner" class="title">
8 <div id="logo">
8 <div id="logo">
9 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
9 <h1><a href="${h.url('home')}">${c.rhodecode_name}</a></h1>
10 </div>
10 </div>
11 <!-- MENU -->
11 <!-- MENU -->
12 ${self.page_nav()}
12 ${self.page_nav()}
13 <!-- END MENU -->
13 <!-- END MENU -->
14 ${self.body()}
14 ${self.body()}
15 </div>
15 </div>
16 </div>
16 </div>
17 <!-- END HEADER -->
17 <!-- END HEADER -->
18
18
19 <!-- CONTENT -->
19 <!-- CONTENT -->
20 <div id="content">
20 <div id="content">
21 <div class="flash_msg">
21 <div class="flash_msg">
22 <% messages = h.flash.pop_messages() %>
22 <% messages = h.flash.pop_messages() %>
23 % if messages:
23 % if messages:
24 <ul id="flash-messages">
24 <ul id="flash-messages">
25 % for message in messages:
25 % for message in messages:
26 <li class="${message.category}_msg">${message}</li>
26 <li class="${message.category}_msg">${message}</li>
27 % endfor
27 % endfor
28 </ul>
28 </ul>
29 % endif
29 % endif
30 </div>
30 </div>
31 <div id="main">
31 <div id="main">
32 ${next.main()}
32 ${next.main()}
33 </div>
33 </div>
34 </div>
34 </div>
35 <!-- END CONTENT -->
35 <!-- END CONTENT -->
36
36
37 <!-- FOOTER -->
37 <!-- FOOTER -->
38 <div id="footer">
38 <div id="footer">
39 <div id="footer-inner" class="title">
39 <div id="footer-inner" class="title">
40 <div>
40 <div>
41 <p class="footer-link">
41 <p class="footer-link">
42 ${_('Server instance: %s') % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}
42 ${_('Server instance: %s') % c.rhodecode_instanceid if c.rhodecode_instanceid else ''}
43 </p>
43 </p>
44 <p class="footer-link-right">
44 <p class="footer-link-right">
45 <a href="${h.url('rhodecode_official')}">RhodeCode ${c.rhodecode_version}</a>
45 <a href="${h.url('rhodecode_official')}">
46 RhodeCode
47 %if c.visual.show_version:
48 ${c.rhodecode_version}
49 %endif
50 </a>
46 &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski and others
51 &copy; 2010-${h.datetime.today().year} by Marcin Kuzminski and others
47 &ndash; <a href="${h.url('bugtracker')}">${_('Report a bug')}</a>
52 &ndash; <a href="${h.url('bugtracker')}">${_('Report a bug')}</a>
48 </p>
53 </p>
49 </div>
54 </div>
50 </div>
55 </div>
51 </div>
56 </div>
52
57
53 <!-- END FOOTER -->
58 <!-- END FOOTER -->
54
59
55 ### MAKO DEFS ###
60 ### MAKO DEFS ###
56 <%def name="breadcrumbs()">
61 <%def name="breadcrumbs()">
57 <div class="breadcrumbs">
62 <div class="breadcrumbs">
58 ${self.breadcrumbs_links()}
63 ${self.breadcrumbs_links()}
59 </div>
64 </div>
60 </%def>
65 </%def>
61
66
62 <%def name="context_bar(current)">
67 <%def name="context_bar(current)">
63 ${repo_context_bar(current)}
68 ${repo_context_bar(current)}
64 </%def>
69 </%def>
65
70
66 <%def name="admin_menu()">
71 <%def name="admin_menu()">
67 <ul class="admin_menu">
72 <ul class="admin_menu">
68 <li>${h.link_to(_('Admin journal'),h.url('admin_home'),class_='journal ')}</li>
73 <li>${h.link_to(_('Admin journal'),h.url('admin_home'),class_='journal ')}</li>
69 <li>${h.link_to(_('Repositories'),h.url('repos'),class_='repos')}</li>
74 <li>${h.link_to(_('Repositories'),h.url('repos'),class_='repos')}</li>
70 <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
75 <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
71 <li>${h.link_to(_('Users'),h.url('users'),class_='users')}</li>
76 <li>${h.link_to(_('Users'),h.url('users'),class_='users')}</li>
72 <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
77 <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
73 <li>${h.link_to(_('Permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
78 <li>${h.link_to(_('Permissions'),h.url('edit_permission',id='default'),class_='permissions')}</li>
74 <li>${h.link_to(_('LDAP'),h.url('ldap_home'),class_='ldap')}</li>
79 <li>${h.link_to(_('LDAP'),h.url('ldap_home'),class_='ldap')}</li>
75 <li>${h.link_to(_('Defaults'),h.url('defaults'),class_='defaults')}</li>
80 <li>${h.link_to(_('Defaults'),h.url('defaults'),class_='defaults')}</li>
76 <li class="last">${h.link_to(_('Settings'),h.url('admin_settings'),class_='settings')}</li>
81 <li class="last">${h.link_to(_('Settings'),h.url('admin_settings'),class_='settings')}</li>
77 </ul>
82 </ul>
78 </%def>
83 </%def>
79
84
80 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
85 <%def name="admin_menu_simple(repositories=None, repository_groups=None, user_groups=None)">
81 <ul>
86 <ul>
82 %if repositories:
87 %if repositories:
83 <li>${h.link_to(_('Repositories'),h.url('repos'),class_='repos')}</li>
88 <li>${h.link_to(_('Repositories'),h.url('repos'),class_='repos')}</li>
84 %endif
89 %endif
85 %if repository_groups:
90 %if repository_groups:
86 <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
91 <li>${h.link_to(_('Repository groups'),h.url('repos_groups'),class_='repos_groups')}</li>
87 %endif
92 %endif
88 %if user_groups:
93 %if user_groups:
89 <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
94 <li>${h.link_to(_('User groups'),h.url('users_groups'),class_='groups')}</li>
90 %endif
95 %endif
91 </ul>
96 </ul>
92 </%def>
97 </%def>
93
98
94 <%def name="repo_context_bar(current=None)">
99 <%def name="repo_context_bar(current=None)">
95 <%
100 <%
96 def follow_class():
101 def follow_class():
97 if c.repository_following:
102 if c.repository_following:
98 return h.literal('following')
103 return h.literal('following')
99 else:
104 else:
100 return h.literal('follow')
105 return h.literal('follow')
101 %>
106 %>
102 <%
107 <%
103 def is_current(selected):
108 def is_current(selected):
104 if selected == current:
109 if selected == current:
105 return h.literal('class="current"')
110 return h.literal('class="current"')
106 %>
111 %>
107
112
108 <!--- CONTEXT BAR -->
113 <!--- CONTEXT BAR -->
109 <div id="context-bar" class="box">
114 <div id="context-bar" class="box">
110 <div id="breadcrumbs">
115 <div id="breadcrumbs">
111 ${h.link_to(_(u'Repositories'),h.url('home'))}
116 ${h.link_to(_(u'Repositories'),h.url('home'))}
112 &raquo;
117 &raquo;
113 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
118 ${h.repo_link(c.rhodecode_db_repo.groups_and_repo)}
114 </div>
119 </div>
115 <ul id="context-pages" class="horizontal-list">
120 <ul id="context-pages" class="horizontal-list">
116 <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}" class="summary">${_('Summary')}</a></li>
121 <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}" class="summary">${_('Summary')}</a></li>
117 <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}" class="changelogs">${_('Changelog')}</a></li>
122 <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}" class="changelogs">${_('Changelog')}</a></li>
118 <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name)}" class="files"></span>${_('Files')}</a></li>
123 <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name)}" class="files"></span>${_('Files')}</a></li>
119 <li ${is_current('switch-to')}>
124 <li ${is_current('switch-to')}>
120 <a href="#" id="branch_tag_switcher_2" class="dropdown switch-to"></span>${_('Switch To')}</a>
125 <a href="#" id="branch_tag_switcher_2" class="dropdown switch-to"></span>${_('Switch To')}</a>
121 <ul id="switch_to_list_2" class="switch_to submenu">
126 <ul id="switch_to_list_2" class="switch_to submenu">
122 <li><a href="#">${_('loading...')}</a></li>
127 <li><a href="#">${_('loading...')}</a></li>
123 </ul>
128 </ul>
124 </li>
129 </li>
125 <li ${is_current('options')}>
130 <li ${is_current('options')}>
126 <a href="#" class="dropdown options"></span>${_('Options')}</a>
131 <a href="#" class="dropdown options"></span>${_('Options')}</a>
127 <ul>
132 <ul>
128 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
133 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
129 <li>${h.link_to(_('Settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
134 <li>${h.link_to(_('Settings'),h.url('edit_repo',repo_name=c.repo_name),class_='settings')}</li>
130 %endif
135 %endif
131 %if c.rhodecode_db_repo.fork:
136 %if c.rhodecode_db_repo.fork:
132 <li>${h.link_to(_('Compare fork'),h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default', merge=1),class_='compare_request')}</li>
137 <li>${h.link_to(_('Compare fork'),h.url('compare_url',repo_name=c.rhodecode_db_repo.fork.repo_name,org_ref_type='branch',org_ref='default',other_repo=c.repo_name,other_ref_type='branch',other_ref=request.GET.get('branch') or 'default', merge=1),class_='compare_request')}</li>
133 %endif
138 %endif
134 <li>${h.link_to(_('Search'),h.url('search_repo',repo_name=c.repo_name),class_='search')}</li>
139 <li>${h.link_to(_('Search'),h.url('search_repo',repo_name=c.repo_name),class_='search')}</li>
135
140
136 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
141 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking:
137 %if c.rhodecode_db_repo.locked[0]:
142 %if c.rhodecode_db_repo.locked[0]:
138 <li>${h.link_to(_('Unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
143 <li>${h.link_to(_('Unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
139 %else:
144 %else:
140 <li>${h.link_to(_('Lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
145 <li>${h.link_to(_('Lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
141 %endif
146 %endif
142 %endif
147 %endif
143 ## TODO: this check feels wrong, it would be better to have a check for permissions
148 ## TODO: this check feels wrong, it would be better to have a check for permissions
144 ## also it feels like a job for the controller
149 ## also it feels like a job for the controller
145 %if c.rhodecode_user.username != 'default':
150 %if c.rhodecode_user.username != 'default':
146 <li>
151 <li>
147 <a class="${follow_class()}" onclick="javascript:toggleFollowingRepo(this,${c.rhodecode_db_repo.repo_id},'${str(h.get_token())}');">
152 <a class="${follow_class()}" onclick="javascript:toggleFollowingRepo(this,${c.rhodecode_db_repo.repo_id},'${str(h.get_token())}');">
148 <span class="show-follow">${_('Follow')}</span>
153 <span class="show-follow">${_('Follow')}</span>
149 <span class="show-following">${_('Unfollow')}</span>
154 <span class="show-following">${_('Unfollow')}</span>
150 </a>
155 </a>
151 </li>
156 </li>
152 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}" class="fork">${_('Fork')}</a></li>
157 <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}" class="fork">${_('Fork')}</a></li>
153 %if h.is_hg(c.rhodecode_repo):
158 %if h.is_hg(c.rhodecode_repo):
154 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="pull-request">${_('Create Pull Request')}</a></li>
159 <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}" class="pull-request">${_('Create Pull Request')}</a></li>
155 %endif
160 %endif
156 %endif
161 %endif
157 </ul>
162 </ul>
158 </li>
163 </li>
159 <li ${is_current('showpullrequest')}>
164 <li ${is_current('showpullrequest')}>
160 <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests')}" class="pull-request">${_('Pull Requests')}
165 <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests')}" class="pull-request">${_('Pull Requests')}
161 %if c.repository_pull_requests:
166 %if c.repository_pull_requests:
162 <span>${c.repository_pull_requests}</span>
167 <span>${c.repository_pull_requests}</span>
163 %endif
168 %endif
164 </a>
169 </a>
165 </li>
170 </li>
166 </ul>
171 </ul>
167 </div>
172 </div>
168 <script type="text/javascript">
173 <script type="text/javascript">
169 YUE.on('branch_tag_switcher_2','mouseover',function(){
174 YUE.on('branch_tag_switcher_2','mouseover',function(){
170 var loaded = YUD.hasClass('branch_tag_switcher_2','loaded');
175 var loaded = YUD.hasClass('branch_tag_switcher_2','loaded');
171 if(!loaded){
176 if(!loaded){
172 YUD.addClass('branch_tag_switcher_2','loaded');
177 YUD.addClass('branch_tag_switcher_2','loaded');
173 ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list_2',
178 ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list_2',
174 function(o){},
179 function(o){},
175 function(o){YUD.removeClass('branch_tag_switcher_2','loaded');}
180 function(o){YUD.removeClass('branch_tag_switcher_2','loaded');}
176 ,null);
181 ,null);
177 }
182 }
178 return false;
183 return false;
179 });
184 });
180 </script>
185 </script>
181 <!--- END CONTEXT BAR -->
186 <!--- END CONTEXT BAR -->
182 </%def>
187 </%def>
183
188
184 <%def name="usermenu()">
189 <%def name="usermenu()">
185 ## USER MENU
190 ## USER MENU
186 <li>
191 <li>
187 <a class="menu_link childs" id="quick_login_link">
192 <a class="menu_link childs" id="quick_login_link">
188 <span class="icon">
193 <span class="icon">
189 <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
194 <img src="${h.gravatar_url(c.rhodecode_user.email,20)}" alt="avatar">
190 </span>
195 </span>
191 %if c.rhodecode_user.username != 'default':
196 %if c.rhodecode_user.username != 'default':
192 <span class="menu_link_user">${c.rhodecode_user.username}</span>
197 <span class="menu_link_user">${c.rhodecode_user.username}</span>
193 %if c.unread_notifications != 0:
198 %if c.unread_notifications != 0:
194 <span class="menu_link_notifications">${c.unread_notifications}</span>
199 <span class="menu_link_notifications">${c.unread_notifications}</span>
195 %endif
200 %endif
196 %else:
201 %else:
197 <span>${_('Not logged in')}</span>
202 <span>${_('Not logged in')}</span>
198 %endif
203 %endif
199 </a>
204 </a>
200
205
201 <div class="user-menu">
206 <div class="user-menu">
202 <div id="quick_login">
207 <div id="quick_login">
203 %if c.rhodecode_user.username == 'default':
208 %if c.rhodecode_user.username == 'default':
204 <h4>${_('Login to your account')}</h4>
209 <h4>${_('Login to your account')}</h4>
205 ${h.form(h.url('login_home',came_from=h.url.current()))}
210 ${h.form(h.url('login_home',came_from=h.url.current()))}
206 <div class="form">
211 <div class="form">
207 <div class="fields">
212 <div class="fields">
208 <div class="field">
213 <div class="field">
209 <div class="label">
214 <div class="label">
210 <label for="username">${_('Username')}:</label>
215 <label for="username">${_('Username')}:</label>
211 </div>
216 </div>
212 <div class="input">
217 <div class="input">
213 ${h.text('username',class_='focus')}
218 ${h.text('username',class_='focus')}
214 </div>
219 </div>
215
220
216 </div>
221 </div>
217 <div class="field">
222 <div class="field">
218 <div class="label">
223 <div class="label">
219 <label for="password">${_('Password')}:</label>
224 <label for="password">${_('Password')}:</label>
220 </div>
225 </div>
221 <div class="input">
226 <div class="input">
222 ${h.password('password',class_='focus')}
227 ${h.password('password',class_='focus')}
223 </div>
228 </div>
224
229
225 </div>
230 </div>
226 <div class="buttons">
231 <div class="buttons">
227 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
232 <div class="password_forgoten">${h.link_to(_('Forgot password ?'),h.url('reset_password'))}</div>
228 <div class="register">
233 <div class="register">
229 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
234 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
230 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
235 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
231 %endif
236 %endif
232 </div>
237 </div>
233 <div class="submit">
238 <div class="submit">
234 ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
239 ${h.submit('sign_in',_('Log In'),class_="ui-btn xsmall")}
235 </div>
240 </div>
236 </div>
241 </div>
237 </div>
242 </div>
238 </div>
243 </div>
239 ${h.end_form()}
244 ${h.end_form()}
240 %else:
245 %else:
241 <div class="links_left">
246 <div class="links_left">
242 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
247 <div class="big_gravatar"><img alt="gravatar" src="${h.gravatar_url(c.rhodecode_user.email,48)}" /></div>
243 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
248 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
244 <div class="email">${c.rhodecode_user.email}</div>
249 <div class="email">${c.rhodecode_user.email}</div>
245 </div>
250 </div>
246 <div class="links_right">
251 <div class="links_right">
247 <ol class="links">
252 <ol class="links">
248 <li><a href="${h.url('notifications')}">${_('Notifications')}: ${c.unread_notifications}</a></li>
253 <li><a href="${h.url('notifications')}">${_('Notifications')}: ${c.unread_notifications}</a></li>
249 <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
254 <li>${h.link_to(_(u'My account'),h.url('admin_settings_my_account'))}</li>
250 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
255 <li class="logout">${h.link_to(_(u'Log Out'),h.url('logout_home'))}</li>
251 </ol>
256 </ol>
252 </div>
257 </div>
253 %endif
258 %endif
254 </div>
259 </div>
255 </div>
260 </div>
256
261
257 </li>
262 </li>
258 </%def>
263 </%def>
259
264
260 <%def name="menu(current=None)">
265 <%def name="menu(current=None)">
261 <%
266 <%
262 def is_current(selected):
267 def is_current(selected):
263 if selected == current:
268 if selected == current:
264 return h.literal('class="current"')
269 return h.literal('class="current"')
265 %>
270 %>
266 <ul id="quick" class="horizontal-list">
271 <ul id="quick" class="horizontal-list">
267 <!-- repo switcher -->
272 <!-- repo switcher -->
268 <li ${is_current('repositories')}>
273 <li ${is_current('repositories')}>
269 <a class="menu_link repo_switcher childs" id="repo_switcher" title="${_('Switch repository')}" href="${h.url('home')}">
274 <a class="menu_link repo_switcher childs" id="repo_switcher" title="${_('Switch repository')}" href="${h.url('home')}">
270 ${_('Repositories')}
275 ${_('Repositories')}
271 </a>
276 </a>
272 <ul id="repo_switcher_list" class="repo_switcher">
277 <ul id="repo_switcher_list" class="repo_switcher">
273 <li>
278 <li>
274 <a href="#">${_('loading...')}</a>
279 <a href="#">${_('loading...')}</a>
275 </li>
280 </li>
276 </ul>
281 </ul>
277 </li>
282 </li>
278 ##ROOT MENU
283 ##ROOT MENU
279 %if c.rhodecode_user.username != 'default':
284 %if c.rhodecode_user.username != 'default':
280 <li ${is_current('journal')}>
285 <li ${is_current('journal')}>
281 <a class="menu_link journal" title="${_('Show recent activity')}" href="${h.url('journal')}">
286 <a class="menu_link journal" title="${_('Show recent activity')}" href="${h.url('journal')}">
282 ${_('Journal')}
287 ${_('Journal')}
283 </a>
288 </a>
284 </li>
289 </li>
285 %else:
290 %else:
286 <li ${is_current('journal')}>
291 <li ${is_current('journal')}>
287 <a class="menu_link journal" title="${_('Public journal')}" href="${h.url('public_journal')}">
292 <a class="menu_link journal" title="${_('Public journal')}" href="${h.url('public_journal')}">
288 ${_('Public journal')}
293 ${_('Public journal')}
289 </a>
294 </a>
290 </li>
295 </li>
291 %endif
296 %endif
292 <li ${is_current('gists')}>
297 <li ${is_current('gists')}>
293 <a class="menu_link gists childs" title="${_('Show public gists')}" href="${h.url('gists')}">
298 <a class="menu_link gists childs" title="${_('Show public gists')}" href="${h.url('gists')}">
294 ${_('Gists')}
299 ${_('Gists')}
295 </a>
300 </a>
296 <ul class="admin_menu">
301 <ul class="admin_menu">
297 <li>${h.link_to(_('Create new gist'),h.url('new_gist'),class_='gists-new ')}</li>
302 <li>${h.link_to(_('Create new gist'),h.url('new_gist'),class_='gists-new ')}</li>
298 <li>${h.link_to(_('All public gists'),h.url('gists'),class_='gists ')}</li>
303 <li>${h.link_to(_('All public gists'),h.url('gists'),class_='gists ')}</li>
299 %if c.rhodecode_user.username != 'default':
304 %if c.rhodecode_user.username != 'default':
300 <li>${h.link_to(_('My public gists'),h.url('gists', public=1),class_='gists')}</li>
305 <li>${h.link_to(_('My public gists'),h.url('gists', public=1),class_='gists')}</li>
301 <li>${h.link_to(_('My private gists'),h.url('gists', private=1),class_='gists-private ')}</li>
306 <li>${h.link_to(_('My private gists'),h.url('gists', private=1),class_='gists-private ')}</li>
302 %endif
307 %endif
303 </ul>
308 </ul>
304 </li>
309 </li>
305 <li ${is_current('search')}>
310 <li ${is_current('search')}>
306 <a class="menu_link search" title="${_('Search in repositories')}" href="${h.url('search')}">
311 <a class="menu_link search" title="${_('Search in repositories')}" href="${h.url('search')}">
307 ${_('Search')}
312 ${_('Search')}
308 </a>
313 </a>
309 </li>
314 </li>
310 % if h.HasPermissionAll('hg.admin')('access admin main page'):
315 % if h.HasPermissionAll('hg.admin')('access admin main page'):
311 <li ${is_current('admin')}>
316 <li ${is_current('admin')}>
312 <a class="menu_link admin childs" title="${_('Admin')}" href="${h.url('admin_home')}">
317 <a class="menu_link admin childs" title="${_('Admin')}" href="${h.url('admin_home')}">
313 ${_('Admin')}
318 ${_('Admin')}
314 </a>
319 </a>
315 ${admin_menu()}
320 ${admin_menu()}
316 </li>
321 </li>
317 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
322 % elif c.rhodecode_user.repositories_admin or c.rhodecode_user.repository_groups_admin or c.rhodecode_user.user_groups_admin:
318 <li ${is_current('admin')}>
323 <li ${is_current('admin')}>
319 <a class="menu_link admin childs" title="${_('Admin')}">
324 <a class="menu_link admin childs" title="${_('Admin')}">
320 ${_('Admin')}
325 ${_('Admin')}
321 </a>
326 </a>
322 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
327 ${admin_menu_simple(c.rhodecode_user.repositories_admin,
323 c.rhodecode_user.repository_groups_admin,
328 c.rhodecode_user.repository_groups_admin,
324 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
329 c.rhodecode_user.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
325 </li>
330 </li>
326 % endif
331 % endif
327 ${usermenu()}
332 ${usermenu()}
328 <script type="text/javascript">
333 <script type="text/javascript">
329 YUE.on('repo_switcher','mouseover',function(){
334 YUE.on('repo_switcher','mouseover',function(){
330 var target = 'q_filter_rs';
335 var target = 'q_filter_rs';
331 var qfilter_activate = function(){
336 var qfilter_activate = function(){
332 var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
337 var nodes = YUQ('ul#repo_switcher_list li a.repo_name');
333 var func = function(node){
338 var func = function(node){
334 return node.parentNode;
339 return node.parentNode;
335 }
340 }
336 q_filter(target,nodes,func);
341 q_filter(target,nodes,func);
337 }
342 }
338
343
339 var loaded = YUD.hasClass('repo_switcher','loaded');
344 var loaded = YUD.hasClass('repo_switcher','loaded');
340 if(!loaded){
345 if(!loaded){
341 YUD.addClass('repo_switcher','loaded');
346 YUD.addClass('repo_switcher','loaded');
342 ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
347 ypjax("${h.url('repo_switcher')}",'repo_switcher_list',
343 function(o){qfilter_activate();YUD.get(target).focus()},
348 function(o){qfilter_activate();YUD.get(target).focus()},
344 function(o){YUD.removeClass('repo_switcher','loaded');}
349 function(o){YUD.removeClass('repo_switcher','loaded');}
345 ,null);
350 ,null);
346 }else{
351 }else{
347 YUD.get(target).focus();
352 YUD.get(target).focus();
348 }
353 }
349 return false;
354 return false;
350 });
355 });
351
356
352 YUE.on('header-dd', 'click',function(e){
357 YUE.on('header-dd', 'click',function(e){
353 YUD.addClass('header-inner', 'hover');
358 YUD.addClass('header-inner', 'hover');
354 YUD.addClass('content', 'hover');
359 YUD.addClass('content', 'hover');
355 });
360 });
356
361
357 </script>
362 </script>
358 </%def>
363 </%def>
General Comments 0
You need to be logged in to leave comments. Login now