##// END OF EJS Templates
backported fix for #337
marcink -
r1899:0f463fa8 default
parent child Browse files
Show More
@@ -1,694 +1,716
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 import traceback
25 import traceback
26
26
27 import formencode
27 import formencode
28 from formencode import All
28 from formencode import All
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
29 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
30 Email, Bool, StringBoolean, Set
30 Email, Bool, StringBoolean, Set
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34
34
35 from rhodecode.config.routing import ADMIN_PREFIX
35 from rhodecode.config.routing import ADMIN_PREFIX
36 from rhodecode.lib.utils import repo_name_slug
36 from rhodecode.lib.utils import repo_name_slug
37 from rhodecode.lib.auth import authenticate, get_crypt_password
37 from rhodecode.lib.auth import authenticate, get_crypt_password
38 from rhodecode.lib.exceptions import LdapImportError
38 from rhodecode.lib.exceptions import LdapImportError
39 from rhodecode.model.user import UserModel
39 from rhodecode.model.user import UserModel
40 from rhodecode.model.repo import RepoModel
40 from rhodecode.model.repo import RepoModel
41 from rhodecode.model.db import User, UsersGroup, Group
41 from rhodecode.model.db import User, UsersGroup, Group, Repository
42 from rhodecode import BACKENDS
42 from rhodecode import BACKENDS
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 User.get_by_username(value, case_insensitive=True):
74 if User.get_by_username(value, case_insensitive=True):
75 raise formencode.Invalid(_('This username already '
75 raise formencode.Invalid(_('This username already '
76 'exists') , value, state)
76 'exists') , value, state)
77
77
78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
78 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
79 raise formencode.Invalid(_('Username may only contain '
79 raise formencode.Invalid(_('Username may only contain '
80 'alphanumeric characters '
80 'alphanumeric characters '
81 'underscores, periods or dashes '
81 'underscores, periods or dashes '
82 'and must begin with alphanumeric '
82 'and must begin with alphanumeric '
83 'character'), value, state)
83 'character'), value, state)
84
84
85 return _ValidUsername
85 return _ValidUsername
86
86
87
87
88 def ValidUsersGroup(edit, old_data):
88 def ValidUsersGroup(edit, old_data):
89
89
90 class _ValidUsersGroup(formencode.validators.FancyValidator):
90 class _ValidUsersGroup(formencode.validators.FancyValidator):
91
91
92 def validate_python(self, value, state):
92 def validate_python(self, value, state):
93 if value in ['default']:
93 if value in ['default']:
94 raise formencode.Invalid(_('Invalid group name'), value, state)
94 raise formencode.Invalid(_('Invalid group name'), value, state)
95 #check if group is unique
95 #check if group is unique
96 old_ugname = None
96 old_ugname = None
97 if edit:
97 if edit:
98 old_ugname = UsersGroup.get(
98 old_ugname = UsersGroup.get(
99 old_data.get('users_group_id')).users_group_name
99 old_data.get('users_group_id')).users_group_name
100
100
101 if old_ugname != value or not edit:
101 if old_ugname != value or not edit:
102 if UsersGroup.get_by_group_name(value, cache=False,
102 if UsersGroup.get_by_group_name(value, cache=False,
103 case_insensitive=True):
103 case_insensitive=True):
104 raise formencode.Invalid(_('This users group '
104 raise formencode.Invalid(_('This users group '
105 'already exists') , value,
105 'already exists') , value,
106 state)
106 state)
107
107
108
108
109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
109 if re.match(r'^[a-zA-Z0-9]{1}[a-zA-Z0-9\-\_\.]+$', value) is None:
110 raise formencode.Invalid(_('Group name may only contain '
110 raise formencode.Invalid(_('Group name may only contain '
111 'alphanumeric characters '
111 'alphanumeric characters '
112 'underscores, periods or dashes '
112 'underscores, periods or dashes '
113 'and must begin with alphanumeric '
113 'and must begin with alphanumeric '
114 'character'), value, state)
114 'character'), value, state)
115
115
116 return _ValidUsersGroup
116 return _ValidUsersGroup
117
117
118
118
119 def ValidReposGroup(edit, old_data):
119 def ValidReposGroup(edit, old_data):
120 class _ValidReposGroup(formencode.validators.FancyValidator):
120 class _ValidReposGroup(formencode.validators.FancyValidator):
121
121
122 def validate_python(self, value, state):
122 def validate_python(self, value, state):
123 #TODO WRITE VALIDATIONS
123 # TODO WRITE VALIDATIONS
124 group_name = value.get('group_name')
124 group_name = value.get('group_name')
125 group_parent_id = int(value.get('group_parent_id') or -1)
125 group_parent_id = value.get('group_parent_id')
126
126
127 # slugify repo group just in case :)
127 # slugify repo group just in case :)
128 slug = repo_name_slug(group_name)
128 slug = repo_name_slug(group_name)
129
129
130 # check for parent of self
130 # check for parent of self
131 if edit and old_data['group_id'] == group_parent_id:
131 parent_of_self = lambda: (
132 e_dict = {'group_parent_id':_('Cannot assign this group '
132 old_data['group_id'] == int(group_parent_id)
133 'as parent')}
133 if group_parent_id else False
134 )
135 if edit and parent_of_self():
136 e_dict = {
137 'group_parent_id': _('Cannot assign this group as parent')
138 }
134 raise formencode.Invalid('', value, state,
139 raise formencode.Invalid('', value, state,
135 error_dict=e_dict)
140 error_dict=e_dict)
136
141
137 old_gname = None
142 old_gname = None
138 if edit:
143 if edit:
139 old_gname = Group.get(
144 old_gname = Group.get(
140 old_data.get('group_id')).group_name
145 old_data.get('group_id')).group_name
141
146
142 if old_gname != group_name or not edit:
147 if old_gname != group_name or not edit:
143 # check filesystem
148
144 gr = Group.query().filter(Group.group_name == slug)\
149 # check group
145 .filter(Group.group_parent_id == group_parent_id).scalar()
150 gr = Group.query()\
151 .filter(Group.group_name == slug)\
152 .filter(Group.group_parent_id == group_parent_id)\
153 .scalar()
146
154
147 if gr:
155 if gr:
148 e_dict = {'group_name':_('This group already exists')}
156 e_dict = {
157 'group_name': _('This group already exists')
158 }
159 raise formencode.Invalid('', value, state,
160 error_dict=e_dict)
161
162 # check for same repo
163 repo = Repository.query()\
164 .filter(Repository.repo_name == slug)\
165 .scalar()
166
167 if repo:
168 e_dict = {
169 'group_name': _('Repository with this name already exists')
170 }
149 raise formencode.Invalid('', value, state,
171 raise formencode.Invalid('', value, state,
150 error_dict=e_dict)
172 error_dict=e_dict)
151
173
152 return _ValidReposGroup
174 return _ValidReposGroup
153
175
154 class ValidPassword(formencode.validators.FancyValidator):
176 class ValidPassword(formencode.validators.FancyValidator):
155
177
156 def to_python(self, value, state):
178 def to_python(self, value, state):
157
179
158 if value:
180 if value:
159
181
160 if value.get('password'):
182 if value.get('password'):
161 try:
183 try:
162 value['password'] = get_crypt_password(value['password'])
184 value['password'] = get_crypt_password(value['password'])
163 except UnicodeEncodeError:
185 except UnicodeEncodeError:
164 e_dict = {'password':_('Invalid characters in password')}
186 e_dict = {'password':_('Invalid characters in password')}
165 raise formencode.Invalid('', value, state, error_dict=e_dict)
187 raise formencode.Invalid('', value, state, error_dict=e_dict)
166
188
167 if value.get('password_confirmation'):
189 if value.get('password_confirmation'):
168 try:
190 try:
169 value['password_confirmation'] = \
191 value['password_confirmation'] = \
170 get_crypt_password(value['password_confirmation'])
192 get_crypt_password(value['password_confirmation'])
171 except UnicodeEncodeError:
193 except UnicodeEncodeError:
172 e_dict = {'password_confirmation':_('Invalid characters in password')}
194 e_dict = {'password_confirmation':_('Invalid characters in password')}
173 raise formencode.Invalid('', value, state, error_dict=e_dict)
195 raise formencode.Invalid('', value, state, error_dict=e_dict)
174
196
175 if value.get('new_password'):
197 if value.get('new_password'):
176 try:
198 try:
177 value['new_password'] = \
199 value['new_password'] = \
178 get_crypt_password(value['new_password'])
200 get_crypt_password(value['new_password'])
179 except UnicodeEncodeError:
201 except UnicodeEncodeError:
180 e_dict = {'new_password':_('Invalid characters in password')}
202 e_dict = {'new_password':_('Invalid characters in password')}
181 raise formencode.Invalid('', value, state, error_dict=e_dict)
203 raise formencode.Invalid('', value, state, error_dict=e_dict)
182
204
183 return value
205 return value
184
206
185 class ValidPasswordsMatch(formencode.validators.FancyValidator):
207 class ValidPasswordsMatch(formencode.validators.FancyValidator):
186
208
187 def validate_python(self, value, state):
209 def validate_python(self, value, state):
188
210
189 pass_val = value.get('password') or value.get('new_password')
211 pass_val = value.get('password') or value.get('new_password')
190 if pass_val != value['password_confirmation']:
212 if pass_val != value['password_confirmation']:
191 e_dict = {'password_confirmation':
213 e_dict = {'password_confirmation':
192 _('Passwords do not match')}
214 _('Passwords do not match')}
193 raise formencode.Invalid('', value, state, error_dict=e_dict)
215 raise formencode.Invalid('', value, state, error_dict=e_dict)
194
216
195 class ValidAuth(formencode.validators.FancyValidator):
217 class ValidAuth(formencode.validators.FancyValidator):
196 messages = {
218 messages = {
197 'invalid_password':_('invalid password'),
219 'invalid_password':_('invalid password'),
198 'invalid_login':_('invalid user name'),
220 'invalid_login':_('invalid user name'),
199 'disabled_account':_('Your account is disabled')
221 'disabled_account':_('Your account is disabled')
200 }
222 }
201
223
202 # error mapping
224 # error mapping
203 e_dict = {'username':messages['invalid_login'],
225 e_dict = {'username':messages['invalid_login'],
204 'password':messages['invalid_password']}
226 'password':messages['invalid_password']}
205 e_dict_disable = {'username':messages['disabled_account']}
227 e_dict_disable = {'username':messages['disabled_account']}
206
228
207 def validate_python(self, value, state):
229 def validate_python(self, value, state):
208 password = value['password']
230 password = value['password']
209 username = value['username']
231 username = value['username']
210 user = User.get_by_username(username)
232 user = User.get_by_username(username)
211
233
212 if authenticate(username, password):
234 if authenticate(username, password):
213 return value
235 return value
214 else:
236 else:
215 if user and user.active is False:
237 if user and user.active is False:
216 log.warning('user %s is disabled', username)
238 log.warning('user %s is disabled', username)
217 raise formencode.Invalid(self.message('disabled_account',
239 raise formencode.Invalid(self.message('disabled_account',
218 state=State_obj),
240 state=State_obj),
219 value, state,
241 value, state,
220 error_dict=self.e_dict_disable)
242 error_dict=self.e_dict_disable)
221 else:
243 else:
222 log.warning('user %s not authenticated', username)
244 log.warning('user %s not authenticated', username)
223 raise formencode.Invalid(self.message('invalid_password',
245 raise formencode.Invalid(self.message('invalid_password',
224 state=State_obj), value, state,
246 state=State_obj), value, state,
225 error_dict=self.e_dict)
247 error_dict=self.e_dict)
226
248
227 class ValidRepoUser(formencode.validators.FancyValidator):
249 class ValidRepoUser(formencode.validators.FancyValidator):
228
250
229 def to_python(self, value, state):
251 def to_python(self, value, state):
230 try:
252 try:
231 User.query().filter(User.active == True)\
253 User.query().filter(User.active == True)\
232 .filter(User.username == value).one()
254 .filter(User.username == value).one()
233 except Exception:
255 except Exception:
234 raise formencode.Invalid(_('This username is not valid'),
256 raise formencode.Invalid(_('This username is not valid'),
235 value, state)
257 value, state)
236 return value
258 return value
237
259
238 def ValidRepoName(edit, old_data):
260 def ValidRepoName(edit, old_data):
239 class _ValidRepoName(formencode.validators.FancyValidator):
261 class _ValidRepoName(formencode.validators.FancyValidator):
240 def to_python(self, value, state):
262 def to_python(self, value, state):
241
263
242 repo_name = value.get('repo_name')
264 repo_name = value.get('repo_name')
243
265
244 slug = repo_name_slug(repo_name)
266 slug = repo_name_slug(repo_name)
245 if slug in [ADMIN_PREFIX, '']:
267 if slug in [ADMIN_PREFIX, '']:
246 e_dict = {'repo_name': _('This repository name is disallowed')}
268 e_dict = {'repo_name': _('This repository name is disallowed')}
247 raise formencode.Invalid('', value, state, error_dict=e_dict)
269 raise formencode.Invalid('', value, state, error_dict=e_dict)
248
270
249
271
250 if value.get('repo_group'):
272 if value.get('repo_group'):
251 gr = Group.get(value.get('repo_group'))
273 gr = Group.get(value.get('repo_group'))
252 group_path = gr.full_path
274 group_path = gr.full_path
253 # value needs to be aware of group name in order to check
275 # value needs to be aware of group name in order to check
254 # db key This is an actual just the name to store in the
276 # db key This is an actual just the name to store in the
255 # database
277 # database
256 repo_name_full = group_path + Group.url_sep() + repo_name
278 repo_name_full = group_path + Group.url_sep() + repo_name
257
279
258 else:
280 else:
259 group_path = ''
281 group_path = ''
260 repo_name_full = repo_name
282 repo_name_full = repo_name
261
283
262
284
263 value['repo_name_full'] = repo_name_full
285 value['repo_name_full'] = repo_name_full
264 rename = old_data.get('repo_name') != repo_name_full
286 rename = old_data.get('repo_name') != repo_name_full
265 create = not edit
287 create = not edit
266 if rename or create:
288 if rename or create:
267
289
268 if group_path != '':
290 if group_path != '':
269 if RepoModel().get_by_repo_name(repo_name_full,):
291 if RepoModel().get_by_repo_name(repo_name_full,):
270 e_dict = {'repo_name':_('This repository already '
292 e_dict = {'repo_name':_('This repository already '
271 'exists in a group "%s"') %
293 'exists in a group "%s"') %
272 gr.group_name}
294 gr.group_name}
273 raise formencode.Invalid('', value, state,
295 raise formencode.Invalid('', value, state,
274 error_dict=e_dict)
296 error_dict=e_dict)
275 elif Group.get_by_group_name(repo_name_full):
297 elif Group.get_by_group_name(repo_name_full):
276 e_dict = {'repo_name':_('There is a group with this'
298 e_dict = {'repo_name':_('There is a group with this'
277 ' name already "%s"') %
299 ' name already "%s"') %
278 repo_name_full}
300 repo_name_full}
279 raise formencode.Invalid('', value, state,
301 raise formencode.Invalid('', value, state,
280 error_dict=e_dict)
302 error_dict=e_dict)
281
303
282 elif RepoModel().get_by_repo_name(repo_name_full):
304 elif RepoModel().get_by_repo_name(repo_name_full):
283 e_dict = {'repo_name':_('This repository '
305 e_dict = {'repo_name':_('This repository '
284 'already exists')}
306 'already exists')}
285 raise formencode.Invalid('', value, state,
307 raise formencode.Invalid('', value, state,
286 error_dict=e_dict)
308 error_dict=e_dict)
287
309
288 return value
310 return value
289
311
290 return _ValidRepoName
312 return _ValidRepoName
291
313
292 def ValidForkName():
314 def ValidForkName():
293 class _ValidForkName(formencode.validators.FancyValidator):
315 class _ValidForkName(formencode.validators.FancyValidator):
294 def to_python(self, value, state):
316 def to_python(self, value, state):
295
317
296 repo_name = value.get('fork_name')
318 repo_name = value.get('fork_name')
297
319
298 slug = repo_name_slug(repo_name)
320 slug = repo_name_slug(repo_name)
299 if slug in [ADMIN_PREFIX, '']:
321 if slug in [ADMIN_PREFIX, '']:
300 e_dict = {'repo_name': _('This repository name is disallowed')}
322 e_dict = {'repo_name': _('This repository name is disallowed')}
301 raise formencode.Invalid('', value, state, error_dict=e_dict)
323 raise formencode.Invalid('', value, state, error_dict=e_dict)
302
324
303 if RepoModel().get_by_repo_name(repo_name):
325 if RepoModel().get_by_repo_name(repo_name):
304 e_dict = {'fork_name':_('This repository '
326 e_dict = {'fork_name':_('This repository '
305 'already exists')}
327 'already exists')}
306 raise formencode.Invalid('', value, state,
328 raise formencode.Invalid('', value, state,
307 error_dict=e_dict)
329 error_dict=e_dict)
308 return value
330 return value
309 return _ValidForkName
331 return _ValidForkName
310
332
311
333
312 def SlugifyName():
334 def SlugifyName():
313 class _SlugifyName(formencode.validators.FancyValidator):
335 class _SlugifyName(formencode.validators.FancyValidator):
314
336
315 def to_python(self, value, state):
337 def to_python(self, value, state):
316 return repo_name_slug(value)
338 return repo_name_slug(value)
317
339
318 return _SlugifyName
340 return _SlugifyName
319
341
320 def ValidCloneUri():
342 def ValidCloneUri():
321 from mercurial.httprepo import httprepository, httpsrepository
343 from mercurial.httprepo import httprepository, httpsrepository
322 from rhodecode.lib.utils import make_ui
344 from rhodecode.lib.utils import make_ui
323
345
324 class _ValidCloneUri(formencode.validators.FancyValidator):
346 class _ValidCloneUri(formencode.validators.FancyValidator):
325
347
326 def to_python(self, value, state):
348 def to_python(self, value, state):
327 if not value:
349 if not value:
328 pass
350 pass
329 elif value.startswith('https'):
351 elif value.startswith('https'):
330 try:
352 try:
331 httpsrepository(make_ui('db'), value).capabilities
353 httpsrepository(make_ui('db'), value).capabilities
332 except Exception, e:
354 except Exception, e:
333 log.error(traceback.format_exc())
355 log.error(traceback.format_exc())
334 raise formencode.Invalid(_('invalid clone url'), value,
356 raise formencode.Invalid(_('invalid clone url'), value,
335 state)
357 state)
336 elif value.startswith('http'):
358 elif value.startswith('http'):
337 try:
359 try:
338 httprepository(make_ui('db'), value).capabilities
360 httprepository(make_ui('db'), value).capabilities
339 except Exception, e:
361 except Exception, e:
340 log.error(traceback.format_exc())
362 log.error(traceback.format_exc())
341 raise formencode.Invalid(_('invalid clone url'), value,
363 raise formencode.Invalid(_('invalid clone url'), value,
342 state)
364 state)
343 else:
365 else:
344 raise formencode.Invalid(_('Invalid clone url, provide a '
366 raise formencode.Invalid(_('Invalid clone url, provide a '
345 'valid clone http\s url'), value,
367 'valid clone http\s url'), value,
346 state)
368 state)
347 return value
369 return value
348
370
349 return _ValidCloneUri
371 return _ValidCloneUri
350
372
351 def ValidForkType(old_data):
373 def ValidForkType(old_data):
352 class _ValidForkType(formencode.validators.FancyValidator):
374 class _ValidForkType(formencode.validators.FancyValidator):
353
375
354 def to_python(self, value, state):
376 def to_python(self, value, state):
355 if old_data['repo_type'] != value:
377 if old_data['repo_type'] != value:
356 raise formencode.Invalid(_('Fork have to be the same '
378 raise formencode.Invalid(_('Fork have to be the same '
357 'type as original'), value, state)
379 'type as original'), value, state)
358
380
359 return value
381 return value
360 return _ValidForkType
382 return _ValidForkType
361
383
362 class ValidPerms(formencode.validators.FancyValidator):
384 class ValidPerms(formencode.validators.FancyValidator):
363 messages = {'perm_new_member_name':_('This username or users group name'
385 messages = {'perm_new_member_name':_('This username or users group name'
364 ' is not valid')}
386 ' is not valid')}
365
387
366 def to_python(self, value, state):
388 def to_python(self, value, state):
367 perms_update = []
389 perms_update = []
368 perms_new = []
390 perms_new = []
369 #build a list of permission to update and new permission to create
391 #build a list of permission to update and new permission to create
370 for k, v in value.items():
392 for k, v in value.items():
371 #means new added member to permissions
393 #means new added member to permissions
372 if k.startswith('perm_new_member'):
394 if k.startswith('perm_new_member'):
373 new_perm = value.get('perm_new_member', False)
395 new_perm = value.get('perm_new_member', False)
374 new_member = value.get('perm_new_member_name', False)
396 new_member = value.get('perm_new_member_name', False)
375 new_type = value.get('perm_new_member_type')
397 new_type = value.get('perm_new_member_type')
376
398
377 if new_member and new_perm:
399 if new_member and new_perm:
378 if (new_member, new_perm, new_type) not in perms_new:
400 if (new_member, new_perm, new_type) not in perms_new:
379 perms_new.append((new_member, new_perm, new_type))
401 perms_new.append((new_member, new_perm, new_type))
380 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
402 elif k.startswith('u_perm_') or k.startswith('g_perm_'):
381 member = k[7:]
403 member = k[7:]
382 t = {'u':'user',
404 t = {'u':'user',
383 'g':'users_group'}[k[0]]
405 'g':'users_group'}[k[0]]
384 if member == 'default':
406 if member == 'default':
385 if value['private']:
407 if value['private']:
386 #set none for default when updating to private repo
408 #set none for default when updating to private repo
387 v = 'repository.none'
409 v = 'repository.none'
388 perms_update.append((member, v, t))
410 perms_update.append((member, v, t))
389
411
390 value['perms_updates'] = perms_update
412 value['perms_updates'] = perms_update
391 value['perms_new'] = perms_new
413 value['perms_new'] = perms_new
392
414
393 #update permissions
415 #update permissions
394 for k, v, t in perms_new:
416 for k, v, t in perms_new:
395 try:
417 try:
396 if t is 'user':
418 if t is 'user':
397 self.user_db = User.query()\
419 self.user_db = User.query()\
398 .filter(User.active == True)\
420 .filter(User.active == True)\
399 .filter(User.username == k).one()
421 .filter(User.username == k).one()
400 if t is 'users_group':
422 if t is 'users_group':
401 self.user_db = UsersGroup.query()\
423 self.user_db = UsersGroup.query()\
402 .filter(UsersGroup.users_group_active == True)\
424 .filter(UsersGroup.users_group_active == True)\
403 .filter(UsersGroup.users_group_name == k).one()
425 .filter(UsersGroup.users_group_name == k).one()
404
426
405 except Exception:
427 except Exception:
406 msg = self.message('perm_new_member_name',
428 msg = self.message('perm_new_member_name',
407 state=State_obj)
429 state=State_obj)
408 raise formencode.Invalid(msg, value, state,
430 raise formencode.Invalid(msg, value, state,
409 error_dict={'perm_new_member_name':msg})
431 error_dict={'perm_new_member_name':msg})
410 return value
432 return value
411
433
412 class ValidSettings(formencode.validators.FancyValidator):
434 class ValidSettings(formencode.validators.FancyValidator):
413
435
414 def to_python(self, value, state):
436 def to_python(self, value, state):
415 #settings form can't edit user
437 #settings form can't edit user
416 if value.has_key('user'):
438 if value.has_key('user'):
417 del['value']['user']
439 del['value']['user']
418
440
419 return value
441 return value
420
442
421 class ValidPath(formencode.validators.FancyValidator):
443 class ValidPath(formencode.validators.FancyValidator):
422 def to_python(self, value, state):
444 def to_python(self, value, state):
423
445
424 if not os.path.isdir(value):
446 if not os.path.isdir(value):
425 msg = _('This is not a valid path')
447 msg = _('This is not a valid path')
426 raise formencode.Invalid(msg, value, state,
448 raise formencode.Invalid(msg, value, state,
427 error_dict={'paths_root_path':msg})
449 error_dict={'paths_root_path':msg})
428 return value
450 return value
429
451
430 def UniqSystemEmail(old_data):
452 def UniqSystemEmail(old_data):
431 class _UniqSystemEmail(formencode.validators.FancyValidator):
453 class _UniqSystemEmail(formencode.validators.FancyValidator):
432 def to_python(self, value, state):
454 def to_python(self, value, state):
433 value = value.lower()
455 value = value.lower()
434 if old_data.get('email') != value:
456 if old_data.get('email') != value:
435 user = User.query().filter(User.email == value).scalar()
457 user = User.query().filter(User.email == value).scalar()
436 if user:
458 if user:
437 raise formencode.Invalid(
459 raise formencode.Invalid(
438 _("This e-mail address is already taken"),
460 _("This e-mail address is already taken"),
439 value, state)
461 value, state)
440 return value
462 return value
441
463
442 return _UniqSystemEmail
464 return _UniqSystemEmail
443
465
444 class ValidSystemEmail(formencode.validators.FancyValidator):
466 class ValidSystemEmail(formencode.validators.FancyValidator):
445 def to_python(self, value, state):
467 def to_python(self, value, state):
446 value = value.lower()
468 value = value.lower()
447 user = User.query().filter(User.email == value).scalar()
469 user = User.query().filter(User.email == value).scalar()
448 if user is None:
470 if user is None:
449 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
471 raise formencode.Invalid(_("This e-mail address doesn't exist.") ,
450 value, state)
472 value, state)
451
473
452 return value
474 return value
453
475
454 class LdapLibValidator(formencode.validators.FancyValidator):
476 class LdapLibValidator(formencode.validators.FancyValidator):
455
477
456 def to_python(self, value, state):
478 def to_python(self, value, state):
457
479
458 try:
480 try:
459 import ldap
481 import ldap
460 except ImportError:
482 except ImportError:
461 raise LdapImportError
483 raise LdapImportError
462 return value
484 return value
463
485
464 class AttrLoginValidator(formencode.validators.FancyValidator):
486 class AttrLoginValidator(formencode.validators.FancyValidator):
465
487
466 def to_python(self, value, state):
488 def to_python(self, value, state):
467
489
468 if not value or not isinstance(value, (str, unicode)):
490 if not value or not isinstance(value, (str, unicode)):
469 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
491 raise formencode.Invalid(_("The LDAP Login attribute of the CN "
470 "must be specified - this is the name "
492 "must be specified - this is the name "
471 "of the attribute that is equivalent "
493 "of the attribute that is equivalent "
472 "to 'username'"),
494 "to 'username'"),
473 value, state)
495 value, state)
474
496
475 return value
497 return value
476
498
477 #===============================================================================
499 #===============================================================================
478 # FORMS
500 # FORMS
479 #===============================================================================
501 #===============================================================================
480 class LoginForm(formencode.Schema):
502 class LoginForm(formencode.Schema):
481 allow_extra_fields = True
503 allow_extra_fields = True
482 filter_extra_fields = True
504 filter_extra_fields = True
483 username = UnicodeString(
505 username = UnicodeString(
484 strip=True,
506 strip=True,
485 min=1,
507 min=1,
486 not_empty=True,
508 not_empty=True,
487 messages={
509 messages={
488 'empty':_('Please enter a login'),
510 'empty':_('Please enter a login'),
489 'tooShort':_('Enter a value %(min)i characters long or more')}
511 'tooShort':_('Enter a value %(min)i characters long or more')}
490 )
512 )
491
513
492 password = UnicodeString(
514 password = UnicodeString(
493 strip=True,
515 strip=True,
494 min=3,
516 min=3,
495 not_empty=True,
517 not_empty=True,
496 messages={
518 messages={
497 'empty':_('Please enter a password'),
519 'empty':_('Please enter a password'),
498 'tooShort':_('Enter %(min)i characters or more')}
520 'tooShort':_('Enter %(min)i characters or more')}
499 )
521 )
500
522
501 chained_validators = [ValidAuth]
523 chained_validators = [ValidAuth]
502
524
503 def UserForm(edit=False, old_data={}):
525 def UserForm(edit=False, old_data={}):
504 class _UserForm(formencode.Schema):
526 class _UserForm(formencode.Schema):
505 allow_extra_fields = True
527 allow_extra_fields = True
506 filter_extra_fields = True
528 filter_extra_fields = True
507 username = All(UnicodeString(strip=True, min=1, not_empty=True),
529 username = All(UnicodeString(strip=True, min=1, not_empty=True),
508 ValidUsername(edit, old_data))
530 ValidUsername(edit, old_data))
509 if edit:
531 if edit:
510 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
532 new_password = All(UnicodeString(strip=True, min=6, not_empty=False))
511 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
533 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
512 admin = StringBoolean(if_missing=False)
534 admin = StringBoolean(if_missing=False)
513 else:
535 else:
514 password = All(UnicodeString(strip=True, min=6, not_empty=True))
536 password = All(UnicodeString(strip=True, min=6, not_empty=True))
515 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
537 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=False))
516
538
517 active = StringBoolean(if_missing=False)
539 active = StringBoolean(if_missing=False)
518 name = UnicodeString(strip=True, min=1, not_empty=True)
540 name = UnicodeString(strip=True, min=1, not_empty=True)
519 lastname = UnicodeString(strip=True, min=1, not_empty=True)
541 lastname = UnicodeString(strip=True, min=1, not_empty=True)
520 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
542 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
521
543
522 chained_validators = [ValidPasswordsMatch, ValidPassword]
544 chained_validators = [ValidPasswordsMatch, ValidPassword]
523
545
524 return _UserForm
546 return _UserForm
525
547
526
548
527 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
549 def UsersGroupForm(edit=False, old_data={}, available_members=[]):
528 class _UsersGroupForm(formencode.Schema):
550 class _UsersGroupForm(formencode.Schema):
529 allow_extra_fields = True
551 allow_extra_fields = True
530 filter_extra_fields = True
552 filter_extra_fields = True
531
553
532 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
554 users_group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
533 ValidUsersGroup(edit, old_data))
555 ValidUsersGroup(edit, old_data))
534
556
535 users_group_active = StringBoolean(if_missing=False)
557 users_group_active = StringBoolean(if_missing=False)
536
558
537 if edit:
559 if edit:
538 users_group_members = OneOf(available_members, hideList=False,
560 users_group_members = OneOf(available_members, hideList=False,
539 testValueList=True,
561 testValueList=True,
540 if_missing=None, not_empty=False)
562 if_missing=None, not_empty=False)
541
563
542 return _UsersGroupForm
564 return _UsersGroupForm
543
565
544 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
566 def ReposGroupForm(edit=False, old_data={}, available_groups=[]):
545 class _ReposGroupForm(formencode.Schema):
567 class _ReposGroupForm(formencode.Schema):
546 allow_extra_fields = True
568 allow_extra_fields = True
547 filter_extra_fields = True
569 filter_extra_fields = True
548
570
549 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
571 group_name = All(UnicodeString(strip=True, min=1, not_empty=True),
550 SlugifyName())
572 SlugifyName())
551 group_description = UnicodeString(strip=True, min=1,
573 group_description = UnicodeString(strip=True, min=1,
552 not_empty=True)
574 not_empty=True)
553 group_parent_id = OneOf(available_groups, hideList=False,
575 group_parent_id = OneOf(available_groups, hideList=False,
554 testValueList=True,
576 testValueList=True,
555 if_missing=None, not_empty=False)
577 if_missing=None, not_empty=False)
556
578
557 chained_validators = [ValidReposGroup(edit, old_data)]
579 chained_validators = [ValidReposGroup(edit, old_data)]
558
580
559 return _ReposGroupForm
581 return _ReposGroupForm
560
582
561 def RegisterForm(edit=False, old_data={}):
583 def RegisterForm(edit=False, old_data={}):
562 class _RegisterForm(formencode.Schema):
584 class _RegisterForm(formencode.Schema):
563 allow_extra_fields = True
585 allow_extra_fields = True
564 filter_extra_fields = True
586 filter_extra_fields = True
565 username = All(ValidUsername(edit, old_data),
587 username = All(ValidUsername(edit, old_data),
566 UnicodeString(strip=True, min=1, not_empty=True))
588 UnicodeString(strip=True, min=1, not_empty=True))
567 password = All(UnicodeString(strip=True, min=6, not_empty=True))
589 password = All(UnicodeString(strip=True, min=6, not_empty=True))
568 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
590 password_confirmation = All(UnicodeString(strip=True, min=6, not_empty=True))
569 active = StringBoolean(if_missing=False)
591 active = StringBoolean(if_missing=False)
570 name = UnicodeString(strip=True, min=1, not_empty=True)
592 name = UnicodeString(strip=True, min=1, not_empty=True)
571 lastname = UnicodeString(strip=True, min=1, not_empty=True)
593 lastname = UnicodeString(strip=True, min=1, not_empty=True)
572 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
594 email = All(Email(not_empty=True), UniqSystemEmail(old_data))
573
595
574 chained_validators = [ValidPasswordsMatch, ValidPassword]
596 chained_validators = [ValidPasswordsMatch, ValidPassword]
575
597
576 return _RegisterForm
598 return _RegisterForm
577
599
578 def PasswordResetForm():
600 def PasswordResetForm():
579 class _PasswordResetForm(formencode.Schema):
601 class _PasswordResetForm(formencode.Schema):
580 allow_extra_fields = True
602 allow_extra_fields = True
581 filter_extra_fields = True
603 filter_extra_fields = True
582 email = All(ValidSystemEmail(), Email(not_empty=True))
604 email = All(ValidSystemEmail(), Email(not_empty=True))
583 return _PasswordResetForm
605 return _PasswordResetForm
584
606
585 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
607 def RepoForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
586 repo_groups=[]):
608 repo_groups=[]):
587 class _RepoForm(formencode.Schema):
609 class _RepoForm(formencode.Schema):
588 allow_extra_fields = True
610 allow_extra_fields = True
589 filter_extra_fields = False
611 filter_extra_fields = False
590 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
612 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
591 SlugifyName())
613 SlugifyName())
592 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
614 clone_uri = All(UnicodeString(strip=True, min=1, not_empty=False),
593 ValidCloneUri()())
615 ValidCloneUri()())
594 repo_group = OneOf(repo_groups, hideList=True)
616 repo_group = OneOf(repo_groups, hideList=True)
595 repo_type = OneOf(supported_backends)
617 repo_type = OneOf(supported_backends)
596 description = UnicodeString(strip=True, min=1, not_empty=True)
618 description = UnicodeString(strip=True, min=1, not_empty=True)
597 private = StringBoolean(if_missing=False)
619 private = StringBoolean(if_missing=False)
598 enable_statistics = StringBoolean(if_missing=False)
620 enable_statistics = StringBoolean(if_missing=False)
599 enable_downloads = StringBoolean(if_missing=False)
621 enable_downloads = StringBoolean(if_missing=False)
600
622
601 if edit:
623 if edit:
602 #this is repo owner
624 #this is repo owner
603 user = All(UnicodeString(not_empty=True), ValidRepoUser)
625 user = All(UnicodeString(not_empty=True), ValidRepoUser)
604
626
605 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
627 chained_validators = [ValidRepoName(edit, old_data), ValidPerms]
606 return _RepoForm
628 return _RepoForm
607
629
608 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
630 def RepoForkForm(edit=False, old_data={}, supported_backends=BACKENDS.keys()):
609 class _RepoForkForm(formencode.Schema):
631 class _RepoForkForm(formencode.Schema):
610 allow_extra_fields = True
632 allow_extra_fields = True
611 filter_extra_fields = False
633 filter_extra_fields = False
612 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
634 fork_name = All(UnicodeString(strip=True, min=1, not_empty=True),
613 SlugifyName())
635 SlugifyName())
614 description = UnicodeString(strip=True, min=1, not_empty=True)
636 description = UnicodeString(strip=True, min=1, not_empty=True)
615 private = StringBoolean(if_missing=False)
637 private = StringBoolean(if_missing=False)
616 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
638 repo_type = All(ValidForkType(old_data), OneOf(supported_backends))
617
639
618 chained_validators = [ValidForkName()]
640 chained_validators = [ValidForkName()]
619
641
620 return _RepoForkForm
642 return _RepoForkForm
621
643
622 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
644 def RepoSettingsForm(edit=False, old_data={}, supported_backends=BACKENDS.keys(),
623 repo_groups=[]):
645 repo_groups=[]):
624 class _RepoForm(formencode.Schema):
646 class _RepoForm(formencode.Schema):
625 allow_extra_fields = True
647 allow_extra_fields = True
626 filter_extra_fields = False
648 filter_extra_fields = False
627 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
649 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True),
628 SlugifyName())
650 SlugifyName())
629 description = UnicodeString(strip=True, min=1, not_empty=True)
651 description = UnicodeString(strip=True, min=1, not_empty=True)
630 repo_group = OneOf(repo_groups, hideList=True)
652 repo_group = OneOf(repo_groups, hideList=True)
631 private = StringBoolean(if_missing=False)
653 private = StringBoolean(if_missing=False)
632
654
633 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
655 chained_validators = [ValidRepoName(edit, old_data), ValidPerms,
634 ValidSettings]
656 ValidSettings]
635 return _RepoForm
657 return _RepoForm
636
658
637
659
638 def ApplicationSettingsForm():
660 def ApplicationSettingsForm():
639 class _ApplicationSettingsForm(formencode.Schema):
661 class _ApplicationSettingsForm(formencode.Schema):
640 allow_extra_fields = True
662 allow_extra_fields = True
641 filter_extra_fields = False
663 filter_extra_fields = False
642 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
664 rhodecode_title = UnicodeString(strip=True, min=1, not_empty=True)
643 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
665 rhodecode_realm = UnicodeString(strip=True, min=1, not_empty=True)
644 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
666 rhodecode_ga_code = UnicodeString(strip=True, min=1, not_empty=False)
645
667
646 return _ApplicationSettingsForm
668 return _ApplicationSettingsForm
647
669
648 def ApplicationUiSettingsForm():
670 def ApplicationUiSettingsForm():
649 class _ApplicationUiSettingsForm(formencode.Schema):
671 class _ApplicationUiSettingsForm(formencode.Schema):
650 allow_extra_fields = True
672 allow_extra_fields = True
651 filter_extra_fields = False
673 filter_extra_fields = False
652 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
674 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
653 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
675 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=1, not_empty=True))
654 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
676 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
655 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
677 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
656 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
678 hooks_pretxnchangegroup_push_logger = OneOf(['True', 'False'], if_missing=False)
657 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
679 hooks_preoutgoing_pull_logger = OneOf(['True', 'False'], if_missing=False)
658
680
659 return _ApplicationUiSettingsForm
681 return _ApplicationUiSettingsForm
660
682
661 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
683 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
662 class _DefaultPermissionsForm(formencode.Schema):
684 class _DefaultPermissionsForm(formencode.Schema):
663 allow_extra_fields = True
685 allow_extra_fields = True
664 filter_extra_fields = True
686 filter_extra_fields = True
665 overwrite_default = StringBoolean(if_missing=False)
687 overwrite_default = StringBoolean(if_missing=False)
666 anonymous = OneOf(['True', 'False'], if_missing=False)
688 anonymous = OneOf(['True', 'False'], if_missing=False)
667 default_perm = OneOf(perms_choices)
689 default_perm = OneOf(perms_choices)
668 default_register = OneOf(register_choices)
690 default_register = OneOf(register_choices)
669 default_create = OneOf(create_choices)
691 default_create = OneOf(create_choices)
670
692
671 return _DefaultPermissionsForm
693 return _DefaultPermissionsForm
672
694
673
695
674 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
696 def LdapSettingsForm(tls_reqcert_choices, search_scope_choices, tls_kind_choices):
675 class _LdapSettingsForm(formencode.Schema):
697 class _LdapSettingsForm(formencode.Schema):
676 allow_extra_fields = True
698 allow_extra_fields = True
677 filter_extra_fields = True
699 filter_extra_fields = True
678 pre_validators = [LdapLibValidator]
700 pre_validators = [LdapLibValidator]
679 ldap_active = StringBoolean(if_missing=False)
701 ldap_active = StringBoolean(if_missing=False)
680 ldap_host = UnicodeString(strip=True,)
702 ldap_host = UnicodeString(strip=True,)
681 ldap_port = Number(strip=True,)
703 ldap_port = Number(strip=True,)
682 ldap_tls_kind = OneOf(tls_kind_choices)
704 ldap_tls_kind = OneOf(tls_kind_choices)
683 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
705 ldap_tls_reqcert = OneOf(tls_reqcert_choices)
684 ldap_dn_user = UnicodeString(strip=True,)
706 ldap_dn_user = UnicodeString(strip=True,)
685 ldap_dn_pass = UnicodeString(strip=True,)
707 ldap_dn_pass = UnicodeString(strip=True,)
686 ldap_base_dn = UnicodeString(strip=True,)
708 ldap_base_dn = UnicodeString(strip=True,)
687 ldap_filter = UnicodeString(strip=True,)
709 ldap_filter = UnicodeString(strip=True,)
688 ldap_search_scope = OneOf(search_scope_choices)
710 ldap_search_scope = OneOf(search_scope_choices)
689 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
711 ldap_attr_login = All(AttrLoginValidator, UnicodeString(strip=True,))
690 ldap_attr_firstname = UnicodeString(strip=True,)
712 ldap_attr_firstname = UnicodeString(strip=True,)
691 ldap_attr_lastname = UnicodeString(strip=True,)
713 ldap_attr_lastname = UnicodeString(strip=True,)
692 ldap_attr_email = UnicodeString(strip=True,)
714 ldap_attr_email = UnicodeString(strip=True,)
693
715
694 return _LdapSettingsForm
716 return _LdapSettingsForm
General Comments 0
You need to be logged in to leave comments. Login now