Add content negotiation related route decorators

This commit is contained in:
Patrick Jentsch 2023-03-06 15:02:46 +01:00
parent 8a55ce902e
commit 4fb5f2f2dc

View File

@ -1,7 +1,9 @@
from flask import abort, current_app from flask import abort, current_app, request
from flask_login import current_user from flask_login import current_user
from functools import wraps from functools import wraps
from threading import Thread from threading import Thread
from typing import List, Union
from werkzeug.exceptions import NotAcceptable
from app.models import Permission from app.models import Permission
@ -61,3 +63,55 @@ def background(f):
thread.start() thread.start()
return thread return thread
return wrapped return wrapped
def consumes(mime_type: str, *_mime_types: str):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
provided = request.mimetype
consumeables = {mime_type, *_mime_types}
if provided not in consumeables:
raise NotAcceptable()
return f(*args, **kwargs)
return decorated_function
return decorator
def produces(mime_type: str, *_mime_types: str):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
accepted = {*request.accept_mimetypes.values()}
produceables = {mime_type, *_mime_types}
if len(produceables & accepted) == 0:
raise NotAcceptable()
return f(*args, **kwargs)
return decorated_function
return decorator
def content_negotiation(
produces: Union[str, List[str]],
consumes: Union[str, List[str]]
):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
provided = request.mimetype
if isinstance(consumes, str):
consumeables = {consumes}
else:
consumeables = {*consumes}
accepted = {*request.accept_mimetypes.values()}
if isinstance(produces, str):
produceables = {produces}
else:
produceables = {*produces}
if len(produceables & accepted) == 0:
raise NotAcceptable()
if provided not in consumeables:
raise NotAcceptable()
return f(*args, **kwargs)
return decorated_function
return decorator