From b6157f495396e0007dd4dd0143a769ae792339d2 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Thu, 3 Sep 2020 22:04:28 +0200 Subject: [PATCH] Added ErrorHandler for automatic Exception handling No need for try except for HTTP 500 or 403 error --- flaschengeist/__init__.py | 34 ++++++++++++++++++++++++++++- flaschengeist/system/decorator.py | 12 +++++----- flaschengeist/system/models/user.py | 8 +++---- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/flaschengeist/__init__.py b/flaschengeist/__init__.py index 56a8348..3b531c7 100644 --- a/flaschengeist/__init__.py +++ b/flaschengeist/__init__.py @@ -9,8 +9,12 @@ 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 @@ -21,8 +25,27 @@ with (_module_path / 'logging.yml').open(mode='rb') as file: 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(): @@ -49,4 +72,13 @@ def create_app(): logger.info('Loaded plugin > %s <', entry_point.name) app.register_blueprint(entry_point.load()()) - return app + @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 \ No newline at end of file diff --git a/flaschengeist/system/decorator.py b/flaschengeist/system/decorator.py index 3942cd8..930cf17 100644 --- a/flaschengeist/system/decorator.py +++ b/flaschengeist/system/decorator.py @@ -1,5 +1,7 @@ from functools import wraps from flask import request, jsonify +from werkzeug.exceptions import Unauthorized + from flaschengeist import logger @@ -15,15 +17,13 @@ def login_required(**kwargs): def wrapper(*args, **kwargs): token = request.headers.get('Token') logger.debug("token is {{ {} }}".format(token)) - access_token = ac_controller.validate_token(token, roles) - logger.debug("accToken is {{ {} }}".format(access_token)) - kwargs['accToken'] = access_token + access_token = ac_controller.validate_token(token, request.user_agent, roles) if access_token: + kwargs['access_token'] = access_token logger.debug("token {{ {} }} is valid".format(token)) return func(*args, **kwargs) else: - logger.warning("token {{ {} }} is not valid".format(token)) - return jsonify({"error": "error", - "message": "permission denied"}), 401 + logger.info("token {{ {} }} is not valid".format(token)) + raise Unauthorized return wrapper return real_decorator diff --git a/flaschengeist/system/models/user.py b/flaschengeist/system/models/user.py index c636be0..e028781 100644 --- a/flaschengeist/system/models/user.py +++ b/flaschengeist/system/models/user.py @@ -61,7 +61,7 @@ class User(db.Model): if 'display_name' in data: self.display_name = data['display_name'] - def default(self): + def serialize(self): return { # TODO: username should be UID? "username": self.uid, @@ -93,10 +93,8 @@ class Group(db.Model): name = db.Column(db.String(30)) permissions = db.relationship("Permission", secondary=group_permission_association_table) - def toJSON(self): - return { - 'name': self.name - } + def serialize(self): + return self.name class Permission(db.Model):