Passed
Push — master ( f9d80a...526772 )
by Mingyu
01:39
created

app.views.route()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
from functools import wraps
2
import json
3
import gzip
4
import time
5
6
from flask import Response, abort, after_this_request, g, jsonify, request
7
from flask_jwt_extended import jwt_required, get_jwt_identity
8
from flask_restful import Resource
9
from werkzeug.exceptions import HTTPException
10
11
12
def after_request(response):
13
    response.headers['X-Content-Type-Options'] = 'nosniff'
14
    response.headers['X-Frame-Options'] = 'deny'
15
16
    return response
17
18
19
def exception_handler(e):
20
    print(e)
21
22
    if isinstance(e, HTTPException):
23
        description = e.description
24
        code = e.code
25
    elif isinstance(e, BaseResource.ValidationError):
26
        description = e.description
27
        code = 400
28
    else:
29
        description = ''
30
        code = 500
31
32
    return jsonify({
33
        'msg': description
34
    }), code
35
36
37
def gzipped(fn):
38
    @wraps(fn)
39
    def wrapper(*args, **kwargs):
40
        @after_this_request
41
        def zipper(response):
42
            if 'gzip' not in request.headers.get('Accept-Encoding', '')\
43
                    or not 200 <= response.status_code < 300\
44
                    or 'Content-Encoding' in response.headers:
45
                # 1. Accept-Encoding에 gzip이 포함되어 있지 않거나
46
                # 2. 200번대의 status code로 response하지 않거나
47
                # 3. response header에 이미 Content-Encoding이 명시되어 있는 경우
48
                return response
49
50
            response.data = gzip.compress(response.data)
51
            response.headers.update({
52
                'Content-Encoding': 'gzip',
53
                'Vary': 'Accept-Encoding',
54
                'Content-Length': len(response.data)
55
            })
56
57
            return response
58
        return fn(*args, **kwargs)
59
    return wrapper
60
61
62
def auth_required(model):
63
    def decorator(fn):
64
        @wraps(fn)
65
        @jwt_required
66
        def wrapper(*args, **kwargs):
67
            raise NotImplementedError()
68
69
            # return fn(*args, **kwargs)
70
        return wrapper
71
    return decorator
72
73
74
def json_required(required_keys, check_blank_str=True):
75
    def decorator(fn):
76
        if fn.__name__ == 'get':
77
            print('[WARN] JSON with GET method? on "{}()"'.format(fn.__qualname__))
78
79
        @wraps(fn)
80
        def wrapper(*args, **kwargs):
81
            if not request.is_json:
82
                abort(406)
83
84
            for key, typ in required_keys.items():
85
                if key not in request.json or type(request.json[key]) is not typ:
86
                    abort(400)
87
                if check_blank_str and typ is str and not request.json[key]:
88
                    abort(400)
89
90
            return fn(*args, **kwargs)
91
        return wrapper
92
    return decorator
93
94
95
class BaseResource(Resource):
96
    def __init__(self):
97
        self.now = time.strftime('%Y-%m-%d %H:%M:%S')
98
99
    @classmethod
100
    def unicode_safe_json_dumps(cls, data, status_code=200, **kwargs) -> Response:
101
        return Response(
102
            json.dumps(data, ensure_ascii=False),
103
            status_code,
104
            content_type='application/json; charset=utf8',
105
            **kwargs
106
        )
107
108
    class ValidationError(Exception):
109
        def __init__(self, description='', *args):
110
            self.description = description
111
112
            super(BaseResource.ValidationError, self).__init__(*args)
113
114
115
def route(app):
116
    app.after_request(after_request)
117
    app.register_error_handler(Exception, exception_handler)
118
119
    from app.views import sample
120
    app.register_blueprint(sample.api.blueprint)
121