From ad3e2a34b82e6d6d4c8ac4964a50166d8f565b64 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Mon, 7 Sep 2020 16:07:35 +0200 Subject: [PATCH] Added route for getting API version and installed plugins + some cleanup --- flaschengeist/__init__.py | 67 +------------------------------ flaschengeist/app.py | 84 +++++++++++++++++++++++++++++++++++++++ run_flaschengeist | 2 +- setup.py | 52 ++++++++++++------------ 4 files changed, 114 insertions(+), 91 deletions(-) create mode 100644 flaschengeist/app.py diff --git a/flaschengeist/__init__.py b/flaschengeist/__init__.py index 7e5dd23..7882802 100644 --- a/flaschengeist/__init__.py +++ b/flaschengeist/__init__.py @@ -7,78 +7,15 @@ import yaml import logging import pkg_resources -from flask import Flask from pathlib import Path - -from flask.json import JSONEncoder, jsonify -from flask_cors import CORS from logging.config import dictConfig - -from werkzeug.exceptions import HTTPException from werkzeug.local import LocalProxy _module_path = Path(__file__).parent logger = LocalProxy(lambda: logging.getLogger(__name__)) +__version__ = pkg_resources.get_distribution('flaschengeist').version + with (_module_path / 'logging.yml').open(mode='rb') as file: config = yaml.safe_load(file.read()) logging.config.dictConfig(config) - - -class CustomJSONEncoder(JSONEncoder): - def default(self, o): - # Check if custom model - try: - return o.serialize() - except AttributeError: - pass - - # Check if iterable - try: - iterable = iter(o) - except TypeError: - pass - else: - return list(iterable) - return JSONEncoder.default(self, o) - - -def create_app(): - app = Flask(__name__) - app.json_encoder = CustomJSONEncoder - CORS(app) - - with app.app_context(): - from .system.database import db - from .system.config import configure_app, config - configure_app(app) - db.init_app(app) - - for entry_point in pkg_resources.iter_entry_points('flaschengeist.auth'): - logger.debug('Found authentication plugin: %s', entry_point.name) - if entry_point.name == config['FLASCHENGEIST']['AUTH']: - app.config['FG_AUTH_BACKEND'] = entry_point.load()() - app.config['FG_AUTH_BACKEND'].configure( - config[entry_point.name] if config.has_section(entry_point.name) else {}) - logger.info('Loaded authentication plugin > %s <', entry_point.name) - break - if not app.config['FG_AUTH_BACKEND']: - logger.error('No authentication plugin configured or authentication plugin not found') - - logger.info('Search for plugins') - for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin'): - logger.debug("Found plugin: %s", entry_point.name) - if config.get(entry_point.name, 'enabled', fallback=False): - logger.info("Loaded plugin >{}<".format(entry_point.name)) - app.register_blueprint(entry_point.load()()) - - @app.errorhandler(Exception) - def handle_exception(e): - if isinstance(e, HTTPException): - logger.debug(e.description, exc_info=True) - return jsonify({"error": e.name}), e.code - - logger.error(str(e), exc_info=True) - return jsonify({"error": "Internal server error occurred"}), 500 - - return app diff --git a/flaschengeist/app.py b/flaschengeist/app.py new file mode 100644 index 0000000..a4103ae --- /dev/null +++ b/flaschengeist/app.py @@ -0,0 +1,84 @@ +from datetime import datetime + +import pkg_resources +from flask import Flask +from flask.json import JSONEncoder, jsonify +from flask_cors import CORS +from werkzeug.exceptions import HTTPException + +from . import logger +from .system.config import config, configure_app + + +class CustomJSONEncoder(JSONEncoder): + def default(self, o): + # Check if custom model + try: + return o.serialize() + except AttributeError: + pass + + if isinstance(o, datetime): + return o.isoformat() + # Check if iterable + try: + iterable = iter(o) + except TypeError: + pass + else: + return list(iterable) + return JSONEncoder.default(self, o) + + +def __load_auth(app): + for entry_point in pkg_resources.iter_entry_points('flaschengeist.auth'): + logger.debug('Found authentication plugin: %s', entry_point.name) + if entry_point.name == config['FLASCHENGEIST']['AUTH']: + app.config['FG_AUTH_BACKEND'] = entry_point.load()() + app.config['FG_AUTH_BACKEND'].configure( + config[entry_point.name] if config.has_section(entry_point.name) else {}) + logger.info('Loaded authentication plugin > %s <', entry_point.name) + break + if not app.config['FG_AUTH_BACKEND']: + logger.error('No authentication plugin configured or authentication plugin not found') + + +def __load_plugins(app): + logger.info('Search for plugins') + app.config['FG_PLUGINS'] = {} + for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin'): + logger.debug("Found plugin: >{}<".format(entry_point.name)) + if config.get(entry_point.name, 'enabled', fallback=False): + logger.info("Loaded plugin >{}<".format(entry_point.name)) + app.config["FG_PLUGINS"][entry_point.name] = True + app.register_blueprint(entry_point.load()()) + else: + app.config["FG_PLUGINS"][entry_point.name] = False + + +def create_app(): + app = Flask(__name__) + app.json_encoder = CustomJSONEncoder + CORS(app) + + with app.app_context(): + from .system.database import db + configure_app(app) + db.init_app(app) + __load_auth(app) + __load_plugins(app) + + @app.route("/", methods=["GET"]) + def __get_state(): + from . import __version__ as version + return jsonify({"plugins": app.config["FG_PLUGINS"], "version": version}) + + @app.errorhandler(Exception) + def handle_exception(e): + if isinstance(e, HTTPException): + logger.debug(e.description, exc_info=True) + return jsonify({"error": e.description}), e.code + logger.error(str(e), exc_info=True) + return jsonify({"error": "Internal server error occurred"}), 500 + + return app diff --git a/run_flaschengeist b/run_flaschengeist index 6a89775..1636efd 100644 --- a/run_flaschengeist +++ b/run_flaschengeist @@ -1,5 +1,5 @@ #!/usr/bin/python3 -from flaschengeist import create_app +from flaschengeist.app import create_app import bjoern import argparse diff --git a/setup.py b/setup.py index 7f2e559..23b76be 100644 --- a/setup.py +++ b/setup.py @@ -1,32 +1,34 @@ from setuptools import setup, find_packages setup( - name='flaschengeist', - version='0.0.1', - url='https://wu5.de/redmine/projects/geruecht', - author='WU5 + Friends', - author_email='tim@groeger-clan.de', - description='Does things', + name="flaschengeist", + version="2.0.0-dev", + url="https://wu5.de/redmine/projects/geruecht", + author="WU5 + Friends", + author_email="tim@groeger-clan.de", + description="Does things", packages=find_packages(), - package_data={'': ['*.yml']}, - scripts=['run_flaschengeist'], - install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", - "flask_cors", "werkzeug", "bjoern"], - extras_require={ - 'ldap': [ - 'flask_ldapconn', - 'ldap3' - ] - }, + package_data={"": ["*.yml"]}, + scripts=["run_flaschengeist"], + install_requires=[ + "Flask >= 1.1", + "PyYAML>=5.3.1", + "sqlalchemy>=1.3", + "flask_sqlalchemy", + "flask_cors", + "werkzeug", + "bjoern", + ], + extras_require={"ldap": ["flask_ldapconn", "ldap3"]}, entry_points={ - 'flaschengeist.plugin': [ - 'auth = flaschengeist.modules.auth:register', - 'users = flaschengeist.modules.users:register', - 'schedule = flaschengeist.modules.schedule:register' + "flaschengeist.plugin": [ + "auth = flaschengeist.modules.auth:register", + "users = flaschengeist.modules.users:register", + "schedule = flaschengeist.modules.schedule:register", ], - 'flaschengeist.auth': [ - 'auth_plain = flaschengeist.modules.auth_plain:AuthPlain', - 'auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]' - ] - } + "flaschengeist.auth": [ + "auth_plain = flaschengeist.modules.auth_plain:AuthPlain", + "auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]", + ], + }, )