1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
# coding=utf-8
import os
from functools import wraps
from json import JSONDecodeError
from flask import request
from schema import Schema, SchemaError
from pysite.constants import ErrorCodes, ValidationTypes
def api_key(f):
"""
Decorator to check if X-API-Key is valid.
Should only be applied to functions on APIView routes.
"""
@wraps(f)
def inner(self, *args, **kwargs):
if not request.headers.get("X-API-Key") == os.environ.get("API_KEY"):
return self.error(ErrorCodes.invalid_api_key)
return f(self, *args, **kwargs)
return inner
def api_params(schema: Schema, validation_type: ValidationTypes = ValidationTypes.json):
"""
Validate parameters of data passed to the decorated view.
Should only be applied to functions on APIView routes.
This will pass the validated data in as the first parameter to the decorated function.
This data will always be a list, and view functions are expected to be able to handle that
in the case of multiple sets of data being provided by the api.
"""
def inner_decorator(f):
@wraps(f)
def inner(self, *args, **kwargs):
if validation_type == ValidationTypes.json:
try:
if not request.is_json:
return self.error(ErrorCodes.bad_data_format)
data = list(request.get_json())
except JSONDecodeError:
return self.error(ErrorCodes.bad_data_format)
elif validation_type == ValidationTypes.params:
# I really don't like this section here, but I can't think of a better way to do it
multi = request.args # This is a MultiDict, which should be flattened to a list of dicts
# We'll assume that there's always an equal number of values for each param
# Anything else doesn't really make sense anyway
data = []
longest = None
for key, items in multi.lists():
# Make sure every key has the same number of values
if longest is None:
# First iteration, store it
longest = len(items)
elif len(items) != longest:
# At least one key has a different number of values
return self.error(ErrorCodes.bad_data_format)
for i in range(longest): # Now we know all keys have the same number of values...
obj = {} # New dict to store this set of values
for key, items in multi.lists():
obj[key] = items[i] # Store the item at that specific index
data.append(obj)
else:
raise ValueError(f"Unknown validation type: {validation_type}")
try:
schema.validate(data)
except SchemaError:
return self.error(ErrorCodes.incorrect_parameters)
return f(self, data, *args, **kwargs)
return inner
return inner_decorator
|