· 7 years ago · Mar 27, 2018, 02:34 PM
1# -*- coding: utf-8 -*-
2from flask import Flask, redirect, url_for, flash, render_template, g, current_app, request
3import base64
4from io import BytesIO
5from werkzeug.security import generate_password_hash, check_password_hash
6
7from flask_wtf import FlaskForm, validators
8from wtforms import StringField, PasswordField, SubmitField, SelectField
9from flask_sqlalchemy import SQLAlchemy
10from wtforms.validators import Required, Length, EqualTo
11from flask_bootstrap import Bootstrap
12from flask_login import LoginManager, UserMixin, login_user, logout_user,
13 current_user
14
15# AUTH
16from flask_sqlalchemy import BaseQuery
17from flask_principal import Principal, RoleNeed, UserNeed, Permission, Identity, identity_changed, identity_loaded, AnonymousIdentity
18from werkzeug.utils import cached_property
19
20app = Flask(__name__)
21app.config.update(
22 SQLALCHEMY_DATABASE_URI = 'sqlite:///2028.sqlite',
23 DEBUG = True,
24 SECRET_KEY = 'secret'
25)
26app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
27
28# initialize extensions
29bootstrap = Bootstrap(app)
30db = SQLAlchemy(app)
31lm = LoginManager(app)
32Principal(app)
33
34# User Information providers
35@identity_loaded.connect_via(app)
36def on_identity_loaded(sender, identity):
37 g.user = User.query.from_identity(identity)
38
39# Permission
40admin = Permission(RoleNeed('admin'))
41member = Permission(RoleNeed('member'))
42
43# MODELS
44class UserQuery(BaseQuery):
45
46 def from_identity(self):
47 try:
48 user = self.get(int(identity))
49 except ValueError:
50 user = current_user
51
52 if user:
53 identity.provides.update(user.provides)
54
55 identity.user = user
56
57 return user
58
59class User(UserMixin, db.Model):
60
61 query_class = UserQuery
62
63 MEMBER = 100
64 ADMIN = 300
65
66 __tablename__ = 'user'
67 id = db.Column(db.Integer, unique=True, nullable=False, primary_key=True)
68 username = db.Column(db.String(80), unique=True, nullable=False)
69 password_hash = db.Column(db.String(80))
70 role = db.Column(db.Integer, default=100)
71 player = db.Column(db.String, default=100)
72
73 @property
74 def password(self):
75 raise AttributeError('password is not a readable attribute')
76
77 @password.setter
78 def password(self, password):
79 self.password_hash = generate_password_hash(password)
80
81 def verify_password(self, password):
82 return check_password_hash(self.password_hash, password)
83
84 @cached_property
85 def permissions(self):
86 return self.Permissions(self)
87
88 @cached_property
89 def provides(self):
90 needs = [RoleNeed('authenticated'), UserNeed(self.id)]
91
92 if self.is_member:
93 needs.append(RoleNeed('member'))
94
95 if self.is_admin:
96 needs.append(RoleNeed('admin'))
97
98 return needs
99
100 @property
101 def is_member(self):
102 return self.role == self.MEMBER
103
104 @property
105 def is_admin(self):
106 return self.role == self.ADMIN
107
108@lm.user_loader
109def load_user(user_id):
110 """User loader callback for Flask-Login."""
111 return User.query.get(int(user_id))
112
113# FORMS
114class CMSignupForm(FlaskForm):
115 player = SelectField(validators=[Required()],
116 choices=[("CM", "CM"),
117 ("CA", "CA")])
118 username = StringField('Username', validators=[Required(), Length(1, 9)])
119 password = PasswordField("Password", validators=[Required(), Length(1, 9)])
120 password_again = PasswordField('Password again',
121 validators=[Required(), EqualTo('password')])
122 submit = SubmitField("Signup")
123
124class CASignupForm(FlaskForm):
125 player = SelectField(validators=[Required()],
126 choices=[("CM", "CM"),
127 ("CA", "CA")])
128 username = StringField('Username', validators=[Required(), Length(1, 9)])
129 password = PasswordField("Password", validators=[Required(), Length(1, 9)])
130 password_again = PasswordField('Password again',
131 validators=[Required(), EqualTo('password')])
132 submit = SubmitField("Signup")
133
134class LoginForm(FlaskForm):
135 username = StringField('Username', validators=[Required(), Length(1, 9)])
136 password = PasswordField("Password", validators=[Required(), Length(1, 9)])
137 submit = SubmitField("Login")
138
139# VIEWS
140@app.route('/')
141def index():
142 user = User.query.all()
143 return render_template('index.html', user=user)
144
145@app.route('/signup', methods=('GET', 'POST'))
146def cmsignup():
147 if current_user.is_authenticated:
148 # if user is logged in we get out of here
149 return redirect(url_for('index'))
150
151 form = CMSignupForm()
152
153 if form.validate_on_submit():
154 user = User()
155 form.populate_obj(user)
156
157 db.session.add(user)
158 db.session.commit()
159
160 flash('Signup Success %s' % user.username, 'success')
161
162 return redirect(url_for('login'))
163
164 return render_template('cmsignup.html', form=form)
165
166@app.route('/signup', methods=('GET', 'POST'))
167def casignup():
168 if current_user.is_authenticated:
169 # if user is logged in we get out of here
170 return redirect(url_for('index'))
171
172 form = CASignupForm()
173
174 if form.validate_on_submit():
175 user = User()
176 form.populate_obj(user)
177
178 db.session.add(user)
179 db.session.commit()
180
181 flash('Signup Success %s' % user.username, 'success')
182
183 return redirect(url_for('login'))
184
185 return render_template('casignup.html', form=form)
186
187@app.route('/login', methods=('GET', 'POST',))
188def login():
189 """User login route."""
190 if current_user.is_authenticated:
191 # if user is logged in we get out of here
192 return redirect(url_for('index'))
193
194 form = LoginForm()
195
196 if form.validate_on_submit():
197 user = User.query.filter_by(username=form.username.data).first()
198 if user is None or not user.verify_password(form.password.data):
199 flash('ooo!')
200
201 identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
202 flash('ooo, %s' % user.username)
203
204 return redirect(url_for('index'))
205
206 login_user(user)
207 flash('You are now logged in!')
208 return redirect(url_for('cm_e_11a'))
209
210 return render_template('login.html', form=form)
211
212@app.route('/logout')
213def logout():
214 identity_changed.send(current_app._get_current_object(), identity=AnonymousIdentity())
215 flash('oooo!')
216
217 return redirect(url_for('index'))
218
219@app.route('/page')
220@admin.require(401)
221def page():
222 return render_template('page.html')
223
224@app.errorhandler(401)
225def unauthorized(error):
226 flash('Please login to see this page', 'error')
227 return redirect(url_for('login', next=request.path))
228
229db.create_all()
230
231if __name__ == '__main__':
232 app.run()
233
234File "/home/ubuntu/workspace/pb/auth.py", line 201, in login
235 identity_changed.send(current_app._get_current_object(), identity=Identity(user.id))
236AttributeError: 'NoneType' object has no attribute 'id'
237
238File "/home/ubuntu/workspace/pb/auth.py", line 37, in on_identity_loaded
239 g.user = User.query.from_identity(identity)
240TypeError: from_identity() takes 1 positional argument but 2 were given