Passed
Push — master ( 0e0c01...f9d80a )
by Mingyu
01:53
created

app.views   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 24
eloc 91
dl 0
loc 127
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A BaseResource.__init__() 0 2 1
A Router.__init__() 0 3 2
A Router.init_app() 0 6 1
A BaseResource.unicode_safe_json_dumps() 0 7 1

5 Functions

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