##// END OF EJS Templates
fixed bug for user update, when password was always set.
marcink -
r347:40bccabf default
parent child Browse files
Show More
@@ -1,270 +1,271
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 from formencode import All
22 from formencode import All
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
24 Email, Bool, StringBoolean
24 Email, Bool, StringBoolean
25 from pylons import session
25 from pylons import session
26 from pylons.i18n.translation import _
26 from pylons.i18n.translation import _
27 from pylons_app.lib.auth import get_crypt_password
27 from pylons_app.lib.auth import get_crypt_password
28 import pylons_app.lib.helpers as h
28 import pylons_app.lib.helpers as h
29 from pylons_app.model import meta
29 from pylons_app.model import meta
30 from pylons_app.model.db import User, Repository
30 from pylons_app.model.db import User, Repository
31 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.exc import OperationalError
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
33 from webhelpers.pylonslib.secure_form import authentication_token
33 from webhelpers.pylonslib.secure_form import authentication_token
34 import datetime
34 import datetime
35 import formencode
35 import formencode
36 import logging
36 import logging
37 log = logging.getLogger(__name__)
37 log = logging.getLogger(__name__)
38
38
39
39
40 #this is needed to translate the messages using _() in validators
40 #this is needed to translate the messages using _() in validators
41 class State_obj(object):
41 class State_obj(object):
42 _ = staticmethod(_)
42 _ = staticmethod(_)
43
43
44 #===============================================================================
44 #===============================================================================
45 # VALIDATORS
45 # VALIDATORS
46 #===============================================================================
46 #===============================================================================
47 class ValidAuthToken(formencode.validators.FancyValidator):
47 class ValidAuthToken(formencode.validators.FancyValidator):
48 messages = {'invalid_token':_('Token mismatch')}
48 messages = {'invalid_token':_('Token mismatch')}
49
49
50 def validate_python(self, value, state):
50 def validate_python(self, value, state):
51
51
52 if value != authentication_token():
52 if value != authentication_token():
53 raise formencode.Invalid(self.message('invalid_token', state,
53 raise formencode.Invalid(self.message('invalid_token', state,
54 search_number=value), value, state)
54 search_number=value), value, state)
55 class ValidUsername(formencode.validators.FancyValidator):
55 class ValidUsername(formencode.validators.FancyValidator):
56
56
57 def validate_python(self, value, state):
57 def validate_python(self, value, state):
58 if value in ['default', 'new_user']:
58 if value in ['default', 'new_user']:
59 raise formencode.Invalid(_('Invalid username'), value, state)
59 raise formencode.Invalid(_('Invalid username'), value, state)
60
60
61 class ValidPassword(formencode.validators.FancyValidator):
61 class ValidPassword(formencode.validators.FancyValidator):
62
62
63 def to_python(self, value, state):
63 def to_python(self, value, state):
64 return get_crypt_password(value)
64 if value:
65 return get_crypt_password(value)
65
66
66 class ValidAuth(formencode.validators.FancyValidator):
67 class ValidAuth(formencode.validators.FancyValidator):
67 messages = {
68 messages = {
68 'invalid_password':_('invalid password'),
69 'invalid_password':_('invalid password'),
69 'invalid_login':_('invalid user name'),
70 'invalid_login':_('invalid user name'),
70 'disabled_account':_('Your acccount is disabled')
71 'disabled_account':_('Your acccount is disabled')
71
72
72 }
73 }
73 #error mapping
74 #error mapping
74 e_dict = {'username':messages['invalid_login'],
75 e_dict = {'username':messages['invalid_login'],
75 'password':messages['invalid_password']}
76 'password':messages['invalid_password']}
76 e_dict_disable = {'username':messages['disabled_account']}
77 e_dict_disable = {'username':messages['disabled_account']}
77
78
78 def validate_python(self, value, state):
79 def validate_python(self, value, state):
79 sa = meta.Session
80 sa = meta.Session
80 crypted_passwd = get_crypt_password(value['password'])
81 crypted_passwd = get_crypt_password(value['password'])
81 username = value['username']
82 username = value['username']
82 try:
83 try:
83 user = sa.query(User).filter(User.username == username).one()
84 user = sa.query(User).filter(User.username == username).one()
84 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
85 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
85 log.error(e)
86 log.error(e)
86 user = None
87 user = None
87 raise formencode.Invalid(self.message('invalid_password',
88 raise formencode.Invalid(self.message('invalid_password',
88 state=State_obj), value, state,
89 state=State_obj), value, state,
89 error_dict=self.e_dict)
90 error_dict=self.e_dict)
90 if user:
91 if user:
91 if user.active:
92 if user.active:
92 if user.username == username and user.password == crypted_passwd:
93 if user.username == username and user.password == crypted_passwd:
93 from pylons_app.lib.auth import AuthUser
94 from pylons_app.lib.auth import AuthUser
94 auth_user = AuthUser()
95 auth_user = AuthUser()
95 auth_user.username = username
96 auth_user.username = username
96 auth_user.is_authenticated = True
97 auth_user.is_authenticated = True
97 auth_user.is_admin = user.admin
98 auth_user.is_admin = user.admin
98 auth_user.user_id = user.user_id
99 auth_user.user_id = user.user_id
99 session['hg_app_user'] = auth_user
100 session['hg_app_user'] = auth_user
100 session.save()
101 session.save()
101 log.info('user %s is now authenticated', username)
102 log.info('user %s is now authenticated', username)
102
103
103 try:
104 try:
104 user.last_login = datetime.datetime.now()
105 user.last_login = datetime.datetime.now()
105 sa.add(user)
106 sa.add(user)
106 sa.commit()
107 sa.commit()
107 except (OperationalError) as e:
108 except (OperationalError) as e:
108 log.error(e)
109 log.error(e)
109 sa.rollback()
110 sa.rollback()
110
111
111 return value
112 return value
112 else:
113 else:
113 log.warning('user %s not authenticated', username)
114 log.warning('user %s not authenticated', username)
114 raise formencode.Invalid(self.message('invalid_password',
115 raise formencode.Invalid(self.message('invalid_password',
115 state=State_obj), value, state,
116 state=State_obj), value, state,
116 error_dict=self.e_dict)
117 error_dict=self.e_dict)
117 else:
118 else:
118 log.warning('user %s is disabled', username)
119 log.warning('user %s is disabled', username)
119 raise formencode.Invalid(self.message('disabled_account',
120 raise formencode.Invalid(self.message('disabled_account',
120 state=State_obj),
121 state=State_obj),
121 value, state,
122 value, state,
122 error_dict=self.e_dict_disable)
123 error_dict=self.e_dict_disable)
123
124
124
125
125 class ValidRepoUser(formencode.validators.FancyValidator):
126 class ValidRepoUser(formencode.validators.FancyValidator):
126
127
127 def to_python(self, value, state):
128 def to_python(self, value, state):
128 sa = meta.Session
129 sa = meta.Session
129 try:
130 try:
130 self.user_db = sa.query(User)\
131 self.user_db = sa.query(User)\
131 .filter(User.active == True)\
132 .filter(User.active == True)\
132 .filter(User.username == value).one()
133 .filter(User.username == value).one()
133 except Exception:
134 except Exception:
134 raise formencode.Invalid(_('This username is not valid'),
135 raise formencode.Invalid(_('This username is not valid'),
135 value, state)
136 value, state)
136 return self.user_db.user_id
137 return self.user_db.user_id
137
138
138 def ValidRepoName(edit=False):
139 def ValidRepoName(edit=False):
139 class _ValidRepoName(formencode.validators.FancyValidator):
140 class _ValidRepoName(formencode.validators.FancyValidator):
140
141
141 def to_python(self, value, state):
142 def to_python(self, value, state):
142 slug = h.repo_name_slug(value)
143 slug = h.repo_name_slug(value)
143 if slug in ['_admin']:
144 if slug in ['_admin']:
144 raise formencode.Invalid(_('This repository name is disallowed'),
145 raise formencode.Invalid(_('This repository name is disallowed'),
145 value, state)
146 value, state)
146 sa = meta.Session
147 sa = meta.Session
147 if sa.query(Repository).get(slug) and not edit:
148 if sa.query(Repository).get(slug) and not edit:
148 raise formencode.Invalid(_('This repository already exists'),
149 raise formencode.Invalid(_('This repository already exists'),
149 value, state)
150 value, state)
150
151
151 return slug
152 return slug
152 return _ValidRepoName
153 return _ValidRepoName
153
154
154 class ValidPerms(formencode.validators.FancyValidator):
155 class ValidPerms(formencode.validators.FancyValidator):
155 messages = {'perm_new_user_name':_('This username is not valid')}
156 messages = {'perm_new_user_name':_('This username is not valid')}
156
157
157 def to_python(self, value, state):
158 def to_python(self, value, state):
158 perms_update = []
159 perms_update = []
159 perms_new = []
160 perms_new = []
160 #build a list of permission to update and new permission to create
161 #build a list of permission to update and new permission to create
161 for k, v in value.items():
162 for k, v in value.items():
162 if k.startswith('perm_'):
163 if k.startswith('perm_'):
163 if k.startswith('perm_new_user'):
164 if k.startswith('perm_new_user'):
164 new_perm = value.get('perm_new_user', False)
165 new_perm = value.get('perm_new_user', False)
165 new_user = value.get('perm_new_user_name', False)
166 new_user = value.get('perm_new_user_name', False)
166 if new_user and new_perm:
167 if new_user and new_perm:
167 if (new_user, new_perm) not in perms_new:
168 if (new_user, new_perm) not in perms_new:
168 perms_new.append((new_user, new_perm))
169 perms_new.append((new_user, new_perm))
169 else:
170 else:
170 usr = k[5:]
171 usr = k[5:]
171 if usr == 'default':
172 if usr == 'default':
172 if value['private']:
173 if value['private']:
173 #set none for default when updating to private repo
174 #set none for default when updating to private repo
174 v = 'repository.none'
175 v = 'repository.none'
175 perms_update.append((usr, v))
176 perms_update.append((usr, v))
176 value['perms_updates'] = perms_update
177 value['perms_updates'] = perms_update
177 value['perms_new'] = perms_new
178 value['perms_new'] = perms_new
178 sa = meta.Session
179 sa = meta.Session
179 for k, v in perms_new:
180 for k, v in perms_new:
180 try:
181 try:
181 self.user_db = sa.query(User)\
182 self.user_db = sa.query(User)\
182 .filter(User.active == True)\
183 .filter(User.active == True)\
183 .filter(User.username == k).one()
184 .filter(User.username == k).one()
184 except Exception:
185 except Exception:
185 msg = self.message('perm_new_user_name',
186 msg = self.message('perm_new_user_name',
186 state=State_obj)
187 state=State_obj)
187 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
188 raise formencode.Invalid(msg, value, state, error_dict={'perm_new_user_name':msg})
188 return value
189 return value
189
190
190 class ValidSettings(formencode.validators.FancyValidator):
191 class ValidSettings(formencode.validators.FancyValidator):
191
192
192 def to_python(self, value, state):
193 def to_python(self, value, state):
193 #settings form can't edit user
194 #settings form can't edit user
194 if value.has_key('user'):
195 if value.has_key('user'):
195 del['value']['user']
196 del['value']['user']
196
197
197 return value
198 return value
198 #===============================================================================
199 #===============================================================================
199 # FORMS
200 # FORMS
200 #===============================================================================
201 #===============================================================================
201 class LoginForm(formencode.Schema):
202 class LoginForm(formencode.Schema):
202 allow_extra_fields = True
203 allow_extra_fields = True
203 filter_extra_fields = True
204 filter_extra_fields = True
204 username = UnicodeString(
205 username = UnicodeString(
205 strip=True,
206 strip=True,
206 min=3,
207 min=3,
207 not_empty=True,
208 not_empty=True,
208 messages={
209 messages={
209 'empty':_('Please enter a login'),
210 'empty':_('Please enter a login'),
210 'tooShort':_('Enter a value %(min)i characters long or more')}
211 'tooShort':_('Enter a value %(min)i characters long or more')}
211 )
212 )
212
213
213 password = UnicodeString(
214 password = UnicodeString(
214 strip=True,
215 strip=True,
215 min=3,
216 min=3,
216 not_empty=True,
217 not_empty=True,
217 messages={
218 messages={
218 'empty':_('Please enter a password'),
219 'empty':_('Please enter a password'),
219 'tooShort':_('Enter a value %(min)i characters long or more')}
220 'tooShort':_('Enter a value %(min)i characters long or more')}
220 )
221 )
221
222
222
223
223 #chained validators have access to all data
224 #chained validators have access to all data
224 chained_validators = [ValidAuth]
225 chained_validators = [ValidAuth]
225
226
226 def UserForm(edit=False):
227 def UserForm(edit=False):
227 class _UserForm(formencode.Schema):
228 class _UserForm(formencode.Schema):
228 allow_extra_fields = True
229 allow_extra_fields = True
229 filter_extra_fields = True
230 filter_extra_fields = True
230 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
231 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
231 if edit:
232 if edit:
232 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
233 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
233 admin = StringBoolean(if_missing=False)
234 admin = StringBoolean(if_missing=False)
234 else:
235 else:
235 password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
236 password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
236 active = StringBoolean(if_missing=False)
237 active = StringBoolean(if_missing=False)
237 name = UnicodeString(strip=True, min=3, not_empty=True)
238 name = UnicodeString(strip=True, min=3, not_empty=True)
238 lastname = UnicodeString(strip=True, min=3, not_empty=True)
239 lastname = UnicodeString(strip=True, min=3, not_empty=True)
239 email = Email(not_empty=True)
240 email = Email(not_empty=True)
240
241
241 return _UserForm
242 return _UserForm
242
243
243 def RepoForm(edit=False):
244 def RepoForm(edit=False):
244 class _RepoForm(formencode.Schema):
245 class _RepoForm(formencode.Schema):
245 allow_extra_fields = True
246 allow_extra_fields = True
246 filter_extra_fields = False
247 filter_extra_fields = False
247 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
248 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
248 description = UnicodeString(strip=True, min=3, not_empty=True)
249 description = UnicodeString(strip=True, min=3, not_empty=True)
249 private = StringBoolean(if_missing=False)
250 private = StringBoolean(if_missing=False)
250
251
251 if edit:
252 if edit:
252 user = All(Int(not_empty=True), ValidRepoUser)
253 user = All(Int(not_empty=True), ValidRepoUser)
253
254
254 chained_validators = [ValidPerms]
255 chained_validators = [ValidPerms]
255 return _RepoForm
256 return _RepoForm
256
257
257 def RepoSettingsForm(edit=False):
258 def RepoSettingsForm(edit=False):
258 class _RepoForm(formencode.Schema):
259 class _RepoForm(formencode.Schema):
259 allow_extra_fields = True
260 allow_extra_fields = True
260 filter_extra_fields = False
261 filter_extra_fields = False
261 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
262 repo_name = All(UnicodeString(strip=True, min=1, not_empty=True), ValidRepoName(edit))
262 description = UnicodeString(strip=True, min=3, not_empty=True)
263 description = UnicodeString(strip=True, min=3, not_empty=True)
263 private = StringBoolean(if_missing=False)
264 private = StringBoolean(if_missing=False)
264
265
265 chained_validators = [ValidPerms, ValidSettings]
266 chained_validators = [ValidPerms, ValidSettings]
266 return _RepoForm
267 return _RepoForm
267
268
268
269
269
270
270
271
@@ -1,91 +1,90
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for users
3 # Model for users
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
9 # of the License or (at your opinion) any later version of the license.
9 # of the License or (at your opinion) any later version of the license.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
19 # MA 02110-1301, USA.
20
20
21 """
21 """
22 Created on April 9, 2010
22 Created on April 9, 2010
23 Model for users
23 Model for users
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26
27 from pylons_app.model.db import User
27 from pylons_app.model.db import User
28 from pylons_app.model.meta import Session
28 from pylons_app.model.meta import Session
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30 import logging
30 import logging
31 log = logging.getLogger(__name__)
31 log = logging.getLogger(__name__)
32
32
33 class DefaultUserException(Exception):pass
33 class DefaultUserException(Exception):pass
34
34
35 class UserModel(object):
35 class UserModel(object):
36
36
37 def __init__(self):
37 def __init__(self):
38 self.sa = Session()
38 self.sa = Session()
39
39
40 def get_user(self, id):
40 def get_user(self, id):
41 return self.sa.query(User).get(id)
41 return self.sa.query(User).get(id)
42
42
43 def create(self, form_data):
43 def create(self, form_data):
44 try:
44 try:
45 new_user = User()
45 new_user = User()
46 for k, v in form_data.items():
46 for k, v in form_data.items():
47 setattr(new_user, k, v)
47 setattr(new_user, k, v)
48
48
49 self.sa.add(new_user)
49 self.sa.add(new_user)
50 self.sa.commit()
50 self.sa.commit()
51 except Exception as e:
51 except Exception as e:
52 log.error(e)
52 log.error(e)
53 self.sa.rollback()
53 self.sa.rollback()
54 raise
54 raise
55
55
56 def update(self, id, form_data):
56 def update(self, id, form_data):
57 try:
57 try:
58 new_user = self.sa.query(User).get(id)
58 new_user = self.sa.query(User).get(id)
59 if new_user.username == 'default':
59 if new_user.username == 'default':
60 raise DefaultUserException(
60 raise DefaultUserException(
61 _("You can't Edit this user since it's"
61 _("You can't Edit this user since it's"
62 " crucial for entire application"))
62 " crucial for entire application"))
63 for k, v in form_data.items():
63 for k, v in form_data.items():
64 if k == 'new_password' and v != '':
64 if k == 'new_password' and v != '':
65
66 new_user.password = v
65 new_user.password = v
67 else:
66 else:
68 setattr(new_user, k, v)
67 setattr(new_user, k, v)
69
68
70 self.sa.add(new_user)
69 self.sa.add(new_user)
71 self.sa.commit()
70 self.sa.commit()
72 except Exception as e:
71 except Exception as e:
73 log.error(e)
72 log.error(e)
74 self.sa.rollback()
73 self.sa.rollback()
75 raise
74 raise
76
75
77 def delete(self, id):
76 def delete(self, id):
78
77
79 try:
78 try:
80
79
81 user = self.sa.query(User).get(id)
80 user = self.sa.query(User).get(id)
82 if user.username == 'default':
81 if user.username == 'default':
83 raise DefaultUserException(
82 raise DefaultUserException(
84 _("You can't remove this user since it's"
83 _("You can't remove this user since it's"
85 " crucial for entire application"))
84 " crucial for entire application"))
86 self.sa.delete(user)
85 self.sa.delete(user)
87 self.sa.commit()
86 self.sa.commit()
88 except Exception as e:
87 except Exception as e:
89 log.error(e)
88 log.error(e)
90 self.sa.rollback()
89 self.sa.rollback()
91 raise
90 raise
General Comments 0
You need to be logged in to leave comments. Login now