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