##// END OF EJS Templates
Added lastlogin to user after login, model db update
marcink -
r242:5da4ef11 default
parent child Browse files
Show More
@@ -1,46 +1,52
1 from pylons_app.model.meta import Base
1 from pylons_app.model.meta import Base
2 from sqlalchemy.orm import relation, backref
2 from sqlalchemy.orm import relation, backref
3 from sqlalchemy import *
3 from sqlalchemy import *
4
4
5 class User(Base):
5 class User(Base):
6 __tablename__ = 'users'
6 __tablename__ = 'users'
7 __table_args__ = {'useexisting':True}
7 __table_args__ = {'useexisting':True}
8 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
8 user_id = Column("user_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
9 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
9 username = Column("username", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
10 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
10 password = Column("password", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
11 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
11 active = Column("active", BOOLEAN(), nullable=True, unique=None, default=None)
12 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=None)
12 admin = Column("admin", BOOLEAN(), nullable=True, unique=None, default=None)
13 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
13 name = Column("name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
14 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
14 lastname = Column("lastname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
15 email = Column("email", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
16 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
16 last_login = Column("last_login", DATETIME(timezone=False), nullable=True, unique=None, default=None)
17
17
18 user_log = relation('UserLog')
18 user_log = relation('UserLog')
19
19
20 def __repr__(self):
20 def __repr__(self):
21 return "<User('%s:%s')>" % (self.user_id, self.username)
21 return "<User('%s:%s')>" % (self.user_id, self.username)
22
22
23 class UserLog(Base):
23 class UserLog(Base):
24 __tablename__ = 'user_logs'
24 __tablename__ = 'user_logs'
25 __table_args__ = {'useexisting':True}
25 __table_args__ = {'useexisting':True}
26 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
26 user_log_id = Column("user_log_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
27 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
27 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
28 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
28 repository = Column("repository", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
29 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
29 action = Column("action", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
30 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
30 action_date = Column("action_date", DATETIME(timezone=False), nullable=True, unique=None, default=None)
31
31
32 user = relation('User')
32 user = relation('User')
33
33
34 class Repository(Base):
34 class Repository(Base):
35 __tablename__ = 'repositories'
35 __tablename__ = 'repositories'
36 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
36 repo_id = Column("repo_id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
37 repo_name = Column("repo_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
38 user_id = Column("user_id", INTEGER(), ForeignKey(u'users.user_id'), nullable=True, unique=None, default=None)
39 private = Column("private", BOOLEAN(), nullable=True, unique=None, default=None)
40
41 user = relation('User')
42
37
43
38 class Permission(Base):
44 class Permission(Base):
39 __tablename__ = 'permissions'
45 __tablename__ = 'permissions'
40 __table_args__ = {'useexisting':True}
46 __table_args__ = {'useexisting':True}
41 permission_id = Column("id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
47 permission_id = Column("id", INTEGER(), nullable=False, unique=True, default=None, primary_key=1)
42 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
48 permission_name = Column("permission_name", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
43 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
49 permission_longname = Column("permission_longname", TEXT(length=None, convert_unicode=False, assert_unicode=None), nullable=True, unique=None, default=None)
44
50
45 def __repr__(self):
51 def __repr__(self):
46 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
52 return "<Permission('%s:%s')>" % (self.permission_id, self.permission_name)
@@ -1,155 +1,165
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.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 from formencode.validators import UnicodeString, OneOf, Int, Number, Regex, \
23 Email, Bool, StringBoolean
24 Email, Bool, StringBoolean
24 from formencode import All
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 from pylons_app.model import meta
28 from pylons_app.model import meta
29 from pylons_app.model.db import User
29 from pylons_app.model.db import User
30 from sqlalchemy.exc import OperationalError
30 from sqlalchemy.exc import OperationalError
31 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
31 from sqlalchemy.orm.exc import NoResultFound, MultipleResultsFound
32 from webhelpers.pylonslib.secure_form import authentication_token
32 from webhelpers.pylonslib.secure_form import authentication_token
33 import datetime
33 import formencode
34 import formencode
34 import logging
35 import logging
35 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
36
37
37
38
38 #this is needed to translate the messages using _() in validators
39 #this is needed to translate the messages using _() in validators
39 class State_obj(object):
40 class State_obj(object):
40 _ = staticmethod(_)
41 _ = staticmethod(_)
41
42
42 #===============================================================================
43 #===============================================================================
43 # VALIDATORS
44 # VALIDATORS
44 #===============================================================================
45 #===============================================================================
45 class ValidAuthToken(formencode.validators.FancyValidator):
46 class ValidAuthToken(formencode.validators.FancyValidator):
46 messages = {'invalid_token':_('Token mismatch')}
47 messages = {'invalid_token':_('Token mismatch')}
47
48
48 def validate_python(self, value, state):
49 def validate_python(self, value, state):
49
50
50 if value != authentication_token():
51 if value != authentication_token():
51 raise formencode.Invalid(self.message('invalid_token', state,
52 raise formencode.Invalid(self.message('invalid_token', state,
52 search_number=value), value, state)
53 search_number=value), value, state)
53 class ValidUsername(formencode.validators.FancyValidator):
54 class ValidUsername(formencode.validators.FancyValidator):
54
55
55 def validate_python(self, value, state):
56 def validate_python(self, value, state):
56 pass
57 pass
57
58
58 class ValidPassword(formencode.validators.FancyValidator):
59 class ValidPassword(formencode.validators.FancyValidator):
59
60
60 def to_python(self, value, state):
61 def to_python(self, value, state):
61 return get_crypt_password(value)
62 return get_crypt_password(value)
62
63
63 class ValidAuth(formencode.validators.FancyValidator):
64 class ValidAuth(formencode.validators.FancyValidator):
64 messages = {
65 messages = {
65 'invalid_password':_('invalid password'),
66 'invalid_password':_('invalid password'),
66 'invalid_login':_('invalid user name'),
67 'invalid_login':_('invalid user name'),
67 'disabled_account':_('Your acccount is disabled')
68 'disabled_account':_('Your acccount is disabled')
68
69
69 }
70 }
70 #error mapping
71 #error mapping
71 e_dict = {'username':messages['invalid_login'],
72 e_dict = {'username':messages['invalid_login'],
72 'password':messages['invalid_password']}
73 'password':messages['invalid_password']}
73 e_dict_disable = {'username':messages['disabled_account']}
74 e_dict_disable = {'username':messages['disabled_account']}
74
75
75 def validate_python(self, value, state):
76 def validate_python(self, value, state):
76 sa = meta.Session
77 sa = meta.Session
77 crypted_passwd = get_crypt_password(value['password'])
78 crypted_passwd = get_crypt_password(value['password'])
78 username = value['username']
79 username = value['username']
79 try:
80 try:
80 user = sa.query(User).filter(User.username == username).one()
81 user = sa.query(User).filter(User.username == username).one()
81 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
82 except (NoResultFound, MultipleResultsFound, OperationalError) as e:
82 log.error(e)
83 log.error(e)
83 user = None
84 user = None
84 raise formencode.Invalid(self.message('invalid_password',
85 raise formencode.Invalid(self.message('invalid_password',
85 state=State_obj), value, state,
86 state=State_obj), value, state,
86 error_dict=self.e_dict)
87 error_dict=self.e_dict)
87 if user:
88 if user:
88 if user.active:
89 if user.active:
89 if user.username == username and user.password == crypted_passwd:
90 if user.username == username and user.password == crypted_passwd:
90 from pylons_app.lib.auth import AuthUser
91 from pylons_app.lib.auth import AuthUser
91 auth_user = AuthUser()
92 auth_user = AuthUser()
92 auth_user.username = username
93 auth_user.username = username
93 auth_user.is_authenticated = True
94 auth_user.is_authenticated = True
94 auth_user.is_admin = user.admin
95 auth_user.is_admin = user.admin
95 session['hg_app_user'] = auth_user
96 session['hg_app_user'] = auth_user
96 session.save()
97 session.save()
97 log.info('user %s is now authenticated', username)
98 log.info('user %s is now authenticated', username)
99
100 try:
101 user.last_login = datetime.datetime.now()
102 sa.add(user)
103 sa.commit()
104 except (OperationalError) as e:
105 log.error(e)
106 sa.rollback()
107
98 return value
108 return value
99 else:
109 else:
100 log.warning('user %s not authenticated', username)
110 log.warning('user %s not authenticated', username)
101 raise formencode.Invalid(self.message('invalid_password',
111 raise formencode.Invalid(self.message('invalid_password',
102 state=State_obj), value, state,
112 state=State_obj), value, state,
103 error_dict=self.e_dict)
113 error_dict=self.e_dict)
104 else:
114 else:
105 log.warning('user %s is disabled', username)
115 log.warning('user %s is disabled', username)
106 raise formencode.Invalid(self.message('disabled_account',
116 raise formencode.Invalid(self.message('disabled_account',
107 state=State_obj),
117 state=State_obj),
108 value, state,
118 value, state,
109 error_dict=self.e_dict_disable)
119 error_dict=self.e_dict_disable)
110
120
111
121
112
122
113 #===============================================================================
123 #===============================================================================
114 # FORMS
124 # FORMS
115 #===============================================================================
125 #===============================================================================
116 class LoginForm(formencode.Schema):
126 class LoginForm(formencode.Schema):
117 allow_extra_fields = True
127 allow_extra_fields = True
118 filter_extra_fields = True
128 filter_extra_fields = True
119 username = UnicodeString(
129 username = UnicodeString(
120 strip=True,
130 strip=True,
121 min=3,
131 min=3,
122 not_empty=True,
132 not_empty=True,
123 messages={
133 messages={
124 'empty':_('Please enter a login'),
134 'empty':_('Please enter a login'),
125 'tooShort':_('Enter a value %(min)i characters long or more')}
135 'tooShort':_('Enter a value %(min)i characters long or more')}
126 )
136 )
127
137
128 password = UnicodeString(
138 password = UnicodeString(
129 strip=True,
139 strip=True,
130 min=3,
140 min=3,
131 not_empty=True,
141 not_empty=True,
132 messages={
142 messages={
133 'empty':_('Please enter a password'),
143 'empty':_('Please enter a password'),
134 'tooShort':_('Enter a value %(min)i characters long or more')}
144 'tooShort':_('Enter a value %(min)i characters long or more')}
135 )
145 )
136
146
137
147
138 #chained validators have access to all data
148 #chained validators have access to all data
139 chained_validators = [ValidAuth]
149 chained_validators = [ValidAuth]
140
150
141 def UserForm(edit=False):
151 def UserForm(edit=False):
142 class _UserForm(formencode.Schema):
152 class _UserForm(formencode.Schema):
143 allow_extra_fields = True
153 allow_extra_fields = True
144 filter_extra_fields = True
154 filter_extra_fields = True
145 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
155 username = All(UnicodeString(strip=True, min=3, not_empty=True), ValidUsername)
146 if edit:
156 if edit:
147 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
157 new_password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
148 else:
158 else:
149 password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
159 password = All(UnicodeString(strip=True, min=3, not_empty=False), ValidPassword)
150 active = StringBoolean(if_missing=False)
160 active = StringBoolean(if_missing=False)
151 name = UnicodeString(strip=True, min=3, not_empty=True)
161 name = UnicodeString(strip=True, min=3, not_empty=True)
152 lastname = UnicodeString(strip=True, min=3, not_empty=True)
162 lastname = UnicodeString(strip=True, min=3, not_empty=True)
153 email = Email(not_empty=True)
163 email = Email(not_empty=True)
154
164
155 return _UserForm
165 return _UserForm
General Comments 0
You need to be logged in to leave comments. Login now