Passed
Push — master ( 35a645...4815b0 )
by Mingyu
01:13
created

app.views.exception_handler()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
from functools import wraps
2
import ujson
3
import time
4
5
from flask import Response, abort, g, request
6
from flask_jwt_extended import jwt_required, get_jwt_identity
7
from flask_restful import Resource
8
9
10
def after_request(response):
11
    """
12
    Set header - X-Content-Type-Options=nosniff, X-Frame-Options=deny before response
13
    """
14
    response.headers['X-Content-Type-Options'] = 'nosniff'
15
    response.headers['X-Frame-Options'] = 'deny'
16
17
    return response
18
19
20
def exception_handler(e):
21
    # TODO
22
23
    return '', 500
24
25
26
def auth_required(model):
27
    def decorator(fn):
28
        """
29
        View decorator for access control
30
        """
31
        @wraps(fn)
32
        @jwt_required
33
        def wrapper(*args, **kwargs):
34
            user = model.objects(id=get_jwt_identity()).first()
35
            if not user:
36
                abort(403)
37
38
            g.user = user
39
40
            return fn(*args, **kwargs)
41
        return wrapper
42
    return decorator
43
44
45
def json_required(*required_keys):
46
    """
47
    View decorator for JSON validation.
48
49
    - If content-type is not application/json : returns status code 406
50
    - If required_keys are not exist on request.json : returns status code 400
51
52
    Args:
53
        *required_keys: Required keys on requested JSON payload
54
    """
55
    def decorator(fn):
56
        if fn.__name__ == 'get':
57
            print('[WARN] JSON with GET method? on "{}()"'.format(fn.__qualname__))
58
59
        @wraps(fn)
60
        def wrapper(*args, **kwargs):
61
            if not request.is_json:
62
                abort(406)
63
64
            for required_key in required_keys:
65
                if required_key not in request.json:
66
                    abort(400)
67
68
            return fn(*args, **kwargs)
69
        return wrapper
70
    return decorator
71
72
73
class BaseResource(Resource):
74
    """
75
    BaseResource with some helper functions based flask_restful.Resource
76
    """
77
    def __init__(self):
78
        self.now = time.strftime('%Y-%m-%d %H:%M:%S')
79
80
    @classmethod
81
    def unicode_safe_json_dumps(cls, data, status_code=200, **kwargs) -> Response:
82
        """
83
        Helper function which processes json response with unicode using ujson
84
85
        Args:
86
            data (dict or list): Data for dump to JSON
87
            status_code (int): Status code for response
88
        """
89
        return Response(
90
            ujson.dumps(data, ensure_ascii=False),
91
            status_code,
92
            content_type='application/json; charset=utf8',
93
            **kwargs
94
        )
95
96
97
class Router:
98
    """
99
    REST resource routing helper class like standard flask 3-rd party libraries
100
    """
101
    def __init__(self, app=None):
102
        if app is not None:
103
            self.init_app(app)
104
105
    def init_app(self, app):
106
        """
107
        Routes resources. Use app.register_blueprint() aggressively
108
        """
109
        app.after_request(after_request)
110
        app.register_error_handler(Exception, exception_handler)
111
112
        from app.views import sample
113
        app.register_blueprint(sample.api.blueprint)
114