app.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import os
  2. from flask import Flask, url_for, redirect, render_template, request
  3. from flask_sqlalchemy import SQLAlchemy
  4. from wtforms import form, fields, validators
  5. import flask_admin as admin
  6. import flask_login as login
  7. from flask_admin.contrib import sqla
  8. from flask_admin import helpers, expose
  9. from werkzeug.security import generate_password_hash, check_password_hash
  10. # Create Flask application
  11. app = Flask(__name__)
  12. # Create dummy secrey key so we can use sessions
  13. app.config['SECRET_KEY'] = '123456790'
  14. # Create in-memory database
  15. app.config['DATABASE_FILE'] = 'sample_db.sqlite'
  16. app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
  17. app.config['SQLALCHEMY_ECHO'] = True
  18. db = SQLAlchemy(app)
  19. # Create user model.
  20. class User(db.Model):
  21. id = db.Column(db.Integer, primary_key=True)
  22. first_name = db.Column(db.String(100))
  23. last_name = db.Column(db.String(100))
  24. login = db.Column(db.String(80), unique=True)
  25. email = db.Column(db.String(120))
  26. password = db.Column(db.String(64))
  27. # Flask-Login integration
  28. def is_authenticated(self):
  29. return True
  30. def is_active(self):
  31. return True
  32. def is_anonymous(self):
  33. return False
  34. def get_id(self):
  35. return self.id
  36. # Required for administrative interface
  37. def __unicode__(self):
  38. return self.username
  39. # Define login and registration forms (for flask-login)
  40. class LoginForm(form.Form):
  41. login = fields.StringField(validators=[validators.required()])
  42. password = fields.PasswordField(validators=[validators.required()])
  43. def validate_login(self, field):
  44. user = self.get_user()
  45. if user is None:
  46. raise validators.ValidationError('Invalid user')
  47. # we're comparing the plaintext pw with the the hash from the db
  48. if not check_password_hash(user.password, self.password.data):
  49. # to compare plain text passwords use
  50. # if user.password != self.password.data:
  51. raise validators.ValidationError('Invalid password')
  52. def get_user(self):
  53. return db.session.query(User).filter_by(login=self.login.data).first()
  54. class RegistrationForm(form.Form):
  55. login = fields.StringField(validators=[validators.required()])
  56. email = fields.StringField()
  57. password = fields.PasswordField(validators=[validators.required()])
  58. def validate_login(self, field):
  59. if db.session.query(User).filter_by(login=self.login.data).count() > 0:
  60. raise validators.ValidationError('Duplicate username')
  61. # Initialize flask-login
  62. def init_login():
  63. login_manager = login.LoginManager()
  64. login_manager.init_app(app)
  65. # Create user loader function
  66. @login_manager.user_loader
  67. def load_user(user_id):
  68. return db.session.query(User).get(user_id)
  69. # Create customized model view class
  70. class MyModelView(sqla.ModelView):
  71. def is_accessible(self):
  72. return login.current_user.is_authenticated
  73. # Create customized index view class that handles login & registration
  74. class MyAdminIndexView(admin.AdminIndexView):
  75. @expose('/')
  76. def index(self):
  77. if not login.current_user.is_authenticated:
  78. return redirect(url_for('.login_view'))
  79. return super(MyAdminIndexView, self).index()
  80. @expose('/login/', methods=('GET', 'POST'))
  81. def login_view(self):
  82. # handle user login
  83. form = LoginForm(request.form)
  84. if helpers.validate_form_on_submit(form):
  85. user = form.get_user()
  86. login.login_user(user)
  87. if login.current_user.is_authenticated:
  88. return redirect(url_for('.index'))
  89. link = '<p>Don\'t have an account? <a href="' + url_for('.register_view') + '">Click here to register.</a></p>'
  90. self._template_args['form'] = form
  91. self._template_args['link'] = link
  92. return super(MyAdminIndexView, self).index()
  93. @expose('/register/', methods=('GET', 'POST'))
  94. def register_view(self):
  95. form = RegistrationForm(request.form)
  96. if helpers.validate_form_on_submit(form):
  97. user = User()
  98. form.populate_obj(user)
  99. # we hash the users password to avoid saving it as plaintext in the db,
  100. # remove to use plain text:
  101. user.password = generate_password_hash(form.password.data)
  102. db.session.add(user)
  103. db.session.commit()
  104. login.login_user(user)
  105. return redirect(url_for('.index'))
  106. link = '<p>Already have an account? <a href="' + url_for('.login_view') + '">Click here to log in.</a></p>'
  107. self._template_args['form'] = form
  108. self._template_args['link'] = link
  109. return super(MyAdminIndexView, self).index()
  110. @expose('/logout/')
  111. def logout_view(self):
  112. login.logout_user()
  113. return redirect(url_for('.index'))
  114. # Flask views
  115. @app.route('/')
  116. def index():
  117. return render_template('index.html')
  118. # Initialize flask-login
  119. init_login()
  120. # Create admin
  121. admin = admin.Admin(app, 'Example: Auth', index_view=MyAdminIndexView(), base_template='my_master.html')
  122. # Add view
  123. admin.add_view(MyModelView(User, db.session))
  124. def build_sample_db():
  125. """
  126. Populate a small db with some example entries.
  127. """
  128. import string
  129. import random
  130. db.drop_all()
  131. db.create_all()
  132. # passwords are hashed, to use plaintext passwords instead:
  133. # test_user = User(login="test", password="test")
  134. test_user = User(login="test", password=generate_password_hash("test"))
  135. db.session.add(test_user)
  136. first_names = [
  137. 'Harry', 'Amelia', 'Oliver', 'Jack', 'Isabella', 'Charlie','Sophie', 'Mia',
  138. 'Jacob', 'Thomas', 'Emily', 'Lily', 'Ava', 'Isla', 'Alfie', 'Olivia', 'Jessica',
  139. 'Riley', 'William', 'James', 'Geoffrey', 'Lisa', 'Benjamin', 'Stacey', 'Lucy'
  140. ]
  141. last_names = [
  142. 'Brown', 'Smith', 'Patel', 'Jones', 'Williams', 'Johnson', 'Taylor', 'Thomas',
  143. 'Roberts', 'Khan', 'Lewis', 'Jackson', 'Clarke', 'James', 'Phillips', 'Wilson',
  144. 'Ali', 'Mason', 'Mitchell', 'Rose', 'Davis', 'Davies', 'Rodriguez', 'Cox', 'Alexander'
  145. ]
  146. for i in range(len(first_names)):
  147. user = User()
  148. user.first_name = first_names[i]
  149. user.last_name = last_names[i]
  150. user.login = user.first_name.lower()
  151. user.email = user.login + "@example.com"
  152. user.password = generate_password_hash(''.join(random.choice(string.ascii_lowercase + string.digits) for i in range(10)))
  153. db.session.add(user)
  154. db.session.commit()
  155. return
  156. if __name__ == '__main__':
  157. # Build a sample db on the fly, if one does not exist yet.
  158. app_dir = os.path.realpath(os.path.dirname(__file__))
  159. database_path = os.path.join(app_dir, app.config['DATABASE_FILE'])
  160. if not os.path.exists(database_path):
  161. build_sample_db()
  162. # Start app
  163. app.run(debug=True)