· 5 years ago · Mar 29, 2020, 11:58 PM
1# This file contains an example Flask-User application.
2# To keep the example simple, we are applying some unusual techniques:
3# - Placing everything in one file
4# - Using class-based configuration (instead of file-based configuration)
5# - Using string-based templates (instead of file-based templates)
6
7import datetime
8from flask import Flask, request, render_template_string, render_template
9from flask_babelex import Babel
10from flask_sqlalchemy import SQLAlchemy
11from flask_user import current_user, login_required, roles_required, UserManager, UserMixin
12
13
14# Class-based application configuration
15class ConfigClass(object):
16 """ Flask application config """
17
18 # Flask settings
19 SECRET_KEY = 'This is an INSECURE secret!! DO NOT use this in production!!'
20
21 # Flask-SQLAlchemy settings
22 SQLALCHEMY_DATABASE_URI = 'sqlite:///basic_app.sqlite' # File-based SQL database
23 SQLALCHEMY_TRACK_MODIFICATIONS = False # Avoids SQLAlchemy warning
24
25 # Flask-Mail SMTP server settings
26 MAIL_SERVER = 'smtp.gmail.com'
27 MAIL_PORT = 465
28 MAIL_USE_SSL = True
29 MAIL_USE_TLS = False
30 MAIL_USERNAME = 'email@example.com'
31 MAIL_PASSWORD = 'password'
32 MAIL_DEFAULT_SENDER = '"MyApp" <noreply@example.com>'
33
34 # Flask-User settings
35 USER_APP_NAME = "Flask-User Basic App" # Shown in and email templates and page footers
36 USER_ENABLE_EMAIL = True # Enable email authentication
37 USER_ENABLE_USERNAME = False # Disable username authentication
38 USER_EMAIL_SENDER_NAME = USER_APP_NAME
39 USER_EMAIL_SENDER_EMAIL = "noreply@example.com"
40
41
42def create_app():
43 """ Flask application factory """
44
45 # Create Flask app load app.config
46 app = Flask(__name__)
47 app.config.from_object(__name__ + '.ConfigClass')
48
49 # Initialize Flask-BabelEx
50 babel = Babel(app)
51
52 # Initialize Flask-SQLAlchemy
53 db = SQLAlchemy(app)
54
55 # Define the User data-model.
56 # NB: Make sure to add flask_user UserMixin !!!
57 class User(db.Model, UserMixin):
58 __tablename__ = 'users'
59 id = db.Column(db.Integer, primary_key=True)
60 active = db.Column('is_active', db.Boolean(), nullable=False, server_default='1')
61
62 # User authentication information. The collation='NOCASE' is required
63 # to search case insensitively when USER_IFIND_MODE is 'nocase_collation'.
64 email = db.Column(db.String(255, collation='NOCASE'), nullable=False, unique=True)
65 email_confirmed_at = db.Column(db.DateTime())
66 password = db.Column(db.String(255), nullable=False, server_default='')
67
68 # User information
69 first_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='')
70 last_name = db.Column(db.String(100, collation='NOCASE'), nullable=False, server_default='')
71
72 # Define the relationship to Role via UserRoles
73 roles = db.relationship('Role', secondary='user_roles')
74
75 # Define the Role data-model
76 class Role(db.Model):
77 __tablename__ = 'roles'
78 id = db.Column(db.Integer(), primary_key=True)
79 name = db.Column(db.String(50), unique=True)
80
81 # Define the UserRoles association table
82 class UserRoles(db.Model):
83 __tablename__ = 'user_roles'
84 id = db.Column(db.Integer(), primary_key=True)
85 user_id = db.Column(db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE'))
86 role_id = db.Column(db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
87
88 # Setup Flask-User and specify the User data-model
89 user_manager = UserManager(app, db, User)
90
91 # Create all database tables
92 db.create_all()
93
94 # Create 'member@example.com' user with no roles
95 if not User.query.filter(User.email == 'member@example.com').first():
96 user = User(
97 email='member@example.com',
98 email_confirmed_at=datetime.datetime.utcnow(),
99 password=user_manager.hash_password('Password1'),
100 )
101 db.session.add(user)
102 db.session.commit()
103
104 # Create 'admin@example.com' user with 'Admin' and 'Agent' roles
105 if not User.query.filter(User.email == 'admin@example.com').first():
106 user = User(
107 email='admin@example.com',
108 email_confirmed_at=datetime.datetime.utcnow(),
109 password=user_manager.hash_password('Password1'),
110 )
111 user.roles.append(Role(name='Admin'))
112 user.roles.append(Role(name='Agent'))
113 db.session.add(user)
114 db.session.commit()
115
116 # The Home page is accessible to anyone
117 @app.route('/')
118 def home_page():
119 jobs = db.engine.execute('')
120 return render_template_string("""
121 {% extends "flask_user_layout.html" %}
122 {% block content %}
123 <h2>{%trans%}Home page{%endtrans%}</h2>
124 <p><a href={{ url_for('user.register') }}>{%trans%}Register{%endtrans%}</a></p>
125 <p><a href={{ url_for('user.login') }}>{%trans%}Sign in{%endtrans%}</a></p>
126 <p><a href={{ url_for('home_page') }}>{%trans%}Home Page{%endtrans%}</a> (accessible to anyone)</p>
127 <p><a href={{ url_for('member_page') }}>{%trans%}Member Page{%endtrans%}</a> (login_required: member@example.com / Password1)</p>
128 <p><a href={{ url_for('admin_page') }}>{%trans%}Admin Page{%endtrans%}</a> (role_required: admin@example.com / Password1')</p>
129 <p><a href={{ url_for('user.logout') }}>{%trans%}Sign out{%endtrans%}</a></p>
130 {% endblock %}
131 """)
132
133 # The Members page is only accessible to authenticated users
134 @app.route('/members')
135 @login_required # Use of @login_required decorator
136 def member_page():
137 return render_template_string("""
138 {% extends "flask_user_layout.html" %}
139 {% block content %}
140 <h2>{%trans%}Members page{%endtrans%}</h2>
141 <p><a href={{ url_for('user.register') }}>{%trans%}Register{%endtrans%}</a></p>
142 <p><a href={{ url_for('user.login') }}>{%trans%}Sign in{%endtrans%}</a></p>
143 <p><a href={{ url_for('home_page') }}>{%trans%}Home Page{%endtrans%}</a> (accessible to anyone)</p>
144 <p><a href={{ url_for('member_page') }}>{%trans%}Member Page{%endtrans%}</a> (login_required: member@example.com / Password1)</p>
145 <p><a href={{ url_for('admin_page') }}>{%trans%}Admin Page{%endtrans%}</a> (role_required: admin@example.com / Password1')</p>
146 <p><a href={{ url_for('user.logout') }}>{%trans%}Sign out{%endtrans%}</a></p>
147 {% endblock %}
148 """)
149
150 # The Admin page requires an 'Admin' role.
151 @app.route('/admin')
152 @roles_required('Admin') # Use of @roles_required decorator
153 def admin_page():
154 return render_template_string("""
155 {% extends "flask_user_layout.html" %}
156 {% block content %}
157 <h2>{%trans%}Admin Page{%endtrans%}</h2>
158 <p><a href={{ url_for('user.register') }}>{%trans%}Register{%endtrans%}</a></p>
159 <p><a href={{ url_for('user.login') }}>{%trans%}Sign in{%endtrans%}</a></p>
160 <p><a href={{ url_for('home_page') }}>{%trans%}Home Page{%endtrans%}</a> (accessible to anyone)</p>
161 <p><a href={{ url_for('member_page') }}>{%trans%}Member Page{%endtrans%}</a> (login_required: member@example.com / Password1)</p>
162 <p><a href={{ url_for('admin_page') }}>{%trans%}Admin Page{%endtrans%}</a> (role_required: admin@example.com / Password1')</p>
163 <p><a href={{ url_for('user.logout') }}>{%trans%}Sign out{%endtrans%}</a></p>
164 {% endblock %}
165 """)
166
167 @app.route("/books")
168 @login_required
169 def books():
170 books = db.engine.execute('SELECT * FROM Book')
171
172 return render_template('books.html', books=books)
173
174 @app.route('/contact-us')
175 @login_required
176 def contact_us():
177 return render_template('contact-us.html')
178
179 @app.route("/seed_db")
180 @login_required
181 def seed_db():
182 db.engine.execute('DROP TABLE IF EXISTS Book', commit=True)
183 db.engine.execute('CREATE TABLE Book (author TEXT, title TEXT, description TEXT)', commit=True)
184 db.engine.execute(
185 'INSERT INTO Book (author, title, description) VALUES ("Mary Shelly", "Frankenstein", "A horror story written by a romantic.")',
186 commit=True)
187 db.engine.execute(
188 'INSERT INTO Book (author, title, description) VALUES ("Henry James", "The Turn of the Screw", "Another British horror story.")',
189 commit=True)
190 db.engine.execute(
191 'INSERT INTO Book (author, title, description) VALUES ("Max Weber", "The Protestant Work Ethic and Spirit of Capitalism", "A classic early 20th century sociology text.")',
192 commit=True)
193 db.engine.execute(
194 'INSERT INTO Book (author, title, description) VALUES ("Robert Putnam", "Bowling Alone", "A classic late 20th century sociology text.")',
195 commit=True)
196
197 book_query = db.engine.execute('SELECT rowid, * FROM Book')
198 for book in book_query:
199 print(book['rowid'])
200 print(book['author'])
201
202 return '<h1>DB Seeded!<h1>'
203
204 @app.route('/erase_DB')
205 @login_required
206 def erase_db():
207 db.engine.execute('DELETE FROM Book', commit=True)
208 return '<h1>DB Erased!<h1>'
209
210 @app.route('/add_book', methods={'GET', 'POST'})
211 def add_book():
212 if request.method == 'POST':
213 author = request.form['author']
214 title = request.form['title']
215 description = request.form['description']
216
217 db.engine.execute('INSERT INTO Book (author, title, description ) VALUES (?, ?, ?)',
218 (author, title, description), commit=True)
219
220 return render_template('add_book.html', book_title=title)
221 return render_template('add_book.html', book_title='')
222
223 return app
224
225# Start development web server
226if __name__ == '__main__':
227 app = create_app()
228 app.run(host='0.0.0.0', port=5000, debug=True)