annotate src/ltpdarepo/user.py @ 213:3d524d31d1c2

Move setup.py to better location.
author Daniele Nicolodi <daniele@grinta.net>
date Fri, 18 Nov 2011 01:49:52 +0100
parents 234d57f3fd1d
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
188
fbab144c296c Add license information.
Daniele Nicolodi <daniele@grinta.net>
parents: 91
diff changeset
1 # Copyright 2011 Daniele Nicolodi <nicolodi@science.unitn.it>
fbab144c296c Add license information.
Daniele Nicolodi <daniele@grinta.net>
parents: 91
diff changeset
2 #
fbab144c296c Add license information.
Daniele Nicolodi <daniele@grinta.net>
parents: 91
diff changeset
3 # This software may be used and distributed according to the terms of
fbab144c296c Add license information.
Daniele Nicolodi <daniele@grinta.net>
parents: 91
diff changeset
4 # the GNU Affero General Public License version 3 or any later version.
fbab144c296c Add license information.
Daniele Nicolodi <daniele@grinta.net>
parents: 91
diff changeset
5
87
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
6 from email.utils import formataddr
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
7
33
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
8 from flask import g
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
9 from wtforms import validators
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
10 from wtforms.fields import TextField, PasswordField, BooleanField
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
11 from wtforms.validators import ValidationError
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
12
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
13 from MySQLdb.cursors import DictCursor
33
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
14
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
15 from ltpdarepo.form import Form
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
16
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
17 INVALIDPASSWORD = '!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
18
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
19
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
20 class IUser(Form):
83
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
21 username = TextField("Username",
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
22 validators=[validators.Required(),
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
23 validators.Length(max=16,
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
24 message=u'Usernames cannot be '
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
25 'longer than 16 characters'),
198
234d57f3fd1d Allow for leading digits in usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 188
diff changeset
26 validators.Regexp(r'^[0-9a-zA-Z\-\._]+$',
83
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
27 message=u'Invalid identifier.')])
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
28 name = TextField("Given name")
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
29 surname = TextField("Family name")
83
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
30 email = TextField("Email",
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
31 validators=[validators.Required(),
da7cab4398c3 MySQL limits usernames to 16 characters.
Daniele Nicolodi <daniele@grinta.net>
parents: 79
diff changeset
32 validators.Email()])
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
33 telephone = TextField("Telephone")
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
34 institution = TextField("Institution")
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
35 admin = BooleanField("Admin")
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
36
33
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
37 def validate_username(form, field):
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
38 curs = g.db.cursor()
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
39 curs.execute("SELECT DISTINCT user FROM mysql.user WHERE user <> ''")
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
40 users = [r[0] for r in curs.fetchall()]
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
41 if field.data in users:
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
42 raise ValidationError(u"MySQL already contains an user with this username.")
6b7774cff458 Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents: 21
diff changeset
43
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
44
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
45 class IPassword(Form):
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
46 password = PasswordField()
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
47 confirm = PasswordField()
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
48
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
49 def validate_password(form, field):
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
50 if not form.password.data == form.confirm.data:
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
51 raise validators.ValidationError(u"Passwords do not match.")
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
52
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
53
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
54 class User(object):
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
55 __slots__ = ('username', 'name', 'surname', 'email',
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
56 'telephone', 'institution', 'admin')
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
57
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
58 def __init__(self, username='', name='', surname='', email='',
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
59 telephone='', institution='', admin=False):
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
60 self.username = username
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
61 self.name = name
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
62 self.surname = surname
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
63 self.email = email
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
64 self.telephone = telephone
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
65 self.institution = institution
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
66 self.admin = bool(admin)
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
67
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
68 def __getitem__(self, name):
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
69 return getattr(self, name)
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
70
87
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
71 @property
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
72 def emailaddr(self):
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
73 # user email address in the form 'Name Surname <email>'
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
74 return formataddr(('%s %s' % (self.name, self.surname), self.email))
6a52c9c3d5ff Add 'emailaddr' property to User class.
Daniele Nicolodi <daniele@grinta.net>
parents: 83
diff changeset
75
20
d19c5ae165de Make load() method of the User class into a static method.
Daniele Nicolodi <daniele@grinta.net>
parents: 0
diff changeset
76 @staticmethod
d19c5ae165de Make load() method of the User class into a static method.
Daniele Nicolodi <daniele@grinta.net>
parents: 0
diff changeset
77 def load(username):
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
78 curs = g.db.cursor(DictCursor)
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
79 curs.execute("""SELECT username,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
80 given_name AS name,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
81 family_name AS surname,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
82 email, institution, telephone,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
83 is_admin AS admin
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
84 FROM users WHERE username=%s""", username)
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
85 user = curs.fetchone()
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
86 if user is None:
20
d19c5ae165de Make load() method of the User class into a static method.
Daniele Nicolodi <daniele@grinta.net>
parents: 0
diff changeset
87 return None
79
18820d874f33 Cleanup some code that survied the makeovers.
Daniele Nicolodi <daniele@grinta.net>
parents: 41
diff changeset
88 return User(**user)
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
89
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
90 def create(self):
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
91 # use an invalid password to prevent user login
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
92 password = INVALIDPASSWORD
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
93
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
94 curs = g.db.cursor()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
95
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
96 for host in ('localhost', '%'):
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
97 curs.execute("""CREATE USER %s@%s IDENTIFIED BY PASSWORD %s""",
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
98 (self.username, host, password))
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
99
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
100 curs.execute("""INSERT INTO users (username, given_name, family_name,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
101 email, telephone, institution, is_admin)
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
102 VALUES (%s, %s, %s, %s, %s, %s, %s)""",
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
103 (self.username, self.name, self.surname,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
104 self.email, self.telephone, self.institution, self.admin))
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
105
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
106 g.db.commit()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
107
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
108 def delete(self):
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
109 curs = g.db.cursor()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
110
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
111 curs.execute("""DELETE FROM users WHERE username=%s""", self.username)
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
112 curs.execute("""SELECT Host FROM mysql.user WHERE User=%s""", self.username)
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
113 hosts = [row[0] for row in curs.fetchall()]
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
114 for host in hosts:
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
115 curs.execute("""DROP USER %s@%s""", (self.username, host))
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
116
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
117 g.db.commit()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
118
91
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
119 def reset(self):
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
120 curs = g.db.cursor()
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
121
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
122 curs.execute("""SELECT Host FROM mysql.user WHERE User=%s""", self.username)
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
123 hosts = [row[0] for row in curs.fetchall()]
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
124 for host in hosts:
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
125 curs.execute("""SET PASSWORD FOR %s@%s = %s""",
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
126 (self.username, host, INVALIDPASSWORD))
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
127
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
128 g.db.commit()
5c1c7f2d6469 Implement user password reset.
Daniele Nicolodi <daniele@grinta.net>
parents: 88
diff changeset
129
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
130 def save(self):
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
131 curs = g.db.cursor()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
132
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
133 curs.execute("""UPDATE users SET given_name=%s, family_name=%s, email=%s,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
134 institution=%s, telephone=%s, is_admin=%s
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
135 WHERE username=%s""",
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
136 (self.name, self.surname, self.email,
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
137 self.telephone, self.institution, self.admin, self.username))
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
138
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
139 g.db.commit()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
140
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
141 def passwd(self, password):
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
142 curs = g.db.cursor()
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
143
21
19f233ab545f Fix empty passwords handling.
Daniele Nicolodi <daniele@grinta.net>
parents: 20
diff changeset
144 curs.execute("""SELECT Host FROM mysql.user WHERE User=%s""", self.username)
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
145 hosts = [row[0] for row in curs.fetchall()]
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
146 for host in hosts:
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
147 curs.execute("""SET PASSWORD FOR %s@%s = PASSWORD(%s)""",
88
7d03f602cade Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents: 87
diff changeset
148 (self.username, host, password))
0
c812c3020b63 Initial import.
Daniele Nicolodi <nicolodi@science.unitn.it>
parents:
diff changeset
149
41
ce7734a6b6ad Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents: 33
diff changeset
150 g.db.commit()