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