def create_blueprint(name, import_name, **kwargs): ''' Provides basic blueprint creation for all API handlers. ''' url_prefix = kwargs.pop('url_prefix', '') bp = Blueprint(name, import_name, url_prefix=url_prefix) # Set App level before-request middleware. bp.before_app_first_request(lambda: None) # Set global before-request bp.before_app_request(lambda: None) return bp
class RestApi(object): def __init__(self, name, import_name, **kw): self.bp = Blueprint(name, import_name, **kw) def route(self, url, **options): """ 通过装饰器注册路由 以下是例子: api = RestApi('home', __name__) @api.route('/') @api.route('/home, endpoint='home') class HomeApi(RestView): def get(self): return self.ok() 也可以限制每个路由接受的方法 @api.route('/', methods=['GET']) @api.route('/create, methods=['POST']) class EmployeeCreateApi(RestView): def get(self): return self.ok() def post(self): name = request.form.get('name') ... return self.ok() """ def decorator(cls): endpoint = options.pop("endpoint", None) or cls.__name__ methods = options.pop("methods", None) or cls.methods self.bp.add_url_rule(url, view_func=cls.as_view(endpoint), methods=methods) return cls return decorator def before_app_request(self, func): return self.bp.before_app_request(func)
if error is None: session.clear() session['user_id'] = user.uid session['user_name'] = user.username res = {"user_id": user.uid, "name": user.username} return jsonify(Const.errcode('0', res=res)) # flash(error) return abort(404) ''' bp.before_app_request() 注册一个 在视图函数之前运行的函数,不论其 URL 是什么。 load_logged_in_user 检查用户 id 是否已经储存在 session 中,并从数据库中获取用户数据, 然后储存在 g.user 中。 g.user 的持续时间比请求要长。 如果没有用户 id ,或者 id 不存在, 那么 g.user 将会是 None 。 ''' @bp.before_app_request def load_logged_in_user(): user_id = session.get('user_id') if user_id is None: g.user = None else: g.user = odb.query_per(User, 'uid', user_id)
# -*- coding: UTF-8 -*- __author__ = 'hunter' from flask import Blueprint from app.util.response_util import code_handle from app.util.login_util import login api = Blueprint('api', __name__) api.after_app_request(code_handle) api.before_app_request(login) from . import views, errors
def create_blueprint(import_name, blogging_engine): blog_app = Blueprint("blogging", import_name, template_folder='templates') # register index index_func = cached_func(blogging_engine, index) blog_app.add_url_rule("/", defaults={"count": None, "page": 1}, view_func=index_func) blog_app.add_url_rule("/<int:count>/", defaults={"page": 1}, view_func=index_func) blog_app.add_url_rule("/<int:count>/<int:page>/", view_func=index_func) # register page_by_id page_by_id_func = cached_func(blogging_engine, page_by_id) blog_app.add_url_rule("/page/<int:post_id>/", defaults={"slug": ""}, view_func=page_by_id_func) blog_app.add_url_rule("/page/<int:post_id>/<slug>/", view_func=page_by_id_func) # register posts_by_tag posts_by_tag_func = cached_func(blogging_engine, posts_by_tag) blog_app.add_url_rule("/tag/<tag>/", defaults=dict(count=None, page=1), view_func=posts_by_tag_func) blog_app.add_url_rule("/tag/<tag>/<int:count>/", defaults=dict(page=1), view_func=posts_by_tag_func) blog_app.add_url_rule("/tag/<tag>/<int:count>/<int:page>/", view_func=posts_by_tag_func) # register posts_by_author posts_by_author_func = cached_func(blogging_engine, posts_by_author) blog_app.add_url_rule("/author/<user_id>/", defaults=dict(count=None, page=1), view_func=posts_by_author_func) blog_app.add_url_rule("/author/<user_id>/<int:count>/", defaults=dict(page=1), view_func=posts_by_author_func) blog_app.add_url_rule("/author/<user_id>/<int:count>/<int:page>/", view_func=posts_by_author_func) # register editor editor_func = editor # For now lets not cache this blog_app.add_url_rule('/editor/', methods=["GET", "POST"], defaults={"post_id": None}, view_func=editor_func) blog_app.add_url_rule('/editor/<int:post_id>/', methods=["GET", "POST"], view_func=editor_func) # register delete delete_func = delete # For now lets not cache this blog_app.add_url_rule("/delete/<int:post_id>/", methods=["POST"], view_func=delete_func) # register sitemap sitemap_func = cached_func(blogging_engine, sitemap) blog_app.add_url_rule("/sitemap.xml", view_func=sitemap_func) # register feed feed_func = cached_func(blogging_engine, feed) blog_app.add_url_rule('/feeds/all.atom.xml', view_func=feed_func) #register before app request # to set the language for sqlalchemy plugin blog_app.before_app_request(set_locale) return blog_app
and the browser then sends it back with subsequent requests. Now that the user's id is stored in the session, it will be available on subsequent requests. At the beginning of each request, if a user is logged in, their information should be loaded and made available to other views. """ session.clear() session['user_id'] = user['id'] return redirect(url_for('main_index')) flash(error) return render_template('auth/login.html') """ bp.before_app_request() registers a function that runs before the view function, no matter what URL is requested. load_logged_in_user checks if a user id is stored in the session and gets that user's data from the database, storing it on g.user, which lasts for the length of the request. If there is no user id, or if the id doesn't exist, g.user will be None. """ @bp.before_app_request def load_logged_in_user(): user_id = session.get('user_id') if user_id is None: g.user = None else:
import flask_restplus from flask import Blueprint from .. import OrganizationsManager orgs_blueprint = Blueprint('organizations', __name__) api = flask_restplus.Api(app=orgs_blueprint, doc='/docs') def get_orgs_config(): return OrganizationsManager.instance.orgs_config from . import environ orgs_blueprint.before_app_request(environ.push_environ_to_g) from . import rest
class Dockerflow(object): """ The Dockerflow Flask extension. Set it up like this: .. code-block:: python :caption: ``myproject.py`` from flask import Flask from dockerflow.flask import Dockerflow app = Flask(__name__) dockerflow = Dockerflow(app) Or if you use the Flask application factory pattern, in an own module set up Dockerflow first: .. code-block:: python :caption: ``myproject/deployment.py`` from dockerflow.flask import Dockerflow dockerflow = Dockerflow() and then import and initialize it with the Flask application object when you create the application: .. code-block:: python :caption: ``myproject/app.py`` def create_app(config_filename): app = Flask(__name__) app.config.from_pyfile(config_filename) from myproject.deployment import dockerflow dockerflow.init_app(app) from myproject.views.admin import admin from myproject.views.frontend import frontend app.register_blueprint(admin) app.register_blueprint(frontend) return app See the parameters for a more detailed list of optional features when initializing the extension. :param app: The Flask app that this Dockerflow extension should be initialized with. :type root: ~flask.Flask or None :param db: A Flask-SQLAlchemy extension instance to be used by the built-in Dockerflow check for the database connection. :param redis: A Redis connection to be used by the built-in Dockerflow check for the Redis connection. :param migrate: A Flask-Migrate extension instance to be used by the built-in Dockerflow check for Alembic migrations. :param silenced_checks: Dockerflow check IDs to ignore when running through the list of configured checks. :type silenced_checks: list :param version_path: The filesystem path where the ``version.json`` can be found. Defaults to the parent directory of the Flask app's root path. """ def __init__(self, app=None, db=None, redis=None, migrate=None, silenced_checks=None, version_path=None, *args, **kwargs): # The Flask blueprint to add the Dockerflow signal callbacks and views self._blueprint = Blueprint('dockerflow', 'dockerflow.flask.app') # The Dockerflow specific logger to be used by internals of this # extension. self.logger = logging.getLogger('dockerflow.flask') self.logger.addHandler(logging.NullHandler()) self.logger.setLevel(logging.INFO) # The request summary logger to be used by this extension # without pre-configuration. See docs for how to set it up. self.summary_logger = logging.getLogger('request.summary') # An ordered dictionary for storing custom Dockerflow checks in. self.checks = OrderedDict() # A list of IDs of custom Dockerflow checks to ignore in case they # show up. self.silenced_checks = silenced_checks or [] # The path where to find the version JSON file. Defaults to the # parent directory of the app root path. self.version_path = version_path self._version_callback = version.get_version # Initialize the app if given. if app: self.init_app(app) # Initialize the built-in checks. if db: self.init_check(checks.check_database_connected, db) if redis: self.init_check(checks.check_redis_connected, redis) if migrate: self.init_check(checks.check_migrations_applied, migrate) def init_check(self, check, obj): """ Adds a given check callback with the provided object to the list of checks. Useful for built-ins but also advanced custom checks. """ self.logger.info('Adding extension check %s' % check.__name__) check = functools.wraps(check)(functools.partial(check, obj)) self.check(func=check) def init_app(self, app): """ Initializes the extension with the given app, registers the built-in views with an own blueprint and hooks up our signal callbacks. """ # If no version path was provided in the init of the Dockerflow # class we'll use the parent directory of the app root path. if self.version_path is None: self.version_path = os.path.dirname(app.root_path) for view in ( ('/__version__', 'version', self._version_view), ('/__heartbeat__', 'heartbeat', self._heartbeat_view), ('/__lbheartbeat__', 'lbheartbeat', self._lbheartbeat_view), ): self._blueprint.add_url_rule(*view) self._blueprint.before_app_request(self._before_request) self._blueprint.after_app_request(self._after_request) self._blueprint.app_errorhandler(HeartbeatFailure)( self._heartbeat_exception_handler) app.register_blueprint(self._blueprint) got_request_exception.connect(self._got_request_exception, sender=app) if not hasattr(app, 'extensions'): # pragma: nocover app.extensions = {} app.extensions['dockerflow'] = self def _heartbeat_exception_handler(self, error): """ An exception handler to act as a middleman to return a heartbeat view response with a 500 error code. """ return error.get_response() def _before_request(self): """ The before_request callback. """ g._request_id = str(uuid.uuid4()) g._start_timestamp = time.time() def _after_request(self, response): """ The signal handler for the request_finished signal. """ if not getattr(g, '_has_exception', False): extra = self.summary_extra() self.summary_logger.info('', extra=extra) return response def _got_request_exception(self, sender, exception, **extra): """ The signal handler for the got_request_exception signal. """ extra = self.summary_extra() extra['errno'] = 500 self.summary_logger.error(str(exception), extra=extra) g._has_exception = True def user_id(self): """ Return the ID of the current request's user """ # This needs flask-login to be installed if not has_flask_login: return # and the actual login manager installed if not hasattr(current_app, 'login_manager'): return # fail if no current_user was attached to the request context try: is_authenticated = current_user.is_authenticated except AttributeError: return # because is_authenticated could be a callable, call it if callable(is_authenticated): is_authenticated = is_authenticated() # and fail if the user isn't authenticated if not is_authenticated: return # finally return the user id try: return current_user.get_id() except UserLoadingError: # but don't fail if for some reason getting the user id # created an exception to not accidently make exception # handling worse. If sqlalchemy is used that catches # all SQLAlchemyError exceptions. pass def summary_extra(self): """ Build the extra data for the summary logger. """ out = { 'errno': 0, 'agent': request.headers.get('User-Agent', ''), 'lang': request.headers.get('Accept-Language', ''), 'method': request.method, 'path': request.path, } # set the uid value to the current user ID user_id = self.user_id() if user_id is None: user_id = '' out['uid'] = user_id # the rid value to the current request ID request_id = g.get('_request_id', None) if request_id is not None: out['rid'] = request_id # and the t value to the time it took to render start_timestamp = g.get('_start_timestamp', None) if start_timestamp is not None: # Duration of request, in milliseconds. out['t'] = int(1000 * (time.time() - start_timestamp)) return out def _version_view(self): """ View that returns the contents of version.json or a 404. """ version_json = self._version_callback(self.version_path) if version_json is None: return 'version.json not found', 404 else: return jsonify(version_json) def _lbheartbeat_view(self): """ Lets the load balancer know the application is running and available. Must return 200 (not 204) for ELB http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-healthchecks.html """ return '', 200 def _heartbeat_check_detail(self, check): errors = list( filter(lambda e: e.id not in self.silenced_checks, check())) level = max([0] + [e.level for e in errors]) return { 'status': checks.level_to_text(level), 'level': level, 'messages': {e.id: e.msg for e in errors}, } def _heartbeat_view(self): """ Runs all the registered checks and returns a JSON response with either a status code of 200 or 500 depending on the results of the checks. Any check that returns a warning or worse (error, critical) will return a 500 response. """ details = {} statuses = {} level = 0 for name, check in self.checks.items(): detail = self._heartbeat_check_detail(check) statuses[name] = detail['status'] level = max(level, detail['level']) if detail['level'] > 0: details[name] = detail payload = { 'status': checks.level_to_text(level), 'checks': statuses, 'details': details, } def render(status_code): return make_response(jsonify(payload), status_code) if level < checks.WARNING: status_code = 200 heartbeat_passed.send(self, level=level) return render(status_code) else: status_code = 500 heartbeat_failed.send(self, level=level) raise HeartbeatFailure(response=render(status_code)) def version_callback(self, func): """ A decorator to optionally register a new Dockerflow version callback and use that instead of the default of :func:`dockerflow.version.get_version`. The callback will be passed the value of the ``version_path`` parameter to the Dockerflow extension object, which defaults to the parent directory of the Flask app's root path. The callback should return a dictionary with the version information as defined in the Dockerflow spec, or None if no version information could be loaded. E.g.:: app = Flask(__name__) dockerflow = Dockerflow(app) @dockerflow.version_callback def my_version(root): return json.loads(os.path.join(root, 'acme_version.json')) """ self._version_callback = func def check(self, func=None, name=None): """ A decorator to register a new Dockerflow check to be run when the /__heartbeat__ endpoint is called., e.g.:: from dockerflow.flask import checks @dockerflow.check def storage_reachable(): try: acme.storage.ping() except SlowConnectionException as exc: return [checks.Warning(exc.msg, id='acme.health.0002')] except StorageException as exc: return [checks.Error(exc.msg, id='acme.health.0001')] or using a custom name:: @dockerflow.check(name='acme-storage-check) def storage_reachable(): # ... """ if func is None: return functools.partial(self.check, name=name) if name is None: name = func.__name__ self.logger.info('Registered Dockerflow check %s', name) @functools.wraps(func) def decorated_function(*args, **kwargs): self.logger.info('Called Dockerflow check %s', name) return func(*args, **kwargs) self.checks[name] = decorated_function return decorated_function
def create_blueprint(endpoints): """Create Invenio-Records-REST blueprint. :params endpoints: Dictionary representing the endpoints configuration. :returns: Configured blueprint. """ endpoints = endpoints or {} blueprint = Blueprint( 'reroils_record_editor', __name__, template_folder='templates', static_folder='static', url_prefix='/editor', ) rec_types = endpoints.keys() blueprint.add_app_template_filter(can_edit) blueprint.add_app_template_filter(jsondumps) blueprint.register_error_handler(PermissionDenied, permission_denied_page) menu_func = partial(init_menu, endpoints=endpoints) menu_func.__module__ = init_menu.__module__ menu_func.__name__ = init_menu.__name__ blueprint.before_app_request(menu_func) for rec_type in rec_types: # search view if endpoints.get(rec_type, {}).get('api'): search_func = partial(search, record_type=rec_type, endpoints=endpoints) search_func.__module__ = search.__module__ search_func.__name__ = search.__name__ blueprint.add_url_rule('/search/%s' % rec_type, endpoint='search_%s' % rec_type, view_func=search_func) # create view create_func = partial(create, record_type=rec_type, endpoints=endpoints) create_func.__module__ = create.__module__ create_func.__name__ = create.__name__ blueprint.add_url_rule('/create/%s' % rec_type, endpoint='create_%s' % rec_type, view_func=create_func) # update view update_func = partial(update, record_type=rec_type, endpoints=endpoints) update_func.__module__ = update.__module__ update_func.__name__ = update.__name__ blueprint.add_url_rule('/update/%s/<int:pid>' % rec_type, endpoint='update_%s' % rec_type, view_func=update_func) # delete view delete_func = partial(delete, record_type=rec_type, endpoints=endpoints) delete_func.__module__ = delete.__module__ delete_func.__name__ = delete.__name__ blueprint.add_url_rule('/delete/%s/<int:pid>' % rec_type, endpoint='delete_%s' % rec_type, view_func=delete_func) # save api save_func = partial(save, record_type=rec_type, endpoints=endpoints) save_func.__module__ = save.__module__ save_func.__name__ = save.__name__ blueprint.add_url_rule('/save/%s' % rec_type, endpoint='save_%s' % rec_type, view_func=save_func, methods=['POST']) return blueprint
from flask import Blueprint from fibonacci.fib.log_request import log_request fib = Blueprint('fib', __name__) fib.before_app_request(log_request) from . import views
from flask import Blueprint, g, session from .article_api_bp import routes as article_routes from .session_api_bp import routes as session_routes from .user_api_bp import load_logged_in_user, routes as user_routes bp = Blueprint('api', __name__) routes = (article_routes + session_routes + user_routes) def tear_down_function(e=None): # print('teardown!!!!!!') g.db.session.close() close_db() for r in routes: bp.add_url_rule(r['rule'], r.get('endpoint', None), view_func=r['view_func'], **r.get('options', {})) bp.before_app_request(load_logged_in_user) # bp.teardown_app_request(tear_down_function)
blueprint = Blueprint('middleware', __name__) # So here we can do something before every request or after. Depending on our needs. # E.g. we can authenticate every request here. class Middleware: def __init__(self): self.logger = logging.getLogger(__name__) @staticmethod @blueprint.before_app_request def do_something_before_a_request(): logger = logging.getLogger(__name__) auth = request.headers.get('Authorization') if auth == 'no_valid_user': logger.info('User not authorized') return Response(json.dumps({'message': 'Unauthorized'}), status=401, mimetype='application/json') def do_something_else_before_a_request(self): auth = request.headers.get('Authorization') self.logger.info(f'Got auth {auth}') # Almost the same here as in the handlers. middleware = Middleware() blueprint.before_app_request(middleware.do_something_else_before_a_request)
main_static_folder = base_dir + '/app/static' main_template_folder = base_dir + '/app/templates' app_file_template_folder = base_dir + '/AppFiles' main = Blueprint('main', __name__, static_folder=main_static_folder, template_folder=main_template_folder) auth = Blueprint('auth', __name__) app_file = Blueprint('app_file', __name__, static_folder=app_file_template_folder) # main.before_app_first_request(before_app_first_request) main.before_app_request(before_app_request) main.before_request(before_request) @main.after_request def after_request(response): print('*' * 20 + who_am_i() + ' start' + '*' * 20) print(request) print(response) print(response.status) print(response.headers) print(response.get_data()) print('*' * 20 + who_am_i() + ' end' + '*' * 20) return response
# -*- coding:utf-8 -*- # ************************************************************************* # Copyright © 2016 Godinsec. All rights reserved. # File Name: urls.py # Author: Allan # Mail: [email protected] # Created Time: 16/9/21 # # ************************************************************************* from flask import Blueprint from .views import get_captcha, login, logout, change_password, unconfirmed,\ before_request, confirm, resend_confirmation, forbidden_page, active_request auth = Blueprint('auth', __name__, static_folder='static', template_folder='templates') auth.before_app_request(before_request) auth.add_url_rule('/captcha', view_func=get_captcha) auth.add_url_rule('/login', view_func=login, methods=['GET', 'POST']) auth.add_url_rule('/change_password', view_func=change_password, methods=['GET', 'POST']) auth.add_url_rule('/logout', view_func=logout) auth.add_url_rule('/confirm/<token>', view_func=confirm) auth.add_url_rule('/confirm', view_func=resend_confirmation) auth.add_url_rule('/unconfirmed', view_func=unconfirmed) auth.add_url_rule('/forbidden/<int:req_active>', view_func=forbidden_page) auth.add_url_rule('/active', view_func=active_request)