def required(self, price, **kwargs):
"""API route decorator to request payment for a resource.
This function stores the resource price in a closure. It will verify
the validity of a payment, and allow access to the resource if the
payment is successfully accepted.
"""
def decorator(fn):
"""Validates payment and returns the original API route."""
@wraps(fn)
def _fn(*fn_args, **fn_kwargs):
# Calculate resource cost
nonlocal price
_price = price(request, *fn_args, **fn_kwargs) if callable(price) else price
# Need better way to pass server url to payment methods (FIXME)
if 'server_url' not in kwargs:
url = urlparse(request.url_root)
kwargs.update({'server_url': url.scheme + '://' + url.netloc})
# Continue to the API view if payment is valid or price is 0
if _price == 0:
return fn(*fn_args, **fn_kwargs)
try:
contains_payment = self.contains_payment(_price, request.headers, **kwargs)
except BadRequest as e:
return Response(e.description, BAD_REQUEST)
if contains_payment:
return fn(*fn_args, **fn_kwargs)
else:
# Get headers for initial 402 response
payment_headers = {}
for method in self.allowed_methods:
payment_headers.update(method.get_402_headers(_price, **kwargs))
# Accessing the .files attribute of a request
# drains the input stream.
request.files
raise PaymentRequiredException(payment_headers)
return _fn
return decorator
评论列表
文章目录