8 Commits
main ... dev

5 changed files with 26 additions and 8 deletions

View File

@@ -58,7 +58,7 @@ jobs:
fetch-tags: true # Fetch all tags (refs/tags) fetch-tags: true # Fetch all tags (refs/tags)
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v7
- name: Set up Python - name: Set up Python
run: uv python install run: uv python install
with: with:

View File

@@ -16,7 +16,7 @@ jobs:
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v2
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v7
- name: (optional) Prepare dependencies - name: (optional) Prepare dependencies
run: | run: |

13
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,13 @@
{
"cSpell.words": [
"buildx",
"Buildx",
"elif",
"gitea",
"Gitea",
"github",
"linux",
"pyproject",
"semapform"
]
}

View File

@@ -4,17 +4,19 @@ This can run independently to support the PHP application.
""" """
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
from contextlib import asynccontextmanager
import json import json
import logging import logging
import os import os
import re import re
import time import time
from typing import Any, TYPE_CHECKING import urllib.parse
from contextlib import asynccontextmanager
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import AsyncIterator, Callable, Awaitable from collections.abc import AsyncIterator, Awaitable, Callable
# Avoid importing heavy modules at top-level to keep `import api_service` lightweight # Avoid importing heavy modules at top-level to keep `import api_service` lightweight
from fastapi import FastAPI, Query, Request, Response from fastapi import FastAPI, Query, Request, Response
@@ -29,7 +31,7 @@ redis_client = None
@asynccontextmanager @asynccontextmanager
async def _lifespan(_app: FastAPI) -> AsyncIterator[None]: async def _lifespan(_app: FastAPI) -> AsyncIterator[None]:
"""Lifespan handler: connect to Redis on startup and close on shutdown.""" """Lifespan handler: connect to Redis on startup and close on shutdown."""
global redis_client global redis_client # type: ignore[PLW0603]
if REDIS_URL: if REDIS_URL:
try: try:
import redis.asyncio as aioredis import redis.asyncio as aioredis
@@ -159,6 +161,10 @@ async def _cache_set(key: str, value: CacheValue, ttl: int = CACHE_TTL_SECONDS)
async def validate_signature(signature: str = Query(...)) -> JSONResponse: async def validate_signature(signature: str = Query(...)) -> JSONResponse:
"""Validate a book signature and return total pages.""" """Validate a book signature and return total pages."""
# check cache first # check cache first
# ensure signature is stripped of leading/trailing whitespace
signature = signature.strip()
# enforce url quotes
signature = urllib.parse.quote(signature)
cache_key = f"signature:{signature}" cache_key = f"signature:{signature}"
cached = await _cache_get(cache_key) cached = await _cache_get(cache_key)
if cached is not None: if cached is not None:

View File

@@ -7,7 +7,6 @@ requires-python = ">=3.13"
dependencies = [ dependencies = [
"bibapi[catalogue]>=0.0.6", "bibapi[catalogue]>=0.0.6",
"fastapi>=0.122.0", "fastapi>=0.122.0",
"pip>=25.3",
"uvicorn>=0.38.0", "uvicorn>=0.38.0",
"redis>=4.6.0", "redis>=4.6.0",
] ]
@@ -16,7 +15,7 @@ name = "gitea"
url = "https://git.theprivateserver.de/api/packages/PHB/pypi/simple/" url = "https://git.theprivateserver.de/api/packages/PHB/pypi/simple/"
[tool.bumpversion] [tool.bumpversion]
current_version = "0.2.0" current_version = "0.1.3"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)" parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"] serialize = ["{major}.{minor}.{patch}"]
search = "{current_version}" search = "{current_version}"