add a "/file" router (static serve from WebDAV)

This commit is contained in:
Jörn-Michael Miehe 2022-09-18 21:59:02 +00:00
parent 8bd87fb6f1
commit 8ef9d4ad2e
6 changed files with 108 additions and 3 deletions

View file

@ -22,6 +22,7 @@ RUN set -ex; \
export DEBIAN_FRONTEND=noninteractive; \ export DEBIAN_FRONTEND=noninteractive; \
apt-get update; apt-get -y install --no-install-recommends \ apt-get update; apt-get -y install --no-install-recommends \
git-flow \ git-flow \
libmagic1 \
; rm -rf /var/lib/apt/lists/*; ; rm -rf /var/lib/apt/lists/*;
# [Optional] Uncomment this line to install global node packages. # [Optional] Uncomment this line to install global node packages.

View file

@ -102,6 +102,7 @@ class Config(BaseModel):
image_dir: str = "image" image_dir: str = "image"
text_dir: str = "text" text_dir: str = "text"
file_dir: str = "file"
logo: LogoUIConfig = LogoUIConfig() logo: LogoUIConfig = LogoUIConfig()
image: ImageConfig = ImageConfig() image: ImageConfig = ImageConfig()

View file

@ -6,7 +6,7 @@ This file: Main API router definition.
from fastapi import APIRouter from fastapi import APIRouter
from . import aggregate, calendar, image, misc, text, ticker from . import aggregate, calendar, file, image, misc, text, ticker
router = APIRouter(prefix="/api/v1") router = APIRouter(prefix="/api/v1")
@ -15,6 +15,7 @@ router.include_router(misc.router)
router.include_router(text.router) router.include_router(text.router)
router.include_router(ticker.router) router.include_router(ticker.router)
router.include_router(image.router) router.include_router(image.router)
router.include_router(file.router)
router.include_router(calendar.router) router.include_router(calendar.router)
router.include_router(aggregate.router) router.include_router(aggregate.router)

View file

@ -0,0 +1,89 @@
"""
Router "file" provides:
- listing files
- finding files by name prefix
- getting files by name prefix
"""
import re
from io import BytesIO
from logging import getLogger
from typing import Iterator
from fastapi import APIRouter, Depends
from fastapi.responses import StreamingResponse
from magic import Magic
from ...dav_common import webdav_ensure_path
from ...dav_file import DavFile
from ._common import FileNameLister, PrefixFinder, PrefixUnique
_logger = getLogger(__name__)
_magic = Magic(mime=True)
router = APIRouter(prefix="/file", tags=["file"])
file_lister = FileNameLister(
path_name="file_dir",
re=re.compile(
r"[^/]$",
flags=re.IGNORECASE,
),
)
file_finder = PrefixFinder(file_lister)
file_unique = PrefixUnique(file_finder)
@router.on_event("startup")
async def start_router() -> None:
_logger.debug(f"{router.prefix} router starting.")
webdav_ensure_path(await file_lister.remote_path)
@router.get(
"/list",
response_model=list[str],
responses=file_lister.responses,
)
async def list_files(
names: Iterator[str] = Depends(file_lister),
) -> list[str]:
return list(names)
@router.get(
"/find/{prefix}",
response_model=list[str],
responses=file_finder.responses,
)
async def find_files(
names: Iterator[str] = Depends(file_finder),
) -> list[str]:
return list(names)
@router.get(
"/get/{prefix}",
response_class=StreamingResponse,
responses=file_unique.responses,
)
async def get_file(
prefix: str,
name: str = Depends(file_unique),
) -> StreamingResponse:
dav_file = DavFile(f"{await file_lister.remote_path}/{name}")
buffer = BytesIO(await dav_file.as_bytes)
mime = _magic.from_buffer(buffer.read(2048))
buffer.seek(0)
return StreamingResponse(
content=buffer,
media_type=mime,
headers={
"Content-Disposition": f"filename={prefix}"
},
)

16
api/poetry.lock generated
View file

@ -138,7 +138,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
[package.extras] [package.extras]
cssselect = ["cssselect (>=0.7)"] cssselect = ["cssselect (>=0.7)"]
html5 = ["html5lib"] html5 = ["html5lib"]
htmlsoup = ["beautifulsoup4"] htmlsoup = ["BeautifulSoup4"]
source = ["Cython (>=0.29.7)"] source = ["Cython (>=0.29.7)"]
[[package]] [[package]]
@ -205,6 +205,14 @@ python-versions = ">=3.7"
[package.extras] [package.extras]
cli = ["click (>=5.0)"] cli = ["click (>=5.0)"]
[[package]]
name = "python-magic"
version = "0.4.27"
description = "File type identification using libmagic"
category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "pytz" name = "pytz"
version = "2022.2.1" version = "2022.2.1"
@ -388,7 +396,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.9" python-versions = "^3.9"
content-hash = "f31c08e6b5aabf05d1d144a083abbfb76c8708ef23f6d99122c646126c9f7bcd" content-hash = "b25d37c0bf9187d599709a66e05d21c0df7da2b140373f6cd50b070ae2f073ab"
[metadata.files] [metadata.files]
anyio = [ anyio = [
@ -617,6 +625,10 @@ python-dotenv = [
{file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"},
{file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"},
] ]
python-magic = [
{file = "python-magic-0.4.27.tar.gz", hash = "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b"},
{file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"},
]
pytz = [ pytz = [
{file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"}, {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"},
{file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"}, {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"},

View file

@ -16,6 +16,7 @@ tomli = "^2.0.1"
tomli-w = "^1.0.0" tomli-w = "^1.0.0"
uvicorn = "^0.18.3" uvicorn = "^0.18.3"
webdavclient3 = "3.14.5" webdavclient3 = "3.14.5"
python-magic = "^0.4.27"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
# pytest = "^5.2" # pytest = "^5.2"