diff --git a/imagemonk/_server.py b/imagemonk/_server.py new file mode 100644 index 0000000..c003f94 --- /dev/null +++ b/imagemonk/_server.py @@ -0,0 +1,53 @@ +import flask + +from imagemonk import __about__ +from imagemonk import configuration +from imagemonk import constants +from imagemonk import database +from imagemonk import exceptions +from imagemonk.resources import ResponseHeaders + + +def make_the_tea() -> None: + """Just for fun + https://en.wikipedia.org/wiki/Hyper_Text_Coffee_Pot_Control_Protocol + """ + if flask.request.content_type == "message/coffeepot": + raise exceptions.IAmATeapotError( + f"Coffee brewing request for '{flask.request.path}' cannot be completed by teapot application" + ) + + +def initialize_database() -> None: + """Initialize the database connection""" + database.initialize(flask.current_app.appconfig) + + +class ImageMonkRequest(flask.Request): + """Extend the default Flask request object to add custom application state settings""" + + def make_response_headers(self) -> ResponseHeaders: + """Create the headers dictionary of the standard response headers + + This function should be used when determining response headers so that the header names, + their contents, and formatting are universal. + + :returns: Dictionary of headers + """ + + return { + constants.HTTP_HEADER_RESPONSE_VERSION: __about__.__version__, + } + + +class ImageMonkFlask(flask.Flask): + """Extend the default Flask object to add the custom application config + + There's probably an easier/more kosher way to do this, but ¯\\_(ツ)_/¯ + """ + + request_class = ImageMonkRequest + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.appconfig: configuration.ImageMonkConfig = configuration.load() diff --git a/imagemonk/application.py b/imagemonk/application.py new file mode 100644 index 0000000..9454ade --- /dev/null +++ b/imagemonk/application.py @@ -0,0 +1,22 @@ +import flask_restful + +from imagemonk import resources +from imagemonk._server import ImageMonkFlask +from imagemonk._server import initialize_database +from imagemonk._server import make_the_tea + + +APPLICATION = ImageMonkFlask(__name__) +API = flask_restful.Api(APPLICATION, catch_all_404s=True) + + +def _set_upload_limit() -> None: + APPLICATION.config["MAX_CONTENT_LENGTH"] = APPLICATION.appconfig.upload.size_limit + + +APPLICATION.before_request(make_the_tea) +APPLICATION.before_first_request(initialize_database) +APPLICATION.before_first_request(_set_upload_limit) + +for resource in resources.RESOURCES: + API.add_resource(resource, *resource.routes) diff --git a/imagemonk/resources/__init__.py b/imagemonk/resources/__init__.py index 2dcc921..de54f85 100644 --- a/imagemonk/resources/__init__.py +++ b/imagemonk/resources/__init__.py @@ -1,6 +1,8 @@ from typing import Tuple from imagemonk.resources._shared import ImageMonkResource +from imagemonk.resources._shared import ResponseBody +from imagemonk.resources._shared import ResponseHeaders from imagemonk.resources.image import Image from imagemonk.resources.image import ImageUpload from imagemonk.resources.openapi import OpenAPI