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 Tuple, Optional
from sanic import response
from sanic.response import HTTPResponse
from .application import LunaApplication
from ..constants.paths import STATIC_ROOT
from ..errors.errors import Error
from ..errors.exception import VLException
from ..web.handlers import BaseHandler
[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)