Skip to content

Commit 9bfb00e

Browse files
committed
add new sessioninterface flask example
1 parent 65e1b35 commit 9bfb00e

9 files changed

+772
-0
lines changed

content/pages/examples/flask/flask-example-projects-code.markdown

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,17 @@ is [open sourced under the MIT license](https://github.com/miguelgrinberg/flasky
7676
aggregator created with [Flask](/flask.html) and the
7777
[News API](https://newsapi.org/). NewsPie is provided as open source under
7878
the [MIT license](https://github.com/skamieniarz/newspie/blob/master/LICENSE).
79+
80+
81+
### tedivm's flask starter app
82+
[tedivm's flask starter app](https://github.com/tedivm/tedivms-flask) is a
83+
base of [Flask](/flask.html) code and related projects such as
84+
[Celery](/celery.html) which provides a template to start your own
85+
Flask web app. The project comes baked with an admin panel,
86+
[API authentication and authorization](/application-programming-interfaces.html),
87+
[SQLAlchemy](/sqlalchemy.html) and many other common libraries that are
88+
often used with Flask.
89+
90+
The project's code is provided as open source under the
91+
[BSD 2-Clause "Simplified" license](https://github.com/tedivm/tedivms-flask/blob/master/LICENSE.txt).
92+

content/pages/examples/flask/flask-globals-request.markdown

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,3 +1597,66 @@ class Service(MethodView):
15971597
15981598
```
15991599
1600+
1601+
## Example 11 from tedivms-flask
1602+
[tedivm's flask starter app](https://github.com/tedivm/tedivms-flask) is a
1603+
base of [Flask](/flask.html) code and related projects such as
1604+
[Celery](/celery.html) which provides a template to start your own
1605+
Flask web app. The project comes baked with an admin panel,
1606+
[API authentication and authorization](/application-programming-interfaces.html),
1607+
[SQLAlchemy](/sqlalchemy.html) and many other common libraries that are
1608+
often used with Flask.
1609+
1610+
The project's code is provided as open source under the
1611+
[BSD 2-Clause "Simplified" license](https://github.com/tedivm/tedivms-flask/blob/master/LICENSE.txt).
1612+
1613+
[**tedivms-flask / app / utils / api.py**](https://github.com/tedivm/tedivms-flask/blob/master/app/utils/api.py)
1614+
1615+
```python
1616+
# api.py
1617+
from app.models import user_models as users
1618+
from functools import wraps
1619+
~~from flask import request, abort, current_app
1620+
1621+
1622+
def is_authorized_api_user(roles=False):
1623+
"""Verify API Token and its owners permission to use it"""
1624+
~~ if 'API_ID' not in request.headers:
1625+
return False
1626+
~~ if 'API_KEY' not in request.headers:
1627+
return False
1628+
~~ api_key = users.ApiKey.query.filter(users.ApiKey.id==request.headers['API_ID']).first()
1629+
if not api_key:
1630+
return False
1631+
~~ if not current_app.user_manager.verify_password(request.headers['API_KEY'], api_key.hash):
1632+
return False
1633+
if not roles:
1634+
return True
1635+
if api_key.user.has_role('admin'):
1636+
return True
1637+
for role in roles:
1638+
if api_key.user.has_role(role):
1639+
return True
1640+
return False
1641+
1642+
1643+
def roles_accepted_api(*role_names):
1644+
def wrapper(view_function):
1645+
@wraps(view_function)
1646+
def decorated_view_function(*args, **kwargs):
1647+
if not is_authorized_api_user(role_names):
1648+
return abort(403)
1649+
return view_function(*args, **kwargs)
1650+
return decorated_view_function
1651+
return wrapper
1652+
1653+
1654+
def api_credentials_required():
1655+
def wrapper(view_function):
1656+
1657+
1658+
## ... source file continues with no further request examples...
1659+
1660+
1661+
```
1662+

content/pages/examples/flask/flask-globals-session.markdown

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,3 +742,137 @@ logger = wrap_logger(
742742
743743
```
744744
745+
746+
## Example 7 from tedivms-flask
747+
[tedivm's flask starter app](https://github.com/tedivm/tedivms-flask) is a
748+
base of [Flask](/flask.html) code and related projects such as
749+
[Celery](/celery.html) which provides a template to start your own
750+
Flask web app. The project comes baked with an admin panel,
751+
[API authentication and authorization](/application-programming-interfaces.html),
752+
[SQLAlchemy](/sqlalchemy.html) and many other common libraries that are
753+
often used with Flask.
754+
755+
The project's code is provided as open source under the
756+
[BSD 2-Clause "Simplified" license](https://github.com/tedivm/tedivms-flask/blob/master/LICENSE.txt).
757+
758+
[**tedivms-flask / app / __init__.py**](https://github.com/tedivm/tedivms-flask/blob/master/app/./__init__.py)
759+
760+
```python
761+
# __init__.py
762+
import boto3
763+
from celery import Celery
764+
from datetime import datetime
765+
import os
766+
import requests
767+
import yaml
768+
769+
~~from flask import Flask, session, render_template
770+
from flask_mail import Mail
771+
from flask_migrate import Migrate, MigrateCommand
772+
~~from flask.sessions import SessionInterface
773+
from flask_sqlalchemy import SQLAlchemy
774+
from flask_user import user_logged_out
775+
from flask_wtf.csrf import CSRFProtect
776+
777+
from beaker.cache import CacheManager
778+
from beaker.util import parse_cache_config_options
779+
from beaker.middleware import SessionMiddleware
780+
781+
# Instantiate Flask extensions
782+
db = SQLAlchemy()
783+
csrf_protect = CSRFProtect()
784+
mail = Mail()
785+
migrate = Migrate()
786+
787+
788+
def get_config():
789+
# Instantiate Flask
790+
app = Flask(__name__)
791+
792+
# Load App Config settings
793+
# Load common settings from 'app/settings.py' file
794+
app.config.from_object('app.settings')
795+
# Load local settings from environmental variable
796+
if 'APPLICATION_SETTINGS' in os.environ:
797+
798+
799+
## ... source file abbreviated to get to session examples ...
800+
801+
802+
cache_opts['cache.data_dir'] = app.config['CACHE_ROOT'] + '/data'
803+
cache_opts['cache.lock_dir'] = app.config['CACHE_ROOT'] + '/lock'
804+
805+
if 'CACHE_URL' in app.config and app.config['CACHE_URL']:
806+
cache_opts['cache.url'] = app.config['CACHE_URL']
807+
808+
809+
cache = CacheManager(**parse_cache_config_options(cache_opts))
810+
811+
812+
def init_session_manager(app):
813+
session_opts = {'cache.expire': 3600}
814+
815+
if 'CACHE_TYPE' not in app.config or not app.config['CACHE_TYPE']:
816+
app.config['CACHE_TYPE'] = 'file'
817+
818+
if app.config['CACHE_TYPE'] == 'file':
819+
if 'CACHE_ROOT' not in app.config or not app.config['CACHE_ROOT']:
820+
app.config['CACHE_ROOT'] = '/tmp/%s' % __name__
821+
822+
~~ session_opts['session.type'] = app.config['CACHE_TYPE']
823+
824+
if 'CACHE_ROOT' in app.config and app.config['CACHE_ROOT']:
825+
~~ session_opts['session.data_dir'] = app.config['CACHE_ROOT'] + '/session'
826+
827+
if 'CACHE_URL' in app.config and app.config['CACHE_URL']:
828+
~~ session_opts['session.url'] = app.config['CACHE_URL']
829+
830+
~~ session_opts['session.auto'] = app.config.get('SESSION_AUTO', True)
831+
~~ session_opts['session.cookie_expires'] = app.config.get('SESSION_COOKIE_EXPIRES', 86400)
832+
~~ session_opts['session.secret'] = app.secret_key
833+
834+
class BeakerSessionInterface(SessionInterface):
835+
def open_session(self, app, request):
836+
session = request.environ['beaker.session']
837+
return session
838+
839+
def save_session(self, app, session, response):
840+
~~ session.save()
841+
842+
app.wsgi_app = SessionMiddleware(app.wsgi_app, session_opts)
843+
app.session_interface = BeakerSessionInterface()
844+
845+
@user_logged_out.connect_via(app)
846+
def clear_session(sender, user, **extra):
847+
~~ session.clear()
848+
849+
850+
def init_celery_service(app):
851+
celery.conf.update(app.config)
852+
853+
854+
def init_error_handlers(app):
855+
856+
def show_error(status, message='An unknown error has occured.'):
857+
return render_template('pages/errors.html', error_code=status, message=message), status
858+
859+
@app.errorhandler(401)
860+
def error_unauthorized(e):
861+
return show_error(401, 'Unauthorized')
862+
863+
@app.errorhandler(403)
864+
def error_forbidden(e):
865+
return show_error(403, 'Forbidden')
866+
867+
@app.errorhandler(404)
868+
def error_pagenotfound(e):
869+
return show_error(404, 'Page not found.')
870+
871+
@app.errorhandler(500)
872+
873+
874+
## ... source file continues with no further session examples...
875+
876+
877+
```
878+

content/pages/examples/flask/flask-helpers-flash.markdown

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,3 +722,161 @@ class LoginManager(object):
722722
723723
```
724724
725+
726+
## Example 5 from tedivms-flask
727+
[tedivm's flask starter app](https://github.com/tedivm/tedivms-flask) is a
728+
base of [Flask](/flask.html) code and related projects such as
729+
[Celery](/celery.html) which provides a template to start your own
730+
Flask web app. The project comes baked with an admin panel,
731+
[API authentication and authorization](/application-programming-interfaces.html),
732+
[SQLAlchemy](/sqlalchemy.html) and many other common libraries that are
733+
often used with Flask.
734+
735+
The project's code is provided as open source under the
736+
[BSD 2-Clause "Simplified" license](https://github.com/tedivm/tedivms-flask/blob/master/LICENSE.txt).
737+
738+
[**tedivms-flask / app / views / misc_views.py**](https://github.com/tedivm/tedivms-flask/blob/master/app/views/misc_views.py)
739+
740+
```python
741+
# misc_views.py
742+
# Copyright 2017 Twin Tech Labs. All rights reserved
743+
744+
from flask import Blueprint, redirect, render_template, current_app, abort
745+
~~from flask import request, url_for, flash, send_from_directory, jsonify, render_template_string
746+
from flask_user import current_user, login_required, roles_accepted
747+
748+
from app import db
749+
from app.models.user_models import UserProfileForm, User, UsersRoles, Role
750+
from app.utils.forms import ConfirmationForm
751+
import uuid, json, os
752+
import datetime
753+
754+
# When using a Flask app factory we must use a blueprint to avoid needing 'app' for '@app.route'
755+
main_blueprint = Blueprint('main', __name__, template_folder='templates')
756+
757+
# The User page is accessible to authenticated users (users that have logged in)
758+
@main_blueprint.route('/')
759+
def member_page():
760+
if not current_user.is_authenticated:
761+
return redirect(url_for('user.login'))
762+
return render_template('pages/member_base.html')
763+
764+
# The Admin page is accessible to users with the 'admin' role
765+
@main_blueprint.route('/admin')
766+
@roles_accepted('admin')
767+
def admin_page():
768+
return redirect(url_for('main.user_admin_page'))
769+
770+
771+
772+
## ... source file abbreviated to get to flash examples ...
773+
774+
775+
if form.validate():
776+
user = User.query.filter(User.email == request.form['email']).first()
777+
if not user:
778+
user = User(email=form.email.data,
779+
first_name=form.first_name.data,
780+
last_name=form.last_name.data,
781+
password=current_app.user_manager.hash_password(form.password.data),
782+
active=True,
783+
email_confirmed_at=datetime.datetime.utcnow())
784+
db.session.add(user)
785+
db.session.commit()
786+
allowed_roles = form.roles.data
787+
for role in roles:
788+
if role.id not in allowed_roles:
789+
if role in user.roles:
790+
user.roles.remove(role)
791+
else:
792+
if role not in user.roles:
793+
user.roles.append(role)
794+
db.session.commit()
795+
~~ flash('You successfully created the new user.', 'success')
796+
return redirect(url_for('main.user_admin_page'))
797+
~~ flash('A user with that email address already exists', 'error')
798+
return render_template('pages/admin/create_user.html', form=form)
799+
800+
801+
@main_blueprint.route('/users/<user_id>/delete', methods=['GET', 'POST'])
802+
@roles_accepted('admin')
803+
def delete_user_page(user_id):
804+
if current_app.config.get('USER_LDAP', False):
805+
abort(400)
806+
form = ConfirmationForm()
807+
user = User.query.filter(User.id == user_id).first()
808+
if not user:
809+
abort(404)
810+
if form.validate():
811+
db.session.query(UsersRoles).filter_by(user_id = user_id).delete()
812+
db.session.query(User).filter_by(id = user_id).delete()
813+
db.session.commit()
814+
~~ flash('You successfully deleted your user!', 'success')
815+
return redirect(url_for('main.user_admin_page'))
816+
return render_template('pages/admin/delete_user.html', form=form)
817+
818+
819+
@main_blueprint.route('/users/<user_id>/edit', methods=['GET', 'POST'])
820+
@roles_accepted('admin')
821+
def edit_user_page(user_id):
822+
if current_app.config.get('USER_LDAP', False):
823+
abort(400)
824+
825+
user = User.query.filter(User.id == user_id).first()
826+
if not user:
827+
abort(404)
828+
829+
form = UserProfileForm(obj=user)
830+
roles = Role.query.all()
831+
form.roles.choices = [(x.id,x.name) for x in roles]
832+
833+
if form.validate():
834+
if 'password' in request.form and len(request.form['password']) >= 8:
835+
user.password = current_app.user_manager.hash_password(request.form['password'])
836+
user.email = form.email.data
837+
user.first_name = form.first_name.data
838+
user.last_name = form.last_name.data
839+
user.active = form.active.data
840+
841+
allowed_roles = form.roles.data
842+
for role in roles:
843+
if role.id not in allowed_roles:
844+
if role in user.roles:
845+
user.roles.remove(role)
846+
else:
847+
if role not in user.roles:
848+
user.roles.append(role)
849+
850+
db.session.commit()
851+
~~ flash('You successfully edited the user.', 'success')
852+
return redirect(url_for('main.user_admin_page'))
853+
854+
form.roles.data = [role.id for role in user.roles]
855+
return render_template('pages/admin/edit_user.html', form=form)
856+
857+
@main_blueprint.route('/pages/profile', methods=['GET', 'POST'])
858+
@login_required
859+
def user_profile_page():
860+
if current_app.config.get('USER_LDAP', False):
861+
abort(400)
862+
863+
# Initialize form
864+
form = UserProfileForm(request.form, obj=current_user)
865+
866+
# Process valid POST
867+
if request.method == 'POST' and form.validate():
868+
# Copy form fields to user_profile fields
869+
form.populate_obj(current_user)
870+
871+
# Save user_profile
872+
db.session.commit()
873+
874+
# Redirect to home page
875+
return redirect(url_for('main.user_profile_page'))
876+
877+
878+
## ... source file continues with no further flash examples...
879+
880+
881+
```
882+

0 commit comments

Comments
 (0)