Mercurial > hg > ltpdarepo
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 |
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 | 13 from MySQLdb.cursors import DictCursor |
33
6b7774cff458
Implement validation for duplicate usernames.
Daniele Nicolodi <daniele@grinta.net>
parents:
21
diff
changeset
|
14 |
0 | 15 from ltpdarepo.form import Form |
16 | |
88
7d03f602cade
Implement user activation.
Daniele Nicolodi <daniele@grinta.net>
parents:
87
diff
changeset
|
17 INVALIDPASSWORD = '!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' |
0 | 18 |
19 | |
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 | 28 name = TextField("Given name") |
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 | 33 telephone = TextField("Telephone") |
34 institution = TextField("Institution") | |
35 admin = BooleanField("Admin") | |
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 | 44 |
45 class IPassword(Form): | |
46 password = PasswordField() | |
47 confirm = PasswordField() | |
48 | |
49 def validate_password(form, field): | |
50 if not form.password.data == form.confirm.data: | |
51 raise validators.ValidationError(u"Passwords do not match.") | |
52 | |
53 | |
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 | 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 | 60 self.username = username |
61 self.name = name | |
62 self.surname = surname | |
63 self.email = email | |
64 self.telephone = telephone | |
65 self.institution = institution | |
66 self.admin = bool(admin) | |
67 | |
68 def __getitem__(self, name): | |
69 return getattr(self, name) | |
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 | 79 curs.execute("""SELECT username, |
80 given_name AS name, | |
81 family_name AS surname, | |
82 email, institution, telephone, | |
83 is_admin AS admin | |
84 FROM users WHERE username=%s""", username) | |
85 user = curs.fetchone() | |
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 | 89 |
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 | 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 | 95 |
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 | 99 |
100 curs.execute("""INSERT INTO users (username, given_name, family_name, | |
101 email, telephone, institution, is_admin) | |
102 VALUES (%s, %s, %s, %s, %s, %s, %s)""", | |
103 (self.username, self.name, self.surname, | |
104 self.email, self.telephone, self.institution, self.admin)) | |
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 | 107 |
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 | 110 |
111 curs.execute("""DELETE FROM users WHERE username=%s""", self.username) | |
112 curs.execute("""SELECT Host FROM mysql.user WHERE User=%s""", self.username) | |
113 hosts = [row[0] for row in curs.fetchall()] | |
114 for host in hosts: | |
115 curs.execute("""DROP USER %s@%s""", (self.username, host)) | |
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 | 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 | 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 | 132 |
133 curs.execute("""UPDATE users SET given_name=%s, family_name=%s, email=%s, | |
134 institution=%s, telephone=%s, is_admin=%s | |
135 WHERE username=%s""", | |
136 (self.name, self.surname, self.email, | |
137 self.telephone, self.institution, self.admin, self.username)) | |
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 | 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 | 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 | 145 hosts = [row[0] for row in curs.fetchall()] |
146 for host in hosts: | |
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 | 149 |
41
ce7734a6b6ad
Consistently access database connection through Flask global variables.
Daniele Nicolodi <daniele@grinta.net>
parents:
33
diff
changeset
|
150 g.db.commit() |