Passed
Push — master ( 1d7190...d4949b )
by Mingyu
01:54 queued 32s
created

app.views.after_request()   A

Complexity

Conditions 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
rs 9.4285
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, request
6
from flask_restful import Resource, abort
7
8
9
def after_request(response):
10
    """
11
    Set header - X-Content-Type-Options=nosniff, X-Frame-Options=deny before response
12
    """
13
    response.headers['X-Content-Type-Options'] = 'nosniff'
14
    response.headers['X-Frame-Options'] = 'deny'
15
16
    return response
17
18
19
def auth_required(fn):
20
    """
21
    View decorator for access control.
22
23
    ### TODO
24
    If you want to access control easily with this decorator,
25
    fill 'wrapper()' function included (1) aborting when access denied client (2) Set user object to flask.g
26
27
    - About custom view decorator
28
    -> http://flask-docs-kr.readthedocs.io/ko/latest/patterns/viewdecorators.html
29
    """
30
    @wraps(fn)
31
    def wrapper(*args, **kwargs):
32
        return fn(*args, **kwargs)
33
34
    return wrapper
35
36
37
def json_required(*required_keys):
38
    """
39
    View decorator for JSON validation.
40
41
    - If content-type is not application/json : returns status code 406
42
    - If required_keys are not exist on request.json : returns status code 400
43
44
    :type required_keys: str
45
    """
46
    def decorator(fn):
47
        if fn.__name__ == 'get':
48
            print('[WARN] JSON with GET method? on "{}()"'.format(fn.__qualname__))
49
50
        @wraps(fn)
51
        def wrapper(*args, **kwargs):
52
            if not request.is_json:
53
                abort(406)
54
55
            for required_key in required_keys:
56
                if required_key not in request.json:
57
                    abort(400)
58
59
            return fn(*args, **kwargs)
60
        return wrapper
61
    return decorator
62
63
64
class BaseResource(Resource):
65
    """
66
    BaseResource with some helper functions based flask_restful.Resource
67
    """
68
    def __init__(self):
69
        self.now = time.strftime('%Y-%m-%d %H:%M:%S')
70
71
    @classmethod
72
    def unicode_safe_json_dumps(cls, data, status_code=200, **kwargs):
73
        """
74
        Helper function which processes json response with unicode using ujson
75
76
        :type data: dict or list
77
        :type status_code: int
78
79
        :rtype: Response
80
        """
81
        return Response(
82
            ujson.dumps(data, ensure_ascii=False),
83
            status_code,
84
            content_type='application/json; charset=utf8',
85
            **kwargs
86
        )
87
88
89
class Router(object):
90
    """
91
    REST resource routing helper class like standard flask 3-rd party libraries
92
    """
93
    def __init__(self, app=None):
94
        if app is not None:
95
            self.init_app(app)
96
97
    def init_app(self, app):
98
        """
99
        Routes resources. Use app.register_blueprint() aggressively
100
        """
101
        app.after_request(after_request)
102
103
        from app.views import sample
104
        app.register_blueprint(sample.api.blueprint)
105