vdoc 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. vdoc/__init__.py +33 -0
  2. vdoc/api/__init__.py +96 -0
  3. vdoc/api/dependencies/__init__.py +1 -0
  4. vdoc/api/dependencies/auth.py +32 -0
  5. vdoc/api/routes/__init__.py +1 -0
  6. vdoc/api/routes/projects.py +71 -0
  7. vdoc/cli/__init__.py +1 -0
  8. vdoc/cli/main.py +84 -0
  9. vdoc/cli/run.py +30 -0
  10. vdoc/constants.py +11 -0
  11. vdoc/docs/_sources/index.rst.txt +20 -0
  12. vdoc/docs/_sources/license_compliance.rst.txt +1251 -0
  13. vdoc/docs/_sources/vdoc.api.dependencies.rst.txt +21 -0
  14. vdoc/docs/_sources/vdoc.api.routes.rst.txt +21 -0
  15. vdoc/docs/_sources/vdoc.api.rst.txt +19 -0
  16. vdoc/docs/_sources/vdoc.cli.rst.txt +29 -0
  17. vdoc/docs/_sources/vdoc.exceptions.rst.txt +10 -0
  18. vdoc/docs/_sources/vdoc.methods.api.rst.txt +21 -0
  19. vdoc/docs/_sources/vdoc.methods.cli.rst.txt +21 -0
  20. vdoc/docs/_sources/vdoc.methods.rst.txt +19 -0
  21. vdoc/docs/_sources/vdoc.models.rst.txt +21 -0
  22. vdoc/docs/_sources/vdoc.rst.txt +34 -0
  23. vdoc/docs/_sources/vdoc.settings.rst.txt +10 -0
  24. vdoc/docs/_static/0fc70aa4dfe4d16d7073.woff +0 -0
  25. vdoc/docs/_static/583e3f428bf2362b546d.woff +0 -0
  26. vdoc/docs/_static/5be6ec379613f10aea3f.woff +0 -0
  27. vdoc/docs/_static/76c1862325ea6f70eeff.woff2 +0 -0
  28. vdoc/docs/_static/83710c128240451d95af.woff +0 -0
  29. vdoc/docs/_static/a63d39a1c104a2b3e87e.woff2 +0 -0
  30. vdoc/docs/_static/awesome-docsearch.css +1 -0
  31. vdoc/docs/_static/awesome-docsearch.js +0 -0
  32. vdoc/docs/_static/awesome-sphinx-design.css +1 -0
  33. vdoc/docs/_static/awesome-sphinx-design.js +0 -0
  34. vdoc/docs/_static/b659956119f91f2342bc.woff2 +0 -0
  35. vdoc/docs/_static/basic.css +914 -0
  36. vdoc/docs/_static/bb50084be2b43ba7b98c.woff2 +0 -0
  37. vdoc/docs/_static/ce1e40901d7a0d88d483.woff2 +0 -0
  38. vdoc/docs/_static/custom.css +4 -0
  39. vdoc/docs/_static/d04352f240062b100fba.woff2 +0 -0
  40. vdoc/docs/_static/default/css/custom.css +138 -0
  41. vdoc/docs/_static/default/fonts/Roboto-Regular.ttf +0 -0
  42. vdoc/docs/_static/default/fonts/nb_architekt_r_neue_bold-webfont.ttf +0 -0
  43. vdoc/docs/_static/default/fonts/nb_architekt_r_neue_bold-webfont.woff2 +0 -0
  44. vdoc/docs/_static/default/icons/error-triangle-dark.png +0 -0
  45. vdoc/docs/_static/default/icons/error-triangle-white.png +0 -0
  46. vdoc/docs/_static/default/icons/note-circle-white.png +0 -0
  47. vdoc/docs/_static/default/logos/voraus_logo_small.svg +12 -0
  48. vdoc/docs/_static/doctools.js +149 -0
  49. vdoc/docs/_static/documentation_options.js +13 -0
  50. vdoc/docs/_static/f1cdf5c21de970ee0592.woff +0 -0
  51. vdoc/docs/_static/fd994e8d90d9cab651b0.woff +0 -0
  52. vdoc/docs/_static/file.png +0 -0
  53. vdoc/docs/_static/language_data.js +192 -0
  54. vdoc/docs/_static/minus.png +0 -0
  55. vdoc/docs/_static/plus.png +0 -0
  56. vdoc/docs/_static/pygments.css +75 -0
  57. vdoc/docs/_static/searchtools.js +632 -0
  58. vdoc/docs/_static/sphinx_highlight.js +154 -0
  59. vdoc/docs/_static/theme.css +9 -0
  60. vdoc/docs/_static/theme.js +2 -0
  61. vdoc/docs/_static/theme.js.LICENSE.txt +6 -0
  62. vdoc/docs/_static/voraus_logo_small.svg +12 -0
  63. vdoc/docs/genindex.html +569 -0
  64. vdoc/docs/index.html +302 -0
  65. vdoc/docs/license_compliance.html +2472 -0
  66. vdoc/docs/objects.inv +0 -0
  67. vdoc/docs/py-modindex.html +267 -0
  68. vdoc/docs/search.html +167 -0
  69. vdoc/docs/searchindex.js +1 -0
  70. vdoc/docs/vdoc.api.dependencies.html +181 -0
  71. vdoc/docs/vdoc.api.html +235 -0
  72. vdoc/docs/vdoc.api.routes.html +233 -0
  73. vdoc/docs/vdoc.cli.html +217 -0
  74. vdoc/docs/vdoc.exceptions.html +208 -0
  75. vdoc/docs/vdoc.html +282 -0
  76. vdoc/docs/vdoc.methods.api.html +244 -0
  77. vdoc/docs/vdoc.methods.cli.html +178 -0
  78. vdoc/docs/vdoc.methods.html +179 -0
  79. vdoc/docs/vdoc.models.html +261 -0
  80. vdoc/docs/vdoc.settings.html +184 -0
  81. vdoc/exceptions/__init__.py +69 -0
  82. vdoc/methods/__init__.py +1 -0
  83. vdoc/methods/api/__init__.py +1 -0
  84. vdoc/methods/api/projects.py +100 -0
  85. vdoc/methods/cli/__init__.py +1 -0
  86. vdoc/methods/cli/cli_run_method.py +20 -0
  87. vdoc/models/__init__.py +1 -0
  88. vdoc/models/project.py +120 -0
  89. vdoc/py.typed +0 -0
  90. vdoc/settings/__init__.py +26 -0
  91. vdoc/webapp/assets/index-CA36XZhf.js +673 -0
  92. vdoc/webapp/assets/index-CA36XZhf.js.gz +0 -0
  93. vdoc/webapp/assets/index-CA36XZhf.js.map +1 -0
  94. vdoc/webapp/assets/index.lazy-Bvif9CcS.js +2 -0
  95. vdoc/webapp/assets/index.lazy-Bvif9CcS.js.gz +0 -0
  96. vdoc/webapp/assets/index.lazy-Bvif9CcS.js.map +1 -0
  97. vdoc/webapp/assets/voraus-Ct0-dFDv.ico +0 -0
  98. vdoc/webapp/index.html +14 -0
  99. vdoc/webapp/index.html.gz +0 -0
  100. vdoc-0.1.0.dist-info/LICENSE.txt +21 -0
  101. vdoc-0.1.0.dist-info/METADATA +203 -0
  102. vdoc-0.1.0.dist-info/RECORD +105 -0
  103. vdoc-0.1.0.dist-info/WHEEL +5 -0
  104. vdoc-0.1.0.dist-info/entry_points.txt +2 -0
  105. vdoc-0.1.0.dist-info/top_level.txt +1 -0
vdoc/__init__.py ADDED
@@ -0,0 +1,33 @@
1
+ """Multi version documentation hosting."""
2
+
3
+ from importlib_metadata import PackageNotFoundError as _PackageNotFoundError
4
+ from importlib_metadata import version as _version
5
+
6
+ __module_name__ = "vdoc"
7
+
8
+ try: # pragma: no cover
9
+ __version__ = _version(__module_name__)
10
+ except _PackageNotFoundError as error: # pragma: no cover
11
+ raise ModuleNotFoundError(
12
+ f"Unable to determine version of package '{__module_name__}'. "
13
+ "If you are on a local development system, use 'pip install -e .[dev]' in order to install the package. "
14
+ "If you are on a productive system, this shouldn't happen. Please report a bug."
15
+ ) from error
16
+
17
+
18
+ def get_app_name() -> str:
19
+ """Returns the human-readable and prettified name of the application.
20
+
21
+ Returns:
22
+ The name of the application.
23
+ """
24
+ return __module_name__.replace("_", "-")
25
+
26
+
27
+ def get_app_version() -> str:
28
+ """Returns the version of the application.
29
+
30
+ Returns:
31
+ The version of the application.
32
+ """
33
+ return __version__
vdoc/api/__init__.py ADDED
@@ -0,0 +1,96 @@
1
+ """Contains the Rest API."""
2
+
3
+ from pathlib import Path
4
+
5
+ from fastapi import FastAPI
6
+ from fastapi.middleware.cors import CORSMiddleware
7
+ from fastapi.responses import JSONResponse
8
+ from fastapi.routing import Mount
9
+ from fastapi.staticfiles import StaticFiles
10
+ from starlette.requests import Request
11
+ from starlette.responses import FileResponse
12
+ from starlette.routing import BaseRoute
13
+
14
+ from vdoc.api.routes import projects as PROJECTS_MODULE
15
+ from vdoc.exceptions import VDocException
16
+ from vdoc.methods.api.projects import get_project_version_impl
17
+ from vdoc.settings import VDocSettings
18
+
19
+ _PACKAGE_PATH = Path(__file__).parent.parent
20
+
21
+ webapp_path = _PACKAGE_PATH / "webapp"
22
+ docs_path = _PACKAGE_PATH / "docs"
23
+
24
+ routes: list[BaseRoute] = [
25
+ Mount(
26
+ "/static/docs",
27
+ app=StaticFiles(directory=str(docs_path), html=True, check_dir=False),
28
+ name="vdoc-docs",
29
+ ),
30
+ Mount(
31
+ "/static/projects",
32
+ app=StaticFiles(directory=VDocSettings().docs_dir.as_posix(), html=True, check_dir=False),
33
+ name="projects",
34
+ ),
35
+ ]
36
+
37
+ app = FastAPI(docs_url="/apidoc")
38
+
39
+
40
+ app.add_middleware(
41
+ CORSMiddleware,
42
+ allow_origins=["*"],
43
+ allow_credentials=False,
44
+ allow_methods=["*"],
45
+ allow_headers=["*"],
46
+ )
47
+
48
+ app.include_router(PROJECTS_MODULE.router, prefix="/api")
49
+
50
+
51
+ @app.exception_handler(VDocException)
52
+ async def unicorn_exception_handler(_: Request, exc: VDocException) -> JSONResponse:
53
+ """Catches all ``VDocException`` exceptions and returns them as properly formatted JSONResponse.
54
+
55
+ Args:
56
+ exc: The catched exception.
57
+
58
+ Returns:
59
+ The exception as formatted JSONResponse.
60
+ """
61
+ return JSONResponse(status_code=exc.status_code, content={"message": exc.detail})
62
+
63
+
64
+ @app.get("/{project_name}/{version}/objects.inv")
65
+ def serve_sphinx_objects_inventory(project_name: str, version: str) -> FileResponse: # pylint: disable=unused-argument
66
+ """Serves the objects.inv sphinx file for intersphinx mappings.
67
+
68
+ Args:
69
+ project_name: The requested project name.
70
+ version: The requested project version.
71
+
72
+ Returns:
73
+ FileResponse: The objects.inv file.
74
+ """
75
+ served_version = get_project_version_impl(name=project_name, version=version)
76
+
77
+ return FileResponse(path=VDocSettings().docs_dir / project_name / served_version / "objects.inv")
78
+
79
+
80
+ for route in routes:
81
+ app.routes.append(route)
82
+
83
+
84
+ @app.get("/{file_path:path}")
85
+ def serve_ui_and_assets(file_path: str) -> FileResponse: # pylint: disable=unused-argument
86
+ """Serves the web UI and the static assets (JS bundles, ...) as a last fallback for all non-matched requests.
87
+
88
+ Args:
89
+ file_path (str): The requested file path.
90
+
91
+ Returns:
92
+ FileResponse: The requested asset file if existing, otherwise the index.html.
93
+ """
94
+ if (full_path := webapp_path / file_path).is_file():
95
+ return FileResponse(path=full_path)
96
+ return FileResponse(path=webapp_path / "index.html")
@@ -0,0 +1 @@
1
+ """Contains all FastAPI dependencies."""
@@ -0,0 +1,32 @@
1
+ """Contains all authentication dependencies."""
2
+
3
+ import secrets
4
+ from typing import Annotated
5
+
6
+ from fastapi import Depends
7
+ from fastapi.security import HTTPBasic, HTTPBasicCredentials
8
+
9
+ from vdoc.exceptions import InvalidCredentials
10
+ from vdoc.settings import VDocSettings
11
+
12
+ security = HTTPBasic()
13
+
14
+
15
+ def require_authentication(credentials: Annotated[HTTPBasicCredentials, Depends(security)]) -> bool:
16
+ """FastAPI dependency that checks for HTTP Basic Auth credentials in the request header.
17
+
18
+ Args:
19
+ credentials: The HTTPBasicAuth credentials sent with the request heder.
20
+
21
+ Raises:
22
+ HTTPException: If the credentials are not valid.
23
+
24
+ Returns:
25
+ True if the request is authenticated.
26
+ """
27
+ settings = VDocSettings()
28
+ is_correct_username = secrets.compare_digest(credentials.username.encode("utf8"), settings.api_username)
29
+ is_correct_password = secrets.compare_digest(credentials.password.encode("utf8"), settings.api_password)
30
+ if not (is_correct_username and is_correct_password):
31
+ raise InvalidCredentials()
32
+ return True
@@ -0,0 +1 @@
1
+ """Contains all REST API routes."""
@@ -0,0 +1,71 @@
1
+ """Contains all projects related REST API routes."""
2
+
3
+ from typing import Annotated
4
+
5
+ from fastapi import APIRouter, Depends, UploadFile
6
+ from fastapi.responses import JSONResponse
7
+
8
+ from vdoc.api.dependencies.auth import require_authentication
9
+ from vdoc.methods.api.projects import (
10
+ get_project_version_impl,
11
+ list_project_versions_impl,
12
+ list_projects_impl,
13
+ upload_project_version_impl,
14
+ )
15
+ from vdoc.models.project import Project
16
+
17
+ router = APIRouter(prefix="/projects", tags=["Projects"])
18
+
19
+
20
+ @router.get("/")
21
+ def list_projects() -> list[Project]:
22
+ """Lists all available projects.
23
+
24
+ Returns:
25
+ A list of all available projects.
26
+ """
27
+ return list_projects_impl()
28
+
29
+
30
+ @router.get("/{name}/versions/")
31
+ def list_project_versions(name: str) -> list[str]:
32
+ """Lists all versions of a project.
33
+
34
+ Args:
35
+ name: The name of the project.
36
+
37
+ Returns:
38
+ A list of all versions of a project.
39
+ """
40
+ return list_project_versions_impl(name=name)
41
+
42
+
43
+ @router.get("/{name}/versions/{version}")
44
+ def get_project_versions(name: str, version: str) -> str:
45
+ """Returns the requested project version.
46
+
47
+ Args:
48
+ name: The name of the project.
49
+ version: The requested version.
50
+
51
+ Returns:
52
+ The requested project version.
53
+ """
54
+ return get_project_version_impl(name=name, version=version)
55
+
56
+
57
+ @router.post("/{name}/versions/{version}")
58
+ def upload_project_version(
59
+ name: str, version: str, file: UploadFile, _: Annotated[str, Depends(require_authentication)]
60
+ ) -> JSONResponse:
61
+ """Accepts and processes an uploaded project documentation.
62
+
63
+ Args:
64
+ name: The project name.
65
+ version: The project version.
66
+ file: The documentation zip file.
67
+
68
+ Returns:
69
+ A message that the documentation has been uploaded successfully.
70
+ """
71
+ return upload_project_version_impl(name=name, version=version, file=file)
vdoc/cli/__init__.py ADDED
@@ -0,0 +1 @@
1
+ """Contains the CLI."""
vdoc/cli/main.py ADDED
@@ -0,0 +1,84 @@
1
+ """Contains the main CLI entry point."""
2
+
3
+ import logging
4
+ from enum import Enum
5
+
6
+ import typer
7
+ from rich.logging import RichHandler
8
+
9
+ from vdoc import get_app_name, get_app_version
10
+ from vdoc.cli.run import _cli_run
11
+ from vdoc.constants import DEFAULT_API_PASSWORD, DEFAULT_API_USERNAME
12
+ from vdoc.settings import VDocSettings
13
+
14
+ _logger = logging.getLogger(__name__)
15
+
16
+
17
+ app = typer.Typer()
18
+ app.command(name="run", help="Runs the application")(_cli_run)
19
+
20
+
21
+ class LogLevel(str, Enum):
22
+ """Enum for log levels for typer."""
23
+
24
+ DEBUG = "DEBUG"
25
+ INFO = "INFO"
26
+ WARNING = "WARNING"
27
+ ERROR = "ERROR"
28
+
29
+ def __str__(self) -> str:
30
+ """String representation of the log level.
31
+
32
+ Returns:
33
+ The log level as string.
34
+ """
35
+ return self.value
36
+
37
+
38
+ def print_version(do_print: bool) -> None:
39
+ """Prints the version of the software.
40
+
41
+ Args:
42
+ do_print: If the version shall be printed.
43
+
44
+ Raises:
45
+ typer.Exit: After the version was printed.
46
+ """
47
+ if do_print:
48
+ print(get_app_version())
49
+ raise typer.Exit()
50
+
51
+
52
+ def check_for_default_credentials() -> None:
53
+ """Checks the configured API credentials and warns if the default credentials are used."""
54
+ settings = VDocSettings()
55
+ if settings.api_password == DEFAULT_API_PASSWORD and settings.api_username == DEFAULT_API_USERNAME:
56
+ _logger.warning(
57
+ "The application is running using the default credentials. Update them according to the documentation!"
58
+ )
59
+
60
+
61
+ @app.callback()
62
+ def _common(
63
+ _: bool = typer.Option(
64
+ False,
65
+ "--version",
66
+ callback=print_version,
67
+ is_eager=True,
68
+ help="Print the installed version of the software.",
69
+ ),
70
+ log_level: LogLevel = typer.Option(LogLevel.INFO, help="The log level"),
71
+ ) -> None:
72
+ rich_handler = RichHandler()
73
+ rich_handler.setFormatter(logging.Formatter("%(message)s"))
74
+ logger = logging.getLogger()
75
+ logger.handlers = [rich_handler]
76
+ logger.setLevel(log_level)
77
+ _logger.info(f"Starting {get_app_name()}@{get_app_version()}")
78
+ check_for_default_credentials()
79
+
80
+
81
+ typer_click_object = typer.main.get_command(app)
82
+
83
+ if __name__ == "__main__": # pragma: no cover
84
+ app()
vdoc/cli/run.py ADDED
@@ -0,0 +1,30 @@
1
+ """This module defines the typer run method."""
2
+
3
+ import logging
4
+ from typing import Annotated
5
+
6
+ import typer
7
+
8
+ from vdoc.methods.cli.cli_run_method import run_impl
9
+ from vdoc.settings import VDocSettings
10
+
11
+ _logger = logging.getLogger(__name__)
12
+
13
+
14
+ def _cli_run(
15
+ bind_address: Annotated[
16
+ str,
17
+ typer.Option(help="Application bind ip address."),
18
+ ] = VDocSettings().bind_address,
19
+ bind_port: Annotated[
20
+ int,
21
+ typer.Option(help="Application bind port."),
22
+ ] = VDocSettings().bind_port,
23
+ ) -> None: # noqa: disable=D103
24
+ try:
25
+ run_impl(bind_address=bind_address, bind_port=bind_port)
26
+ except KeyboardInterrupt as error:
27
+ raise typer.Exit(0) from error
28
+ except Exception as error:
29
+ _logger.error(error)
30
+ raise typer.Exit(1) from error
vdoc/constants.py ADDED
@@ -0,0 +1,11 @@
1
+ """Contains all constant values."""
2
+
3
+ from pathlib import Path
4
+
5
+ CONFIG_ENV_PREFIX = "VDOC_"
6
+
7
+ DEFAULT_DOCS_DIR = Path("/srv/vdoc/docs/")
8
+ DEFAULT_API_USERNAME = b"admin"
9
+ DEFAULT_API_PASSWORD = b"admin"
10
+ DEFAULT_BIND_ADDRESS = "0.0.0.0"
11
+ DEFAULT_BIND_PORT = 8080
@@ -0,0 +1,20 @@
1
+ .. include:: ../README.rst
2
+
3
+ ########
4
+ Contents
5
+ ########
6
+
7
+ .. toctree::
8
+ :maxdepth: 2
9
+
10
+ vdoc
11
+
12
+
13
+ ##############################
14
+ License Compliance Information
15
+ ##############################
16
+
17
+ .. toctree::
18
+ :maxdepth: 1
19
+
20
+ license_compliance