Source code for luna_admin.crutches_on_wheels.web.docs_handler
# -*- coding: utf-8 -*-
"""Document File Handler
Module realizes doc file handler.
"""
from typing import Optional, Tuple
from sanic import response
from sanic.response import HTTPResponse
from ..constants.paths import STATIC_ROOT
from ..errors.errors import Error
from ..errors.exception import VLException
from ..web.handlers import BaseHandler
from .application import LunaApplication
[docs]class SpecDocumentsHandler(BaseHandler):
"""
Handler for getting openapi documentations from static directory
"""
#: (str): custom document name (used in luna-matcher-proxy service)
_docName: Optional[str] = None
@property
def app(self) -> LunaApplication:
"""
Get application
Returns:
running application
"""
return self.request.app
@property
def config(self):
"""
Get running application config
Returns:
running application config
"""
return self.request.app.ctx.serviceConfig
@property
def docName(self):
"""
Current REST API document name getter.
Returns:
REST API document name except extension
"""
if self._docName is None:
return self.request.app.name
return self._docName
[docs] @classmethod
def customise(cls, docName: Optional[str] = None):
"""
Handler customising method.
Args:
docName: document name to store
Returns:
the current handler class
"""
if docName is not None:
cls._docName = docName
return cls
[docs] def getDataFromStatic(self, extension: str) -> Tuple[str, bytes]:
"""
Get file body from a static directory with the specified extension
Args:
extension: extension for document file (html or yml)
Returns:
tuple (filename, document body)
"""
if STATIC_ROOT.exists():
for posixPath in STATIC_ROOT.iterdir():
if self.docName + extension == posixPath.name:
data = posixPath.read_bytes()
return posixPath.name, data
raise VLException(Error.DocumentNotFoundError, 500, isCriticalError=False)
raise VLException(Error.StaticNotFoundError, 500, isCriticalError=False)
[docs] async def get(self) -> HTTPResponse: # pylint: disable-msg=W0221
"""
Get document of services, see `get spec docs`_.
.. _get spec docs:
_static/api.html#operation/getSpec
Resource is reached by address '/docs/spec'
Raises:
VLException(Error.UnsupportedMediaType, 415, isCriticalError=False), if "Accept" header is incorrect
"""
acceptHeaders = self.request.headers.get("Accept", "text/html").split(",")
if "text/html" in acceptHeaders:
contentType, extensionFile = "text/html", ".html"
elif "application/x-yaml" in acceptHeaders:
contentType, extensionFile = "application/x-yaml", ".yml"
# Remove RAML extension when all services will use OpenApi
if self.request.app.name in ("luna-index-manager",):
extensionFile = ".raml"
else:
raise VLException(Error.UnsupportedMediaType, 415, isCriticalError=False)
filename, fileBody = self.getDataFromStatic(extensionFile)
return self.success(
body=fileBody,
extraHeaders={"Content-Disposition": f"inline; filename={filename}"},
contentType=contentType,
)
[docs]class DevelopmentManualHandler(BaseHandler):
"""
Handler for getting sphinx documentations from static directory
"""
@property
def app(self) -> LunaApplication:
"""
Get application
Returns:
running application
"""
return self.request.app
@property
def config(self):
"""
Get running application config
Returns:
running application config
"""
return self.request.app.ctx.serviceConfig
[docs] async def get(self): # pylint: disable-msg=W0221
"""
Get `Sphinx` service documentation, see `get dev manual`_.
.. _get dev manual:
_static/api.html#operation/getDevManual
Resource is reached by address '/docs/dev'
"""
apiVersion = self.request.app.ctx.apiVersion
return response.redirect(f"/{apiVersion}/docs/dev/index.html")
[docs]def addDocHandlersRoutes(app: LunaApplication, specDocName: Optional[str] = None):
"""
Add standard docs handlers (OpenAPI and sphinx) to app
Args:
app: application
specDocName: custom spec doc name
"""
app.add_route(DevelopmentManualHandler.as_view(), rf"/{app.ctx.apiVersion}/docs/dev", strict_slashes=True)
app.add_route(DevelopmentManualHandler.as_view(), rf"/{app.ctx.apiVersion}/docs/dev/", strict_slashes=True)
app.static(rf"/{app.ctx.apiVersion}/docs/dev", STATIC_ROOT / "sphinx", strict_slashes=False)
SpecDocumentsHandler.customise(specDocName)
app.add_route(SpecDocumentsHandler.as_view(), rf"/{app.ctx.apiVersion}/docs/spec", strict_slashes=False)