##// END OF EJS Templates
fixes for #89 ga code
marcink -
r891:cca72864 beta
parent child Browse files
Show More
@@ -1,351 +1,351 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) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2009-2010 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
13 # This program is free software; you can redistribute it and/or
14 # modify it under the terms of the GNU General Public License
14 # modify it under the terms of the GNU General Public License
15 # as published by the Free Software Foundation; version 2
15 # as published by the Free Software Foundation; version 2
16 # of the License or (at your opinion) any later version of the license.
16 # of the License or (at your opinion) any later version of the license.
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, write to the Free Software
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 # MA 02110-1301, USA.
26 # MA 02110-1301, USA.
27
27
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import formencode
30 import formencode
31
31
32 from operator import itemgetter
32 from operator import itemgetter
33 from formencode import htmlfill
33 from formencode import htmlfill
34 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
34 from pylons import request, session, tmpl_context as c, url, app_globals as g, \
35 config
35 config
36 from pylons.controllers.util import abort, redirect
36 from pylons.controllers.util import abort, redirect
37 from pylons.i18n.translation import _
37 from pylons.i18n.translation import _
38
38
39 from rhodecode.lib import helpers as h
39 from rhodecode.lib import helpers as h
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
40 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator, \
41 HasPermissionAnyDecorator, NotAnonymous
41 HasPermissionAnyDecorator, NotAnonymous
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, invalidate_cache, \
44 from rhodecode.lib.utils import repo2db_mapper, invalidate_cache, \
45 set_rhodecode_config
45 set_rhodecode_config
46 from rhodecode.model.db import RhodeCodeUi, Repository
46 from rhodecode.model.db import RhodeCodeUi, Repository
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
47 from rhodecode.model.forms import UserForm, ApplicationSettingsForm, \
48 ApplicationUiSettingsForm
48 ApplicationUiSettingsForm
49 from rhodecode.model.scm import ScmModel
49 from rhodecode.model.scm import ScmModel
50 from rhodecode.model.settings import SettingsModel
50 from rhodecode.model.settings import SettingsModel
51 from rhodecode.model.user import UserModel
51 from rhodecode.model.user import UserModel
52
52
53 from sqlalchemy import func
53 from sqlalchemy import func
54
54
55
55
56 log = logging.getLogger(__name__)
56 log = logging.getLogger(__name__)
57
57
58
58
59 class SettingsController(BaseController):
59 class SettingsController(BaseController):
60 """REST Controller styled on the Atom Publishing Protocol"""
60 """REST Controller styled on the Atom Publishing Protocol"""
61 # To properly map this controller, ensure your config/routing.py
61 # To properly map this controller, ensure your config/routing.py
62 # file has a resource setup:
62 # file has a resource setup:
63 # map.resource('setting', 'settings', controller='admin/settings',
63 # map.resource('setting', 'settings', controller='admin/settings',
64 # path_prefix='/admin', name_prefix='admin_')
64 # path_prefix='/admin', name_prefix='admin_')
65
65
66
66
67 @LoginRequired()
67 @LoginRequired()
68 def __before__(self):
68 def __before__(self):
69 c.admin_user = session.get('admin_user')
69 c.admin_user = session.get('admin_user')
70 c.admin_username = session.get('admin_username')
70 c.admin_username = session.get('admin_username')
71 super(SettingsController, self).__before__()
71 super(SettingsController, self).__before__()
72
72
73
73
74 @HasPermissionAllDecorator('hg.admin')
74 @HasPermissionAllDecorator('hg.admin')
75 def index(self, format='html'):
75 def index(self, format='html'):
76 """GET /admin/settings: All items in the collection"""
76 """GET /admin/settings: All items in the collection"""
77 # url('admin_settings')
77 # url('admin_settings')
78
78
79 defaults = SettingsModel().get_app_settings()
79 defaults = SettingsModel().get_app_settings()
80 defaults.update(self.get_hg_ui_settings())
80 defaults.update(self.get_hg_ui_settings())
81 return htmlfill.render(
81 return htmlfill.render(
82 render('admin/settings/settings.html'),
82 render('admin/settings/settings.html'),
83 defaults=defaults,
83 defaults=defaults,
84 encoding="UTF-8",
84 encoding="UTF-8",
85 force_defaults=False
85 force_defaults=False
86 )
86 )
87
87
88 @HasPermissionAllDecorator('hg.admin')
88 @HasPermissionAllDecorator('hg.admin')
89 def create(self):
89 def create(self):
90 """POST /admin/settings: Create a new item"""
90 """POST /admin/settings: Create a new item"""
91 # url('admin_settings')
91 # url('admin_settings')
92
92
93 @HasPermissionAllDecorator('hg.admin')
93 @HasPermissionAllDecorator('hg.admin')
94 def new(self, format='html'):
94 def new(self, format='html'):
95 """GET /admin/settings/new: Form to create a new item"""
95 """GET /admin/settings/new: Form to create a new item"""
96 # url('admin_new_setting')
96 # url('admin_new_setting')
97
97
98 @HasPermissionAllDecorator('hg.admin')
98 @HasPermissionAllDecorator('hg.admin')
99 def update(self, setting_id):
99 def update(self, setting_id):
100 """PUT /admin/settings/setting_id: Update an existing item"""
100 """PUT /admin/settings/setting_id: Update an existing item"""
101 # Forms posted to this method should contain a hidden field:
101 # Forms posted to this method should contain a hidden field:
102 # <input type="hidden" name="_method" value="PUT" />
102 # <input type="hidden" name="_method" value="PUT" />
103 # Or using helpers:
103 # Or using helpers:
104 # h.form(url('admin_setting', setting_id=ID),
104 # h.form(url('admin_setting', setting_id=ID),
105 # method='put')
105 # method='put')
106 # url('admin_setting', setting_id=ID)
106 # url('admin_setting', setting_id=ID)
107 if setting_id == 'mapping':
107 if setting_id == 'mapping':
108 rm_obsolete = request.POST.get('destroy', False)
108 rm_obsolete = request.POST.get('destroy', False)
109 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
109 log.debug('Rescanning directories with destroy=%s', rm_obsolete)
110
110
111 initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
111 initial = ScmModel().repo_scan(g.paths[0][1], g.baseui)
112 for repo_name in initial.keys():
112 for repo_name in initial.keys():
113 invalidate_cache('get_repo_cached_%s' % repo_name)
113 invalidate_cache('get_repo_cached_%s' % repo_name)
114
114
115 repo2db_mapper(initial, rm_obsolete)
115 repo2db_mapper(initial, rm_obsolete)
116
116
117 h.flash(_('Repositories successfully rescanned'), category='success')
117 h.flash(_('Repositories successfully rescanned'), category='success')
118
118
119 if setting_id == 'whoosh':
119 if setting_id == 'whoosh':
120 repo_location = self.get_hg_ui_settings()['paths_root_path']
120 repo_location = self.get_hg_ui_settings()['paths_root_path']
121 full_index = request.POST.get('full_index', False)
121 full_index = request.POST.get('full_index', False)
122 task = run_task(tasks.whoosh_index, repo_location, full_index)
122 task = run_task(tasks.whoosh_index, repo_location, full_index)
123
123
124 h.flash(_('Whoosh reindex task scheduled'), category='success')
124 h.flash(_('Whoosh reindex task scheduled'), category='success')
125 if setting_id == 'global':
125 if setting_id == 'global':
126
126
127 application_form = ApplicationSettingsForm()()
127 application_form = ApplicationSettingsForm()()
128 try:
128 try:
129 form_result = application_form.to_python(dict(request.POST))
129 form_result = application_form.to_python(dict(request.POST))
130 settings_model = SettingsModel()
130 settings_model = SettingsModel()
131
131
132 try:
132 try:
133 hgsettings1 = settings_model.get('title')
133 hgsettings1 = settings_model.get('title')
134 hgsettings1.app_settings_value = form_result['rhodecode_title']
134 hgsettings1.app_settings_value = form_result['rhodecode_title']
135
135
136 hgsettings2 = settings_model.get('realm')
136 hgsettings2 = settings_model.get('realm')
137 hgsettings2.app_settings_value = form_result['rhodecode_realm']
137 hgsettings2.app_settings_value = form_result['rhodecode_realm']
138
138
139 hgsettings3 = settings_model.get('ga_code')
139 hgsettings3 = settings_model.get('ga_code')
140 hgsettings3.app_settings_value = form_result['ga_code']
140 hgsettings3.app_settings_value = form_result['rhodecode_ga_code']
141
141
142
142
143
143
144 self.sa.add(hgsettings1)
144 self.sa.add(hgsettings1)
145 self.sa.add(hgsettings2)
145 self.sa.add(hgsettings2)
146 self.sa.add(hgsettings3)
146 self.sa.add(hgsettings3)
147 self.sa.commit()
147 self.sa.commit()
148 set_rhodecode_config(config)
148 set_rhodecode_config(config)
149 h.flash(_('Updated application settings'),
149 h.flash(_('Updated application settings'),
150 category='success')
150 category='success')
151
151
152 except:
152 except:
153 log.error(traceback.format_exc())
153 log.error(traceback.format_exc())
154 h.flash(_('error occurred during updating application settings'),
154 h.flash(_('error occurred during updating application settings'),
155 category='error')
155 category='error')
156
156
157 self.sa.rollback()
157 self.sa.rollback()
158
158
159
159
160 except formencode.Invalid, errors:
160 except formencode.Invalid, errors:
161 return htmlfill.render(
161 return htmlfill.render(
162 render('admin/settings/settings.html'),
162 render('admin/settings/settings.html'),
163 defaults=errors.value,
163 defaults=errors.value,
164 errors=errors.error_dict or {},
164 errors=errors.error_dict or {},
165 prefix_error=False,
165 prefix_error=False,
166 encoding="UTF-8")
166 encoding="UTF-8")
167
167
168 if setting_id == 'mercurial':
168 if setting_id == 'mercurial':
169 application_form = ApplicationUiSettingsForm()()
169 application_form = ApplicationUiSettingsForm()()
170 try:
170 try:
171 form_result = application_form.to_python(dict(request.POST))
171 form_result = application_form.to_python(dict(request.POST))
172
172
173 try:
173 try:
174
174
175 hgsettings1 = self.sa.query(RhodeCodeUi)\
175 hgsettings1 = self.sa.query(RhodeCodeUi)\
176 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
176 .filter(RhodeCodeUi.ui_key == 'push_ssl').one()
177 hgsettings1.ui_value = form_result['web_push_ssl']
177 hgsettings1.ui_value = form_result['web_push_ssl']
178
178
179 hgsettings2 = self.sa.query(RhodeCodeUi)\
179 hgsettings2 = self.sa.query(RhodeCodeUi)\
180 .filter(RhodeCodeUi.ui_key == '/').one()
180 .filter(RhodeCodeUi.ui_key == '/').one()
181 hgsettings2.ui_value = form_result['paths_root_path']
181 hgsettings2.ui_value = form_result['paths_root_path']
182
182
183
183
184 #HOOKS
184 #HOOKS
185 hgsettings3 = self.sa.query(RhodeCodeUi)\
185 hgsettings3 = self.sa.query(RhodeCodeUi)\
186 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
186 .filter(RhodeCodeUi.ui_key == 'changegroup.update').one()
187 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
187 hgsettings3.ui_active = bool(form_result['hooks_changegroup_update'])
188
188
189 hgsettings4 = self.sa.query(RhodeCodeUi)\
189 hgsettings4 = self.sa.query(RhodeCodeUi)\
190 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
190 .filter(RhodeCodeUi.ui_key == 'changegroup.repo_size').one()
191 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
191 hgsettings4.ui_active = bool(form_result['hooks_changegroup_repo_size'])
192
192
193 hgsettings5 = self.sa.query(RhodeCodeUi)\
193 hgsettings5 = self.sa.query(RhodeCodeUi)\
194 .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
194 .filter(RhodeCodeUi.ui_key == 'pretxnchangegroup.push_logger').one()
195 hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
195 hgsettings5.ui_active = bool(form_result['hooks_pretxnchangegroup_push_logger'])
196
196
197 hgsettings6 = self.sa.query(RhodeCodeUi)\
197 hgsettings6 = self.sa.query(RhodeCodeUi)\
198 .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
198 .filter(RhodeCodeUi.ui_key == 'preoutgoing.pull_logger').one()
199 hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
199 hgsettings6.ui_active = bool(form_result['hooks_preoutgoing_pull_logger'])
200
200
201
201
202 self.sa.add(hgsettings1)
202 self.sa.add(hgsettings1)
203 self.sa.add(hgsettings2)
203 self.sa.add(hgsettings2)
204 self.sa.add(hgsettings3)
204 self.sa.add(hgsettings3)
205 self.sa.add(hgsettings4)
205 self.sa.add(hgsettings4)
206 self.sa.add(hgsettings5)
206 self.sa.add(hgsettings5)
207 self.sa.add(hgsettings6)
207 self.sa.add(hgsettings6)
208 self.sa.commit()
208 self.sa.commit()
209
209
210 h.flash(_('Updated mercurial settings'),
210 h.flash(_('Updated mercurial settings'),
211 category='success')
211 category='success')
212
212
213 except:
213 except:
214 log.error(traceback.format_exc())
214 log.error(traceback.format_exc())
215 h.flash(_('error occurred during updating application settings'),
215 h.flash(_('error occurred during updating application settings'),
216 category='error')
216 category='error')
217
217
218 self.sa.rollback()
218 self.sa.rollback()
219
219
220
220
221 except formencode.Invalid, errors:
221 except formencode.Invalid, errors:
222 return htmlfill.render(
222 return htmlfill.render(
223 render('admin/settings/settings.html'),
223 render('admin/settings/settings.html'),
224 defaults=errors.value,
224 defaults=errors.value,
225 errors=errors.error_dict or {},
225 errors=errors.error_dict or {},
226 prefix_error=False,
226 prefix_error=False,
227 encoding="UTF-8")
227 encoding="UTF-8")
228
228
229
229
230
230
231 return redirect(url('admin_settings'))
231 return redirect(url('admin_settings'))
232
232
233 @HasPermissionAllDecorator('hg.admin')
233 @HasPermissionAllDecorator('hg.admin')
234 def delete(self, setting_id):
234 def delete(self, setting_id):
235 """DELETE /admin/settings/setting_id: Delete an existing item"""
235 """DELETE /admin/settings/setting_id: Delete an existing item"""
236 # Forms posted to this method should contain a hidden field:
236 # Forms posted to this method should contain a hidden field:
237 # <input type="hidden" name="_method" value="DELETE" />
237 # <input type="hidden" name="_method" value="DELETE" />
238 # Or using helpers:
238 # Or using helpers:
239 # h.form(url('admin_setting', setting_id=ID),
239 # h.form(url('admin_setting', setting_id=ID),
240 # method='delete')
240 # method='delete')
241 # url('admin_setting', setting_id=ID)
241 # url('admin_setting', setting_id=ID)
242
242
243 @HasPermissionAllDecorator('hg.admin')
243 @HasPermissionAllDecorator('hg.admin')
244 def show(self, setting_id, format='html'):
244 def show(self, setting_id, format='html'):
245 """GET /admin/settings/setting_id: Show a specific item"""
245 """GET /admin/settings/setting_id: Show a specific item"""
246 # url('admin_setting', setting_id=ID)
246 # url('admin_setting', setting_id=ID)
247
247
248 @HasPermissionAllDecorator('hg.admin')
248 @HasPermissionAllDecorator('hg.admin')
249 def edit(self, setting_id, format='html'):
249 def edit(self, setting_id, format='html'):
250 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
250 """GET /admin/settings/setting_id/edit: Form to edit an existing item"""
251 # url('admin_edit_setting', setting_id=ID)
251 # url('admin_edit_setting', setting_id=ID)
252
252
253 @NotAnonymous()
253 @NotAnonymous()
254 def my_account(self):
254 def my_account(self):
255 """
255 """
256 GET /_admin/my_account Displays info about my account
256 GET /_admin/my_account Displays info about my account
257 """
257 """
258 # url('admin_settings_my_account')
258 # url('admin_settings_my_account')
259
259
260 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
260 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
261 all_repos = self.sa.query(Repository)\
261 all_repos = self.sa.query(Repository)\
262 .filter(Repository.user_id == c.user.user_id)\
262 .filter(Repository.user_id == c.user.user_id)\
263 .order_by(func.lower(Repository.repo_name))\
263 .order_by(func.lower(Repository.repo_name))\
264 .all()
264 .all()
265
265
266 c.user_repos = ScmModel().get_repos(all_repos)
266 c.user_repos = ScmModel().get_repos(all_repos)
267
267
268 if c.user.username == 'default':
268 if c.user.username == 'default':
269 h.flash(_("You can't edit this user since it's"
269 h.flash(_("You can't edit this user since it's"
270 " crucial for entire application"), category='warning')
270 " crucial for entire application"), category='warning')
271 return redirect(url('users'))
271 return redirect(url('users'))
272
272
273 defaults = c.user.get_dict()
273 defaults = c.user.get_dict()
274 return htmlfill.render(
274 return htmlfill.render(
275 render('admin/users/user_edit_my_account.html'),
275 render('admin/users/user_edit_my_account.html'),
276 defaults=defaults,
276 defaults=defaults,
277 encoding="UTF-8",
277 encoding="UTF-8",
278 force_defaults=False
278 force_defaults=False
279 )
279 )
280
280
281 def my_account_update(self):
281 def my_account_update(self):
282 """PUT /_admin/my_account_update: Update an existing item"""
282 """PUT /_admin/my_account_update: Update an existing item"""
283 # Forms posted to this method should contain a hidden field:
283 # Forms posted to this method should contain a hidden field:
284 # <input type="hidden" name="_method" value="PUT" />
284 # <input type="hidden" name="_method" value="PUT" />
285 # Or using helpers:
285 # Or using helpers:
286 # h.form(url('admin_settings_my_account_update'),
286 # h.form(url('admin_settings_my_account_update'),
287 # method='put')
287 # method='put')
288 # url('admin_settings_my_account_update', id=ID)
288 # url('admin_settings_my_account_update', id=ID)
289 user_model = UserModel()
289 user_model = UserModel()
290 uid = c.rhodecode_user.user_id
290 uid = c.rhodecode_user.user_id
291 _form = UserForm(edit=True, old_data={'user_id':uid,
291 _form = UserForm(edit=True, old_data={'user_id':uid,
292 'email':c.rhodecode_user.email})()
292 'email':c.rhodecode_user.email})()
293 form_result = {}
293 form_result = {}
294 try:
294 try:
295 form_result = _form.to_python(dict(request.POST))
295 form_result = _form.to_python(dict(request.POST))
296 user_model.update_my_account(uid, form_result)
296 user_model.update_my_account(uid, form_result)
297 h.flash(_('Your account was updated successfully'),
297 h.flash(_('Your account was updated successfully'),
298 category='success')
298 category='success')
299
299
300 except formencode.Invalid, errors:
300 except formencode.Invalid, errors:
301 c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
301 c.user = user_model.get(c.rhodecode_user.user_id, cache=False)
302 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
302 c.user = UserModel().get(c.rhodecode_user.user_id, cache=False)
303 all_repos = self.sa.query(Repository)\
303 all_repos = self.sa.query(Repository)\
304 .filter(Repository.user_id == c.user.user_id)\
304 .filter(Repository.user_id == c.user.user_id)\
305 .order_by(func.lower(Repository.repo_name))\
305 .order_by(func.lower(Repository.repo_name))\
306 .all()
306 .all()
307 c.user_repos = ScmModel().get_repos(all_repos)
307 c.user_repos = ScmModel().get_repos(all_repos)
308
308
309 return htmlfill.render(
309 return htmlfill.render(
310 render('admin/users/user_edit_my_account.html'),
310 render('admin/users/user_edit_my_account.html'),
311 defaults=errors.value,
311 defaults=errors.value,
312 errors=errors.error_dict or {},
312 errors=errors.error_dict or {},
313 prefix_error=False,
313 prefix_error=False,
314 encoding="UTF-8")
314 encoding="UTF-8")
315 except Exception:
315 except Exception:
316 log.error(traceback.format_exc())
316 log.error(traceback.format_exc())
317 h.flash(_('error occurred during update of user %s') \
317 h.flash(_('error occurred during update of user %s') \
318 % form_result.get('username'), category='error')
318 % form_result.get('username'), category='error')
319
319
320 return redirect(url('my_account'))
320 return redirect(url('my_account'))
321
321
322 @NotAnonymous()
322 @NotAnonymous()
323 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
323 @HasPermissionAnyDecorator('hg.admin', 'hg.create.repository')
324 def create_repository(self):
324 def create_repository(self):
325 """GET /_admin/create_repository: Form to create a new item"""
325 """GET /_admin/create_repository: Form to create a new item"""
326 new_repo = request.GET.get('repo', '')
326 new_repo = request.GET.get('repo', '')
327 c.new_repo = h.repo_name_slug(new_repo)
327 c.new_repo = h.repo_name_slug(new_repo)
328
328
329 return render('admin/repos/repo_add_create_repository.html')
329 return render('admin/repos/repo_add_create_repository.html')
330
330
331 def get_hg_ui_settings(self):
331 def get_hg_ui_settings(self):
332 ret = self.sa.query(RhodeCodeUi).all()
332 ret = self.sa.query(RhodeCodeUi).all()
333
333
334 if not ret:
334 if not ret:
335 raise Exception('Could not get application ui settings !')
335 raise Exception('Could not get application ui settings !')
336 settings = {}
336 settings = {}
337 for each in ret:
337 for each in ret:
338 k = each.ui_key
338 k = each.ui_key
339 v = each.ui_value
339 v = each.ui_value
340 if k == '/':
340 if k == '/':
341 k = 'root_path'
341 k = 'root_path'
342
342
343 if k.find('.') != -1:
343 if k.find('.') != -1:
344 k = k.replace('.', '_')
344 k = k.replace('.', '_')
345
345
346 if each.ui_section == 'hooks':
346 if each.ui_section == 'hooks':
347 v = each.ui_active
347 v = each.ui_active
348
348
349 settings[each.ui_section + '_' + k] = v
349 settings[each.ui_section + '_' + k] = v
350
350
351 return settings
351 return settings
@@ -1,53 +1,53 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 from pylons import config, tmpl_context as c, request, session
5 from pylons import config, tmpl_context as c, request, session
6 from pylons.controllers import WSGIController
6 from pylons.controllers import WSGIController
7 from pylons.templating import render_mako as render
7 from pylons.templating import render_mako as render
8 from rhodecode import __version__
8 from rhodecode import __version__
9 from rhodecode.lib import auth
9 from rhodecode.lib import auth
10 from rhodecode.lib.utils import get_repo_slug
10 from rhodecode.lib.utils import get_repo_slug
11 from rhodecode.model import meta
11 from rhodecode.model import meta
12 from rhodecode.model.scm import ScmModel
12 from rhodecode.model.scm import ScmModel
13 from rhodecode import BACKENDS
13 from rhodecode import BACKENDS
14
14
15 class BaseController(WSGIController):
15 class BaseController(WSGIController):
16
16
17 def __before__(self):
17 def __before__(self):
18 c.rhodecode_version = __version__
18 c.rhodecode_version = __version__
19 c.rhodecode_name = config.get('rhodecode_title')
19 c.rhodecode_name = config.get('rhodecode_title')
20 c.ga_code = config.get('rhodeocode_ga_code')
20 c.ga_code = config.get('rhodecode_ga_code')
21 c.repo_name = get_repo_slug(request)
21 c.repo_name = get_repo_slug(request)
22 c.cached_repo_list = ScmModel().get_repos()
22 c.cached_repo_list = ScmModel().get_repos()
23 c.backends = BACKENDS.keys()
23 c.backends = BACKENDS.keys()
24 self.cut_off_limit = int(config.get('cut_off_limit'))
24 self.cut_off_limit = int(config.get('cut_off_limit'))
25 self.sa = meta.Session()
25 self.sa = meta.Session()
26 scm_model = ScmModel(self.sa)
26 scm_model = ScmModel(self.sa)
27 #c.unread_journal = scm_model.get_unread_journal()
27 #c.unread_journal = scm_model.get_unread_journal()
28
28
29 if c.repo_name:
29 if c.repo_name:
30 cached_repo = scm_model.get(c.repo_name)
30 cached_repo = scm_model.get(c.repo_name)
31 if cached_repo:
31 if cached_repo:
32 c.repository_tags = cached_repo.tags
32 c.repository_tags = cached_repo.tags
33 c.repository_branches = cached_repo.branches
33 c.repository_branches = cached_repo.branches
34 c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
34 c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
35 c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
35 c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
36 else:
36 else:
37 c.repository_tags = {}
37 c.repository_tags = {}
38 c.repository_branches = {}
38 c.repository_branches = {}
39 c.repository_followers = 0
39 c.repository_followers = 0
40 c.repository_forks = 0
40 c.repository_forks = 0
41
41
42
42
43 def __call__(self, environ, start_response):
43 def __call__(self, environ, start_response):
44 """Invoke the Controller"""
44 """Invoke the Controller"""
45 # WSGIController.__call__ dispatches to the Controller method
45 # WSGIController.__call__ dispatches to the Controller method
46 # the request is routed to. This routing information is
46 # the request is routed to. This routing information is
47 # available in environ['pylons.routes_dict']
47 # available in environ['pylons.routes_dict']
48 try:
48 try:
49 #putting this here makes sure that we update permissions every time
49 #putting this here makes sure that we update permissions every time
50 self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
50 self.rhodecode_user = c.rhodecode_user = auth.get_user(session)
51 return WSGIController.__call__(self, environ, start_response)
51 return WSGIController.__call__(self, environ, start_response)
52 finally:
52 finally:
53 meta.Session.remove()
53 meta.Session.remove()
@@ -1,484 +1,484 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 os
22 import os
23 import re
23 import re
24 import logging
24 import logging
25
25
26 import formencode
26 import formencode
27 from formencode import All
27 from formencode import All
28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
28 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 Email, Bool, StringBoolean
29 Email, Bool, StringBoolean
30
30
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 import rhodecode.lib.helpers as h
33 import rhodecode.lib.helpers as h
34 from rhodecode.lib.auth import authenticate, get_crypt_password
34 from rhodecode.lib.auth import authenticate, get_crypt_password
35 from rhodecode.lib.exceptions import LdapImportError
35 from rhodecode.lib.exceptions import LdapImportError
36 from rhodecode.model import meta
36 from rhodecode.model import meta
37 from rhodecode.model.user import UserModel
37 from rhodecode.model.user import UserModel
38 from rhodecode.model.repo import RepoModel
38 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.db import User
39 from rhodecode.model.db import User
40 from rhodecode import BACKENDS
40 from rhodecode import BACKENDS
41
41
42 from webhelpers.pylonslib.secure_form import authentication_token
42 from webhelpers.pylonslib.secure_form import authentication_token
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46 #this is needed to translate the messages using _() in validators
46 #this is needed to translate the messages using _() in validators
47 class State_obj(object):
47 class State_obj(object):
48 _ = staticmethod(_)
48 _ = staticmethod(_)
49
49
50 #===============================================================================
50 #===============================================================================
51 # VALIDATORS
51 # VALIDATORS
52 #===============================================================================
52 #===============================================================================
53 class ValidAuthToken(formencode.validators.FancyValidator):
53 class ValidAuthToken(formencode.validators.FancyValidator):
54 messages = {'invalid_token':_('Token mismatch')}
54 messages = {'invalid_token':_('Token mismatch')}
55
55
56 def validate_python(self, value, state):
56 def validate_python(self, value, state):
57
57
58 if value != authentication_token():
58 if value != authentication_token():
59 raise formencode.Invalid(self.message('invalid_token', state,
59 raise formencode.Invalid(self.message('invalid_token', state,
60 search_number=value), value, state)
60 search_number=value), value, state)
61
61
62 def ValidUsername(edit, old_data):
62 def ValidUsername(edit, old_data):
63 class _ValidUsername(formencode.validators.FancyValidator):
63 class _ValidUsername(formencode.validators.FancyValidator):
64
64
65 def validate_python(self, value, state):
65 def validate_python(self, value, state):
66 if value in ['default', 'new_user']:
66 if value in ['default', 'new_user']:
67 raise formencode.Invalid(_('Invalid username'), value, state)
67 raise formencode.Invalid(_('Invalid username'), value, state)
68 #check if user is unique
68 #check if user is unique
69 old_un = None
69 old_un = None
70 if edit:
70 if edit:
71 old_un = UserModel().get(old_data.get('user_id')).username
71 old_un = UserModel().get(old_data.get('user_id')).username
72
72
73 if old_un != value or not edit:
73 if old_un != value or not edit:
74 if UserModel().get_by_username(value, cache=False,
74 if UserModel().get_by_username(value, cache=False,
75 case_insensitive=True):
75 case_insensitive=True):
76 raise formencode.Invalid(_('This username already exists') ,
76 raise formencode.Invalid(_('This username already exists') ,
77 value, state)
77 value, state)
78
78
79
79
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
80 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_]+$', value) is None:
81 raise formencode.Invalid(_('Username may only contain '
81 raise formencode.Invalid(_('Username may only contain '
82 'alphanumeric characters underscores '
82 'alphanumeric characters underscores '
83 'or dashes and must begin with '
83 'or dashes and must begin with '
84 'alphanumeric character'),
84 'alphanumeric character'),
85 value, state)
85 value, state)
86
86
87
87
88
88
89 return _ValidUsername
89 return _ValidUsername
90
90
91 class ValidPassword(formencode.validators.FancyValidator):
91 class ValidPassword(formencode.validators.FancyValidator):
92
92
93 def to_python(self, value, state):
93 def to_python(self, value, state):
94
94
95 if value:
95 if value:
96
96
97 if value.get('password'):
97 if value.get('password'):
98 try:
98 try:
99 value['password'] = get_crypt_password(value['password'])
99 value['password'] = get_crypt_password(value['password'])
100 except UnicodeEncodeError:
100 except UnicodeEncodeError:
101 e_dict = {'password':_('Invalid characters in password')}
101 e_dict = {'password':_('Invalid characters in password')}
102 raise formencode.Invalid('', value, state, error_dict=e_dict)
102 raise formencode.Invalid('', value, state, error_dict=e_dict)
103
103
104 if value.get('password_confirmation'):
104 if value.get('password_confirmation'):
105 try:
105 try:
106 value['password_confirmation'] = \
106 value['password_confirmation'] = \
107 get_crypt_password(value['password_confirmation'])
107 get_crypt_password(value['password_confirmation'])
108 except UnicodeEncodeError:
108 except UnicodeEncodeError:
109 e_dict = {'password_confirmation':_('Invalid characters in password')}
109 e_dict = {'password_confirmation':_('Invalid characters in password')}
110 raise formencode.Invalid('', value, state, error_dict=e_dict)
110 raise formencode.Invalid('', value, state, error_dict=e_dict)
111
111
112 if value.get('new_password'):
112 if value.get('new_password'):
113 try:
113 try:
114 value['new_password'] = \
114 value['new_password'] = \
115 get_crypt_password(value['new_password'])
115 get_crypt_password(value['new_password'])
116 except UnicodeEncodeError:
116 except UnicodeEncodeError:
117 e_dict = {'new_password':_('Invalid characters in password')}
117 e_dict = {'new_password':_('Invalid characters in password')}
118 raise formencode.Invalid('', value, state, error_dict=e_dict)
118 raise formencode.Invalid('', value, state, error_dict=e_dict)
119
119
120 return value
120 return value
121
121
122 class ValidPasswordsMatch(formencode.validators.FancyValidator):
122 class ValidPasswordsMatch(formencode.validators.FancyValidator):
123
123
124 def validate_python(self, value, state):
124 def validate_python(self, value, state):
125
125
126 if value['password'] != value['password_confirmation']:
126 if value['password'] != value['password_confirmation']:
127 e_dict = {'password_confirmation':
127 e_dict = {'password_confirmation':
128 _('Password do not match')}
128 _('Password do not match')}
129 raise formencode.Invalid('', value, state, error_dict=e_dict)
129 raise formencode.Invalid('', value, state, error_dict=e_dict)
130
130
131 class ValidAuth(formencode.validators.FancyValidator):
131 class ValidAuth(formencode.validators.FancyValidator):
132 messages = {
132 messages = {
133 'invalid_password':_('invalid password'),
133 'invalid_password':_('invalid password'),
134 'invalid_login':_('invalid user name'),
134 'invalid_login':_('invalid user name'),
135 'disabled_account':_('Your account is disabled')
135 'disabled_account':_('Your account is disabled')
136
136
137 }
137 }
138 #error mapping
138 #error mapping
139 e_dict = {'username':messages['invalid_login'],
139 e_dict = {'username':messages['invalid_login'],
140 'password':messages['invalid_password']}
140 'password':messages['invalid_password']}
141 e_dict_disable = {'username':messages['disabled_account']}
141 e_dict_disable = {'username':messages['disabled_account']}
142
142
143 def validate_python(self, value, state):
143 def validate_python(self, value, state):
144 password = value['password']
144 password = value['password']
145 username = value['username']
145 username = value['username']
146 user = UserModel().get_by_username(username)
146 user = UserModel().get_by_username(username)
147
147
148 if authenticate(username, password):
148 if authenticate(username, password):
149 return value
149 return value
150 else:
150 else:
151 if user and user.active is False:
151 if user and user.active is False:
152 log.warning('user %s is disabled', username)
152 log.warning('user %s is disabled', username)
153 raise formencode.Invalid(self.message('disabled_account',
153 raise formencode.Invalid(self.message('disabled_account',
154 state=State_obj),
154 state=State_obj),
155 value, state,
155 value, state,
156 error_dict=self.e_dict_disable)
156 error_dict=self.e_dict_disable)
157 else:
157 else:
158 log.warning('user %s not authenticated', username)
158 log.warning('user %s not authenticated', username)
159 raise formencode.Invalid(self.message('invalid_password',
159 raise formencode.Invalid(self.message('invalid_password',
160 state=State_obj), value, state,
160 state=State_obj), value, state,
161 error_dict=self.e_dict)
161 error_dict=self.e_dict)
162
162
163 class ValidRepoUser(formencode.validators.FancyValidator):
163 class ValidRepoUser(formencode.validators.FancyValidator):
164
164
165 def to_python(self, value, state):
165 def to_python(self, value, state):
166 sa = meta.Session()
166 sa = meta.Session()
167 try:
167 try:
168 self.user_db = sa.query(User)\
168 self.user_db = sa.query(User)\
169 .filter(User.active == True)\
169 .filter(User.active == True)\
170 .filter(User.username == value).one()
170 .filter(User.username == value).one()
171 except Exception:
171 except Exception:
172 raise formencode.Invalid(_('This username is not valid'),
172 raise formencode.Invalid(_('This username is not valid'),
173 value, state)
173 value, state)
174 finally:
174 finally:
175 meta.Session.remove()
175 meta.Session.remove()
176
176
177 return self.user_db.user_id
177 return self.user_db.user_id
178
178
179 def ValidRepoName(edit, old_data):
179 def ValidRepoName(edit, old_data):
180 class _ValidRepoName(formencode.validators.FancyValidator):
180 class _ValidRepoName(formencode.validators.FancyValidator):
181
181
182 def to_python(self, value, state):
182 def to_python(self, value, state):
183 slug = h.repo_name_slug(value)
183 slug = h.repo_name_slug(value)
184 if slug in ['_admin']:
184 if slug in ['_admin']:
185 raise formencode.Invalid(_('This repository name is disallowed'),
185 raise formencode.Invalid(_('This repository name is disallowed'),
186 value, state)
186 value, state)
187 if old_data.get('repo_name') != value or not edit:
187 if old_data.get('repo_name') != value or not edit:
188 if RepoModel().get_by_repo_name(slug, cache=False):
188 if RepoModel().get_by_repo_name(slug, cache=False):
189 raise formencode.Invalid(_('This repository already exists') ,
189 raise formencode.Invalid(_('This repository already exists') ,
190 value, state)
190 value, state)
191 return slug
191 return slug
192
192
193
193
194 return _ValidRepoName
194 return _ValidRepoName
195
195
196 def ValidForkType(old_data):
196 def ValidForkType(old_data):
197 class _ValidForkType(formencode.validators.FancyValidator):
197 class _ValidForkType(formencode.validators.FancyValidator):
198
198
199 def to_python(self, value, state):
199 def to_python(self, value, state):
200 if old_data['repo_type'] != value:
200 if old_data['repo_type'] != value:
201 raise formencode.Invalid(_('Fork have to be the same type as original'),
201 raise formencode.Invalid(_('Fork have to be the same type as original'),
202 value, state)
202 value, state)
203 return value
203 return value
204 return _ValidForkType
204 return _ValidForkType
205
205
206 class ValidPerms(formencode.validators.FancyValidator):
206 class ValidPerms(formencode.validators.FancyValidator):
207 messages = {'perm_new_user_name':_('This username is not valid')}
207 messages = {'perm_new_user_name':_('This username is not valid')}
208
208
209 def to_python(self, value, state):
209 def to_python(self, value, state):
210 perms_update = []
210 perms_update = []
211 perms_new = []
211 perms_new = []
212 #build a list of permission to update and new permission to create
212 #build a list of permission to update and new permission to create
213 for k, v in value.items():
213 for k, v in value.items():
214 if k.startswith('perm_'):
214 if k.startswith('perm_'):
215 if k.startswith('perm_new_user'):
215 if k.startswith('perm_new_user'):
216 new_perm = value.get('perm_new_user', False)
216 new_perm = value.get('perm_new_user', False)
217 new_user = value.get('perm_new_user_name', False)
217 new_user = value.get('perm_new_user_name', False)
218 if new_user and new_perm:
218 if new_user and new_perm:
219 if (new_user, new_perm) not in perms_new:
219 if (new_user, new_perm) not in perms_new:
220 perms_new.append((new_user, new_perm))
220 perms_new.append((new_user, new_perm))
221 else:
221 else:
222 usr = k[5:]
222 usr = k[5:]
223 if usr == 'default':
223 if usr == 'default':
224 if value['private']:
224 if value['private']:
225 #set none for default when updating to private repo
225 #set none for default when updating to private repo
226 v = 'repository.none'
226 v = 'repository.none'
227 perms_update.append((usr, v))
227 perms_update.append((usr, v))
228 value['perms_updates'] = perms_update
228 value['perms_updates'] = perms_update
229 value['perms_new'] = perms_new
229 value['perms_new'] = perms_new
230 sa = meta.Session
230 sa = meta.Session
231 for k, v in perms_new:
231 for k, v in perms_new:
232 try:
232 try:
233 self.user_db = sa.query(User)\
233 self.user_db = sa.query(User)\
234 .filter(User.active == True)\
234 .filter(User.active == True)\
235 .filter(User.username == k).one()
235 .filter(User.username == k).one()
236 except Exception:
236 except Exception:
237 msg = self.message('perm_new_user_name',
237 msg = self.message('perm_new_user_name',
238 state=State_obj)
238 state=State_obj)
239 raise formencode.Invalid(msg, value, state,
239 raise formencode.Invalid(msg, value, state,
240 error_dict={'perm_new_user_name':msg})
240 error_dict={'perm_new_user_name':msg})
241 return value
241 return value
242
242
243 class ValidSettings(formencode.validators.FancyValidator):
243 class ValidSettings(formencode.validators.FancyValidator):
244
244
245 def to_python(self, value, state):
245 def to_python(self, value, state):
246 #settings form can't edit user
246 #settings form can't edit user
247 if value.has_key('user'):
247 if value.has_key('user'):
248 del['value']['user']
248 del['value']['user']
249
249
250 return value
250 return value
251
251
252 class ValidPath(formencode.validators.FancyValidator):
252 class ValidPath(formencode.validators.FancyValidator):
253 def to_python(self, value, state):
253 def to_python(self, value, state):
254
254
255 if not os.path.isdir(value):
255 if not os.path.isdir(value):
256 msg = _('This is not a valid path')
256 msg = _('This is not a valid path')
257 raise formencode.Invalid(msg, value, state,
257 raise formencode.Invalid(msg, value, state,
258 error_dict={'paths_root_path':msg})
258 error_dict={'paths_root_path':msg})
259 return value
259 return value
260
260
261 def UniqSystemEmail(old_data):
261 def UniqSystemEmail(old_data):
262 class _UniqSystemEmail(formencode.validators.FancyValidator):
262 class _UniqSystemEmail(formencode.validators.FancyValidator):
263 def to_python(self, value, state):
263 def to_python(self, value, state):
264 value = value.lower()
264 value = value.lower()
265 if old_data.get('email') != value:
265 if old_data.get('email') != value:
266 sa = meta.Session()
266 sa = meta.Session()
267 try:
267 try:
268 user = sa.query(User).filter(User.email == value).scalar()
268 user = sa.query(User).filter(User.email == value).scalar()
269 if user:
269 if user:
270 raise formencode.Invalid(_("This e-mail address is already taken") ,
270 raise formencode.Invalid(_("This e-mail address is already taken") ,
271 value, state)
271 value, state)
272 finally:
272 finally:
273 meta.Session.remove()
273 meta.Session.remove()
274
274
275 return value
275 return value
276
276
277 return _UniqSystemEmail
277 return _UniqSystemEmail
278
278
279 class ValidSystemEmail(formencode.validators.FancyValidator):
279 class ValidSystemEmail(formencode.validators.FancyValidator):
280 def to_python(self, value, state):
280 def to_python(self, value, state):
281 value = value.lower()
281 value = value.lower()
282 sa = meta.Session
282 sa = meta.Session
283 try:
283 try:
284 user = sa.query(User).filter(User.email == value).scalar()
284 user = sa.query(User).filter(User.email == value).scalar()
285 if user is None:
285 if user is None:
286 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
286 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
287 value, state)
287 value, state)
288 finally:
288 finally:
289 meta.Session.remove()
289 meta.Session.remove()
290
290
291 return value
291 return value
292
292
293 class LdapLibValidator(formencode.validators.FancyValidator):
293 class LdapLibValidator(formencode.validators.FancyValidator):
294
294
295 def to_python(self, value, state):
295 def to_python(self, value, state):
296
296
297 try:
297 try:
298 import ldap
298 import ldap
299 except ImportError:
299 except ImportError:
300 raise LdapImportError
300 raise LdapImportError
301 return value
301 return value
302
302
303 class BaseDnValidator(formencode.validators.FancyValidator):
303 class BaseDnValidator(formencode.validators.FancyValidator):
304
304
305 def to_python(self, value, state):
305 def to_python(self, value, state):
306
306
307 try:
307 try:
308 value % {'user':'valid'}
308 value % {'user':'valid'}
309
309
310 if value.find('%(user)s') == -1:
310 if value.find('%(user)s') == -1:
311 raise formencode.Invalid(_("You need to specify %(user)s in "
311 raise formencode.Invalid(_("You need to specify %(user)s in "
312 "template for example uid=%(user)s "
312 "template for example uid=%(user)s "
313 ",dc=company...") ,
313 ",dc=company...") ,
314 value, state)
314 value, state)
315
315
316 except KeyError:
316 except KeyError:
317 raise formencode.Invalid(_("Wrong template used, only %(user)s "
317 raise formencode.Invalid(_("Wrong template used, only %(user)s "
318 "is an valid entry") ,
318 "is an valid entry") ,
319 value, state)
319 value, state)
320
320
321 return value
321 return value
322
322
323 #===============================================================================
323 #===============================================================================
324 # FORMS
324 # FORMS
325 #===============================================================================
325 #===============================================================================
326 class LoginForm(formencode.Schema):
326 class LoginForm(formencode.Schema):
327 allow_extra_fields = True
327 allow_extra_fields = True
328 filter_extra_fields = True
328 filter_extra_fields = True
329 username = UnicodeString(
329 username = UnicodeString(
330 strip=True,
330 strip=True,
331 min=1,
331 min=1,
332 not_empty=True,
332 not_empty=True,
333 messages={
333 messages={
334 'empty':_('Please enter a login'),
334 'empty':_('Please enter a login'),
335 'tooShort':_('Enter a value %(min)i characters long or more')}
335 'tooShort':_('Enter a value %(min)i characters long or more')}
336 )
336 )
337
337
338 password = UnicodeString(
338 password = UnicodeString(
339 strip=True,
339 strip=True,
340 min=6,
340 min=6,
341 not_empty=True,
341 not_empty=True,
342 messages={
342 messages={
343 'empty':_('Please enter a password'),
343 'empty':_('Please enter a password'),
344 'tooShort':_('Enter %(min)i characters or more')}
344 'tooShort':_('Enter %(min)i characters or more')}
345 )
345 )
346
346
347
347
348 #chained validators have access to all data
348 #chained validators have access to all data
349 chained_validators = [ValidAuth]
349 chained_validators = [ValidAuth]
350
350
351 def UserForm(edit=False, old_data={}):
351 def UserForm(edit=False, old_data={}):
352 class _UserForm(formencode.Schema):
352 class _UserForm(formencode.Schema):
353 allow_extra_fields = True
353 allow_extra_fields = True
354 filter_extra_fields = True
354 filter_extra_fields = True
355 username = All(UnicodeString(strip=True, min=1, not_empty=True),
355 username = All(UnicodeString(strip=True, min=1, not_empty=True),
356 ValidUsername(edit, old_data))
356 ValidUsername(edit, old_data))
357 if edit:
357 if edit:
358 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
358 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
359 admin = StringBoolean(if_missing=False)
359 admin = StringBoolean(if_missing=False)
360 else:
360 else:
361 password = All(UnicodeString(strip=True, min=6, not_empty=True))
361 password = All(UnicodeString(strip=True, min=6, not_empty=True))
362 active = StringBoolean(if_missing=False)
362 active = StringBoolean(if_missing=False)
363 name = UnicodeString(strip=True, min=1, not_empty=True)
363 name = UnicodeString(strip=True, min=1, not_empty=True)
364 lastname = UnicodeString(strip=True, min=1, not_empty=True)
364 lastname = UnicodeString(strip=True, min=1, not_empty=True)
365 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
365 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
366
366
367 chained_validators = [ValidPassword]
367 chained_validators = [ValidPassword]
368
368
369 return _UserForm
369 return _UserForm
370
370
371 def RegisterForm(edit=False, old_data={}):
371 def RegisterForm(edit=False, old_data={}):
372 class _RegisterForm(formencode.Schema):
372 class _RegisterForm(formencode.Schema):
373 allow_extra_fields = True
373 allow_extra_fields = True
374 filter_extra_fields = True
374 filter_extra_fields = True
375 username = All(ValidUsername(edit, old_data),
375 username = All(ValidUsername(edit, old_data),
376 UnicodeString(strip=True, min=1, not_empty=True))
376 UnicodeString(strip=True, min=1, not_empty=True))
377 password = All(UnicodeString(strip=True, min=6, not_empty=True))
377 password = All(UnicodeString(strip=True, min=6, not_empty=True))
378 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
378 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
379 active = StringBoolean(if_missing=False)
379 active = StringBoolean(if_missing=False)
380 name = UnicodeString(strip=True, min=1, not_empty=True)
380 name = UnicodeString(strip=True, min=1, not_empty=True)
381 lastname = UnicodeString(strip=True, min=1, not_empty=True)
381 lastname = UnicodeString(strip=True, min=1, not_empty=True)
382 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
382 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
383
383
384 chained_validators = [ValidPasswordsMatch, ValidPassword]
384 chained_validators = [ValidPasswordsMatch, ValidPassword]
385
385
386 return _RegisterForm
386 return _RegisterForm
387
387
388 def PasswordResetForm():
388 def PasswordResetForm():
389 class _PasswordResetForm(formencode.Schema):
389 class _PasswordResetForm(formencode.Schema):
390 allow_extra_fields = True
390 allow_extra_fields = True
391 filter_extra_fields = True
391 filter_extra_fields = True
392 email = All(ValidSystemEmail(), Email(not_empty=True))
392 email = All(ValidSystemEmail(), Email(not_empty=True))
393 return _PasswordResetForm
393 return _PasswordResetForm
394
394
395 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
395 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
396 class _RepoForm(formencode.Schema):
396 class _RepoForm(formencode.Schema):
397 allow_extra_fields = True
397 allow_extra_fields = True
398 filter_extra_fields = False
398 filter_extra_fields = False
399 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
399 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
400 ValidRepoName(edit, old_data))
400 ValidRepoName(edit, old_data))
401 description = UnicodeString(strip=True, min=1, not_empty=True)
401 description = UnicodeString(strip=True, min=1, not_empty=True)
402 private = StringBoolean(if_missing=False)
402 private = StringBoolean(if_missing=False)
403 enable_statistics = StringBoolean(if_missing=False)
403 enable_statistics = StringBoolean(if_missing=False)
404 repo_type = OneOf(supported_backends)
404 repo_type = OneOf(supported_backends)
405 if edit:
405 if edit:
406 user = All(Int(not_empty=True), ValidRepoUser)
406 user = All(Int(not_empty=True), ValidRepoUser)
407
407
408 chained_validators = [ValidPerms]
408 chained_validators = [ValidPerms]
409 return _RepoForm
409 return _RepoForm
410
410
411 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
411 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
412 class _RepoForkForm(formencode.Schema):
412 class _RepoForkForm(formencode.Schema):
413 allow_extra_fields = True
413 allow_extra_fields = True
414 filter_extra_fields = False
414 filter_extra_fields = False
415 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
415 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
416 ValidRepoName(edit, old_data))
416 ValidRepoName(edit, old_data))
417 description = UnicodeString(strip=True, min=1, not_empty=True)
417 description = UnicodeString(strip=True, min=1, not_empty=True)
418 private = StringBoolean(if_missing=False)
418 private = StringBoolean(if_missing=False)
419 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
419 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
420 return _RepoForkForm
420 return _RepoForkForm
421
421
422 def RepoSettingsForm(edit=False, old_data={}):
422 def RepoSettingsForm(edit=False, old_data={}):
423 class _RepoForm(formencode.Schema):
423 class _RepoForm(formencode.Schema):
424 allow_extra_fields = True
424 allow_extra_fields = True
425 filter_extra_fields = False
425 filter_extra_fields = False
426 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
426 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
427 ValidRepoName(edit, old_data))
427 ValidRepoName(edit, old_data))
428 description = UnicodeString(strip=True, min=1, not_empty=True)
428 description = UnicodeString(strip=True, min=1, not_empty=True)
429 private = StringBoolean(if_missing=False)
429 private = StringBoolean(if_missing=False)
430
430
431 chained_validators = [ValidPerms, ValidSettings]
431 chained_validators = [ValidPerms, ValidSettings]
432 return _RepoForm
432 return _RepoForm
433
433
434
434
435 def ApplicationSettingsForm():
435 def ApplicationSettingsForm():
436 class _ApplicationSettingsForm(formencode.Schema):
436 class _ApplicationSettingsForm(formencode.Schema):
437 allow_extra_fields = True
437 allow_extra_fields = True
438 filter_extra_fields = False
438 filter_extra_fields = False
439 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
439 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
440 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
440 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
441 ga_code = UnicodeString(strip=True, min=1, not_empty=False)
441 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
442
442
443 return _ApplicationSettingsForm
443 return _ApplicationSettingsForm
444
444
445 def ApplicationUiSettingsForm():
445 def ApplicationUiSettingsForm():
446 class _ApplicationUiSettingsForm(formencode.Schema):
446 class _ApplicationUiSettingsForm(formencode.Schema):
447 allow_extra_fields = True
447 allow_extra_fields = True
448 filter_extra_fields = False
448 filter_extra_fields = False
449 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
449 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
450 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
450 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
451 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
451 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
452 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
452 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
453 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
453 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
454 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
454 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
455
455
456 return _ApplicationUiSettingsForm
456 return _ApplicationUiSettingsForm
457
457
458 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
458 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
459 class _DefaultPermissionsForm(formencode.Schema):
459 class _DefaultPermissionsForm(formencode.Schema):
460 allow_extra_fields = True
460 allow_extra_fields = True
461 filter_extra_fields = True
461 filter_extra_fields = True
462 overwrite_default = StringBoolean(if_missing=False)
462 overwrite_default = StringBoolean(if_missing=False)
463 anonymous = OneOf(['True', 'False'], if_missing=False)
463 anonymous = OneOf(['True', 'False'], if_missing=False)
464 default_perm = OneOf(perms_choices)
464 default_perm = OneOf(perms_choices)
465 default_register = OneOf(register_choices)
465 default_register = OneOf(register_choices)
466 default_create = OneOf(create_choices)
466 default_create = OneOf(create_choices)
467
467
468 return _DefaultPermissionsForm
468 return _DefaultPermissionsForm
469
469
470
470
471 def LdapSettingsForm():
471 def LdapSettingsForm():
472 class _LdapSettingsForm(formencode.Schema):
472 class _LdapSettingsForm(formencode.Schema):
473 allow_extra_fields = True
473 allow_extra_fields = True
474 filter_extra_fields = True
474 filter_extra_fields = True
475 pre_validators = [LdapLibValidator]
475 pre_validators = [LdapLibValidator]
476 ldap_active = StringBoolean(if_missing=False)
476 ldap_active = StringBoolean(if_missing=False)
477 ldap_host = UnicodeString(strip=True,)
477 ldap_host = UnicodeString(strip=True,)
478 ldap_port = Number(strip=True,)
478 ldap_port = Number(strip=True,)
479 ldap_ldaps = StringBoolean(if_missing=False)
479 ldap_ldaps = StringBoolean(if_missing=False)
480 ldap_dn_user = UnicodeString(strip=True,)
480 ldap_dn_user = UnicodeString(strip=True,)
481 ldap_dn_pass = UnicodeString(strip=True,)
481 ldap_dn_pass = UnicodeString(strip=True,)
482 ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
482 ldap_base_dn = All(BaseDnValidator, UnicodeString(strip=True,))
483
483
484 return _LdapSettingsForm
484 return _LdapSettingsForm
@@ -1,189 +1,189 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')} - ${c.rhodecode_name}
5 ${_('Settings administration')} - ${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'))} &raquo; ${_('Settings')}
9 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; ${_('Settings')}
10 </%def>
10 </%def>
11
11
12 <%def name="page_nav()">
12 <%def name="page_nav()">
13 ${self.menu('admin')}
13 ${self.menu('admin')}
14 </%def>
14 </%def>
15
15
16 <%def name="main()">
16 <%def name="main()">
17 <div class="box">
17 <div class="box">
18 <!-- box / title -->
18 <!-- box / title -->
19 <div class="title">
19 <div class="title">
20 ${self.breadcrumbs()}
20 ${self.breadcrumbs()}
21 </div>
21 </div>
22 <!-- end box / title -->
22 <!-- end box / title -->
23
23
24 <h3>${_('Remap and rescan repositories')}</h3>
24 <h3>${_('Remap and rescan repositories')}</h3>
25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
25 ${h.form(url('admin_setting', setting_id='mapping'),method='put')}
26 <div class="form">
26 <div class="form">
27 <!-- fields -->
27 <!-- fields -->
28
28
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label label-checkbox">
31 <div class="label label-checkbox">
32 <label for="destroy">${_('rescan option')}:</label>
32 <label for="destroy">${_('rescan option')}:</label>
33 </div>
33 </div>
34 <div class="checkboxes">
34 <div class="checkboxes">
35 <div class="checkbox">
35 <div class="checkbox">
36 ${h.checkbox('destroy',True)}
36 ${h.checkbox('destroy',True)}
37 <label for="checkbox-1">
37 <label for="checkbox-1">
38 <span class="tooltip" 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.'))}">
38 <span class="tooltip" 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.'))}">
39 ${_('destroy old data')}</span> </label>
39 ${_('destroy old data')}</span> </label>
40 </div>
40 </div>
41 </div>
41 </div>
42 </div>
42 </div>
43
43
44 <div class="buttons">
44 <div class="buttons">
45 ${h.submit('rescan','Rescan repositories',class_="ui-button")}
45 ${h.submit('rescan','Rescan repositories',class_="ui-button")}
46 </div>
46 </div>
47 </div>
47 </div>
48 </div>
48 </div>
49 ${h.end_form()}
49 ${h.end_form()}
50
50
51 <h3>${_('Whoosh indexing')}</h3>
51 <h3>${_('Whoosh indexing')}</h3>
52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
52 ${h.form(url('admin_setting', setting_id='whoosh'),method='put')}
53 <div class="form">
53 <div class="form">
54 <!-- fields -->
54 <!-- fields -->
55
55
56 <div class="fields">
56 <div class="fields">
57 <div class="field">
57 <div class="field">
58 <div class="label label-checkbox">
58 <div class="label label-checkbox">
59 <label for="destroy">${_('index build option')}:</label>
59 <label for="destroy">${_('index build option')}:</label>
60 </div>
60 </div>
61 <div class="checkboxes">
61 <div class="checkboxes">
62 <div class="checkbox">
62 <div class="checkbox">
63 ${h.checkbox('full_index',True)}
63 ${h.checkbox('full_index',True)}
64 <label for="checkbox-1">${_('build from scratch')}</label>
64 <label for="checkbox-1">${_('build from scratch')}</label>
65 </div>
65 </div>
66 </div>
66 </div>
67 </div>
67 </div>
68
68
69 <div class="buttons">
69 <div class="buttons">
70 ${h.submit('reindex','Reindex',class_="ui-button")}
70 ${h.submit('reindex','Reindex',class_="ui-button")}
71 </div>
71 </div>
72 </div>
72 </div>
73 </div>
73 </div>
74 ${h.end_form()}
74 ${h.end_form()}
75
75
76 <h3>${_('Global application settings')}</h3>
76 <h3>${_('Global application settings')}</h3>
77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
77 ${h.form(url('admin_setting', setting_id='global'),method='put')}
78 <div class="form">
78 <div class="form">
79 <!-- fields -->
79 <!-- fields -->
80
80
81 <div class="fields">
81 <div class="fields">
82
82
83 <div class="field">
83 <div class="field">
84 <div class="label">
84 <div class="label">
85 <label for="rhodecode_title">${_('Application name')}:</label>
85 <label for="rhodecode_title">${_('Application name')}:</label>
86 </div>
86 </div>
87 <div class="input">
87 <div class="input">
88 ${h.text('rhodecode_title',size=30)}
88 ${h.text('rhodecode_title',size=30)}
89 </div>
89 </div>
90 </div>
90 </div>
91
91
92 <div class="field">
92 <div class="field">
93 <div class="label">
93 <div class="label">
94 <label for="rhodecode_realm">${_('Realm text')}:</label>
94 <label for="rhodecode_realm">${_('Realm text')}:</label>
95 </div>
95 </div>
96 <div class="input">
96 <div class="input">
97 ${h.text('rhodecode_realm',size=30)}
97 ${h.text('rhodecode_realm',size=30)}
98 </div>
98 </div>
99 </div>
99 </div>
100
100
101 <div class="field">
101 <div class="field">
102 <div class="label">
102 <div class="label">
103 <label for="ga_code">${_('Google analytics code')}:</label>
103 <label for="ga_code">${_('Google analytics code')}:</label>
104 </div>
104 </div>
105 <div class="input">
105 <div class="input">
106 ${h.text('ga_code',size=30)}
106 ${h.text('rhodecode_ga_code',size=30)}
107 </div>
107 </div>
108 </div>
108 </div>
109
109
110 <div class="buttons">
110 <div class="buttons">
111 ${h.submit('save','Save settings',class_="ui-button")}
111 ${h.submit('save','Save settings',class_="ui-button")}
112 ${h.reset('reset','Reset',class_="ui-button")}
112 ${h.reset('reset','Reset',class_="ui-button")}
113 </div>
113 </div>
114 </div>
114 </div>
115 </div>
115 </div>
116 ${h.end_form()}
116 ${h.end_form()}
117
117
118 <h3>${_('Mercurial settings')}</h3>
118 <h3>${_('Mercurial settings')}</h3>
119 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
119 ${h.form(url('admin_setting', setting_id='mercurial'),method='put')}
120 <div class="form">
120 <div class="form">
121 <!-- fields -->
121 <!-- fields -->
122
122
123 <div class="fields">
123 <div class="fields">
124
124
125 <div class="field">
125 <div class="field">
126 <div class="label label-checkbox">
126 <div class="label label-checkbox">
127 <label for="web_push_ssl">${_('Web')}:</label>
127 <label for="web_push_ssl">${_('Web')}:</label>
128 </div>
128 </div>
129 <div class="checkboxes">
129 <div class="checkboxes">
130 <div class="checkbox">
130 <div class="checkbox">
131 ${h.checkbox('web_push_ssl','true')}
131 ${h.checkbox('web_push_ssl','true')}
132 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
132 <label for="web_push_ssl">${_('require ssl for pushing')}</label>
133 </div>
133 </div>
134 </div>
134 </div>
135 </div>
135 </div>
136
136
137 <div class="field">
137 <div class="field">
138 <div class="label label-checkbox">
138 <div class="label label-checkbox">
139 <label for="web_push_ssl">${_('Hooks')}:</label>
139 <label for="web_push_ssl">${_('Hooks')}:</label>
140 </div>
140 </div>
141 <div class="checkboxes">
141 <div class="checkboxes">
142 <div class="checkbox">
142 <div class="checkbox">
143 ${h.checkbox('hooks_changegroup_update','True')}
143 ${h.checkbox('hooks_changegroup_update','True')}
144 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
144 <label for="hooks_changegroup_update">${_('Update repository after push (hg update)')}</label>
145 </div>
145 </div>
146 <div class="checkbox">
146 <div class="checkbox">
147 ${h.checkbox('hooks_changegroup_repo_size','True')}
147 ${h.checkbox('hooks_changegroup_repo_size','True')}
148 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
148 <label for="hooks_changegroup_repo_size">${_('Show repository size after push')}</label>
149 </div>
149 </div>
150 <div class="checkbox">
150 <div class="checkbox">
151 ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
151 ${h.checkbox('hooks_pretxnchangegroup_push_logger','True')}
152 <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
152 <label for="hooks_pretxnchangegroup_push_logger">${_('Log user push commands')}</label>
153 </div>
153 </div>
154 <div class="checkbox">
154 <div class="checkbox">
155 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
155 ${h.checkbox('hooks_preoutgoing_pull_logger','True')}
156 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
156 <label for="hooks_preoutgoing_pull_logger">${_('Log user pull commands')}</label>
157 </div>
157 </div>
158 </div>
158 </div>
159 </div>
159 </div>
160
160
161 <div class="field">
161 <div class="field">
162 <div class="label">
162 <div class="label">
163 <label for="paths_root_path">${_('Repositories location')}:</label>
163 <label for="paths_root_path">${_('Repositories location')}:</label>
164 </div>
164 </div>
165 <div class="input">
165 <div class="input">
166 ${h.text('paths_root_path',size=30,readonly="readonly")}
166 ${h.text('paths_root_path',size=30,readonly="readonly")}
167 <span id="path_unlock" class="tooltip"
167 <span id="path_unlock" class="tooltip"
168 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
168 tooltip_title="${h.tooltip(_('This a crucial application setting. If You really sure you need to change this, you must restart application in order to make this settings take effect. Click this label to unlock.'))}">
169 ${_('unlock')}</span>
169 ${_('unlock')}</span>
170 </div>
170 </div>
171 </div>
171 </div>
172
172
173 <div class="buttons">
173 <div class="buttons">
174 ${h.submit('save','Save settings',class_="ui-button")}
174 ${h.submit('save','Save settings',class_="ui-button")}
175 ${h.reset('reset','Reset',class_="ui-button")}
175 ${h.reset('reset','Reset',class_="ui-button")}
176 </div>
176 </div>
177 </div>
177 </div>
178 </div>
178 </div>
179 ${h.end_form()}
179 ${h.end_form()}
180
180
181 <script type="text/javascript">
181 <script type="text/javascript">
182 YAHOO.util.Event.onDOMReady(function(){
182 YAHOO.util.Event.onDOMReady(function(){
183 YAHOO.util.Event.addListener('path_unlock','click',function(){
183 YAHOO.util.Event.addListener('path_unlock','click',function(){
184 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
184 YAHOO.util.Dom.get('paths_root_path').removeAttribute('readonly');
185 });
185 });
186 });
186 });
187 </script>
187 </script>
188 </div>
188 </div>
189 </%def>
189 </%def>
General Comments 0
You need to be logged in to leave comments. Login now