##// END OF EJS Templates
Added validation for uniq email address
marcink -
r475:9dd38344 celery
parent child Browse files
Show More
@@ -1,334 +1,347 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 from formencode import All
23 23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
24 24 Email, Bool, StringBoolean
25 25 from pylons import session
26 26 from pylons.i18n.translation import _
27 27 from pylons_app.lib.auth import check_password, get_crypt_password
28 28 from pylons_app.model import meta
29 29 from pylons_app.model.user_model import UserModel
30 30 from pylons_app.model.db import User, Repository
31 31 from sqlalchemy.exc import OperationalError
32 32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 33 from webhelpers.pylonslib.secure_form import authentication_token
34 34 import formencode
35 35 import logging
36 36 import os
37 37 import pylons_app.lib.helpers as h
38 38 log = logging.getLogger(__name__)
39 39
40 40
41 41 #this is needed to translate the messages using _() in validators
42 42 class State_obj(object):
43 43 _ = staticmethod(_)
44 44
45 45 #===============================================================================
46 46 # VALIDATORS
47 47 #===============================================================================
48 48 class ValidAuthToken(formencode.validators.FancyValidator):
49 49 messages = {'invalid_token':_('Token mismatch')}
50 50
51 51 def validate_python(self, value, state):
52 52
53 53 if value != authentication_token():
54 54 raise formencode.Invalid(self.message('invalid_token', state,
55 55 search_number=value), value, state)
56 56
57 57 def ValidUsername(edit, old_data):
58 58 class _ValidUsername(formencode.validators.FancyValidator):
59 59
60 60 def validate_python(self, value, state):
61 61 if value in ['default', 'new_user']:
62 62 raise formencode.Invalid(_('Invalid username'), value, state)
63 63 #check if user is uniq
64 64 sa = meta.Session
65 65 old_un = None
66 66 if edit:
67 67 old_un = sa.query(User).get(old_data.get('user_id')).username
68 68
69 69 if old_un != value or not edit:
70 70 if sa.query(User).filter(User.username == value).scalar():
71 71 raise formencode.Invalid(_('This username already exists') ,
72 72 value, state)
73 73 meta.Session.remove()
74 74
75 75 return _ValidUsername
76 76
77 77 class ValidPassword(formencode.validators.FancyValidator):
78 78
79 79 def to_python(self, value, state):
80 80 if value:
81 81 return get_crypt_password(value)
82 82
83 83 class ValidAuth(formencode.validators.FancyValidator):
84 84 messages = {
85 85 'invalid_password':_('invalid password'),
86 86 'invalid_login':_('invalid user name'),
87 87 'disabled_account':_('Your acccount is disabled')
88 88
89 89 }
90 90 #error mapping
91 91 e_dict = {'username':messages['invalid_login'],
92 92 'password':messages['invalid_password']}
93 93 e_dict_disable = {'username':messages['disabled_account']}
94 94
95 95 def validate_python(self, value, state):
96 96 password = value['password']
97 97 username = value['username']
98 98 user = UserModel().get_user_by_name(username)
99 99 if user is None:
100 100 raise formencode.Invalid(self.message('invalid_password',
101 101 state=State_obj), value, state,
102 102 error_dict=self.e_dict)
103 103 if user:
104 104 if user.active:
105 105 if user.username == username and check_password(password,
106 106 user.password):
107 107 return value
108 108 else:
109 109 log.warning('user %s not authenticated', username)
110 110 raise formencode.Invalid(self.message('invalid_password',
111 111 state=State_obj), value, state,
112 112 error_dict=self.e_dict)
113 113 else:
114 114 log.warning('user %s is disabled', username)
115 115 raise formencode.Invalid(self.message('disabled_account',
116 116 state=State_obj),
117 117 value, state,
118 118 error_dict=self.e_dict_disable)
119 119
120 120 class ValidRepoUser(formencode.validators.FancyValidator):
121 121
122 122 def to_python(self, value, state):
123 123 try:
124 124 self.user_db = meta.Session.query(User)\
125 125 .filter(User.active == True)\
126 126 .filter(User.username == value).one()
127 127 except Exception:
128 128 raise formencode.Invalid(_('This username is not valid'),
129 129 value, state)
130 130 finally:
131 131 meta.Session.remove()
132 132
133 133 return self.user_db.user_id
134 134
135 135 def ValidRepoName(edit, old_data):
136 136 class _ValidRepoName(formencode.validators.FancyValidator):
137 137
138 138 def to_python(self, value, state):
139 139 slug = h.repo_name_slug(value)
140 140 if slug in ['_admin']:
141 141 raise formencode.Invalid(_('This repository name is disallowed'),
142 142 value, state)
143 143 if old_data.get('repo_name') != value or not edit:
144 144 sa = meta.Session
145 145 if sa.query(Repository).filter(Repository.repo_name == slug).scalar():
146 146 raise formencode.Invalid(_('This repository already exists') ,
147 147 value, state)
148 148 meta.Session.remove()
149 149 return slug
150 150
151 151
152 152 return _ValidRepoName
153 153
154 154 class ValidPerms(formencode.validators.FancyValidator):
155 155 messages = {'perm_new_user_name':_('This username is not valid')}
156 156
157 157 def to_python(self, value, state):
158 158 perms_update = []
159 159 perms_new = []
160 160 #build a list of permission to update and new permission to create
161 161 for k, v in value.items():
162 162 if k.startswith('perm_'):
163 163 if k.startswith('perm_new_user'):
164 164 new_perm = value.get('perm_new_user', False)
165 165 new_user = value.get('perm_new_user_name', False)
166 166 if new_user and new_perm:
167 167 if (new_user, new_perm) not in perms_new:
168 168 perms_new.append((new_user, new_perm))
169 169 else:
170 170 usr = k[5:]
171 171 if usr == 'default':
172 172 if value['private']:
173 173 #set none for default when updating to private repo
174 174 v = 'repository.none'
175 175 perms_update.append((usr, v))
176 176 value['perms_updates'] = perms_update
177 177 value['perms_new'] = perms_new
178 178 sa = meta.Session
179 179 for k, v in perms_new:
180 180 try:
181 181 self.user_db = sa.query(User)\
182 182 .filter(User.active == True)\
183 183 .filter(User.username == k).one()
184 184 except Exception:
185 185 msg = self.message('perm_new_user_name',
186 186 state=State_obj)
187 187 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
188 188 return value
189 189
190 190 class ValidSettings(formencode.validators.FancyValidator):
191 191
192 192 def to_python(self, value, state):
193 193 #settings form can't edit user
194 194 if value.has_key('user'):
195 195 del['value']['user']
196 196
197 197 return value
198 198
199 199 class ValidPath(formencode.validators.FancyValidator):
200 200 def to_python(self, value, state):
201 201 isdir = os.path.isdir(value.replace('*', ''))
202 202 if (value.endswith('/*') or value.endswith('/**')) and isdir:
203 203 return value
204 204 elif not isdir:
205 205 msg = _('This is not a valid path')
206 206 else:
207 207 msg = _('You need to specify * or ** at the end of path (ie. /tmp/*)')
208 208
209 209 raise formencode.Invalid(msg, value, state,
210 210 error_dict={'paths_root_path':msg})
211 211
212 class UniqSystemEmail(formencode.validators.FancyValidator):
213 def to_python(self, value, state):
214 sa = meta.Session
215 try:
216 user = sa.query(User).filter(User.email == value).scalar()
217 if user:
218 raise formencode.Invalid(_("That e-mail address is already taken") ,
219 value, state)
220 finally:
221 meta.Session.remove()
222
223 return value
224
212 225 class ValidSystemEmail(formencode.validators.FancyValidator):
213 226 def to_python(self, value, state):
214 227 sa = meta.Session
215 228 try:
216 229 user = sa.query(User).filter(User.email == value).scalar()
217 230 if user is None:
218 231 raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
219 232 value, state)
220 233 finally:
221 234 meta.Session.remove()
222 235
223 236 return value
224 237
225 238 #===============================================================================
226 239 # FORMS
227 240 #===============================================================================
228 241 class LoginForm(formencode.Schema):
229 242 allow_extra_fields = True
230 243 filter_extra_fields = True
231 244 username = UnicodeString(
232 245 strip=True,
233 246 min=3,
234 247 not_empty=True,
235 248 messages={
236 249 'empty':_('Please enter a login'),
237 250 'tooShort':_('Enter a value %(min)i characters long or more')}
238 251 )
239 252
240 253 password = UnicodeString(
241 254 strip=True,
242 255 min=3,
243 256 not_empty=True,
244 257 messages={
245 258 'empty':_('Please enter a password'),
246 259 'tooShort':_('Enter a value %(min)i characters long or more')}
247 260 )
248 261
249 262
250 263 #chained validators have access to all data
251 264 chained_validators = [ValidAuth]
252 265
253 266 def UserForm(edit=False, old_data={}):
254 267 class _UserForm(formencode.Schema):
255 268 allow_extra_fields = True
256 269 filter_extra_fields = True
257 270 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername(edit, old_data))
258 271 if edit:
259 272 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
260 273 admin = StringBoolean(if_missing=False)
261 274 else:
262 275 password = All(UnicodeString(strip=True, min=8, not_empty=True), ValidPassword)
263 276 active = StringBoolean(if_missing=False)
264 277 name = UnicodeString(strip=True, min=3, not_empty=True)
265 278 lastname = UnicodeString(strip=True, min=3, not_empty=True)
266 email = Email(not_empty=True)
279 email = All(Email(not_empty=True), UniqSystemEmail())
267 280
268 281 return _UserForm
269 282
270 283 RegisterForm = UserForm
271 284
272 285 def PasswordResetForm():
273 286 class _PasswordResetForm(formencode.Schema):
274 287 allow_extra_fields = True
275 288 filter_extra_fields = True
276 289 email = All(ValidSystemEmail(), Email(not_empty=True))
277 290 return _PasswordResetForm
278 291
279 292 def RepoForm(edit=False, old_data={}):
280 293 class _RepoForm(formencode.Schema):
281 294 allow_extra_fields = True
282 295 filter_extra_fields = False
283 296 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
284 297 description = UnicodeString(strip=True, min=3, not_empty=True)
285 298 private = StringBoolean(if_missing=False)
286 299
287 300 if edit:
288 301 user = All(Int(not_empty=True), ValidRepoUser)
289 302
290 303 chained_validators = [ValidPerms]
291 304 return _RepoForm
292 305
293 306 def RepoSettingsForm(edit=False, old_data={}):
294 307 class _RepoForm(formencode.Schema):
295 308 allow_extra_fields = True
296 309 filter_extra_fields = False
297 310 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit, old_data))
298 311 description = UnicodeString(strip=True, min=3, not_empty=True)
299 312 private = StringBoolean(if_missing=False)
300 313
301 314 chained_validators = [ValidPerms, ValidSettings]
302 315 return _RepoForm
303 316
304 317
305 318 def ApplicationSettingsForm():
306 319 class _ApplicationSettingsForm(formencode.Schema):
307 320 allow_extra_fields = True
308 321 filter_extra_fields = False
309 322 hg_app_title = UnicodeString(strip=True, min=3, not_empty=True)
310 323 hg_app_realm = UnicodeString(strip=True, min=3, not_empty=True)
311 324
312 325 return _ApplicationSettingsForm
313 326
314 327 def ApplicationUiSettingsForm():
315 328 class _ApplicationUiSettingsForm(formencode.Schema):
316 329 allow_extra_fields = True
317 330 filter_extra_fields = False
318 331 web_push_ssl = OneOf(['true', 'false'], if_missing='false')
319 332 paths_root_path = All(ValidPath(), UnicodeString(strip=True, min=3, not_empty=True))
320 333 hooks_changegroup_update = OneOf(['True', 'False'], if_missing=False)
321 334 hooks_changegroup_repo_size = OneOf(['True', 'False'], if_missing=False)
322 335
323 336 return _ApplicationUiSettingsForm
324 337
325 338 def DefaultPermissionsForm(perms_choices, register_choices, create_choices):
326 339 class _DefaultPermissionsForm(formencode.Schema):
327 340 allow_extra_fields = True
328 341 filter_extra_fields = True
329 342 overwrite_default = OneOf(['true', 'false'], if_missing='false')
330 343 default_perm = OneOf(perms_choices)
331 344 default_register = OneOf(register_choices)
332 345 default_create = OneOf(create_choices)
333 346
334 347 return _DefaultPermissionsForm
General Comments 0
You need to be logged in to leave comments. Login now