From 74c8eacbf29b191dd82966fd572c763c71166e9c Mon Sep 17 00:00:00 2001
From: WorldTeacher
Date: Thu, 20 Nov 2025 13:04:42 +0100
Subject: [PATCH] feat: add catalogue check by creating a small service runner
---
API_SERVICE.md | 97 ++++++++++++++++++++++++
api_service.py | 67 +++++++++++++++++
php/config.php | 3 +
php/elsa.php | 200 ++++++++++++++++++++++++++++++++++++++++++++++++-
4 files changed, 364 insertions(+), 3 deletions(-)
create mode 100644 API_SERVICE.md
create mode 100644 api_service.py
diff --git a/API_SERVICE.md b/API_SERVICE.md
new file mode 100644
index 0000000..b98b6fe
--- /dev/null
+++ b/API_SERVICE.md
@@ -0,0 +1,97 @@
+# Signature Validation API Service
+
+This is a lightweight Python service that provides signature validation for the PHP application.
+
+## Why a separate service?
+
+The `bibapi` library is Python-only and provides access to your library catalog. Rather than rewriting this in PHP, we keep a small Python service running just for signature validation.
+
+## Running the Service
+
+### Option 1: Direct Python
+```bash
+python api_service.py
+```
+
+### Option 2: With uvicorn
+```bash
+uvicorn api_service:app --host 0.0.0.0 --port 8001
+```
+
+### Option 3: Docker (if you can run containers internally)
+```dockerfile
+FROM python:3.13-slim
+WORKDIR /app
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+COPY api_service.py .
+EXPOSE 8001
+CMD ["uvicorn", "api_service:app", "--host", "0.0.0.0", "--port", "8001"]
+```
+
+```bash
+docker build -t signature-api .
+docker run -d -p 8001:8001 signature-api
+```
+
+## Configuration
+
+Set the API endpoint in your PHP config. Update `php/config.php`:
+
+```php
+// Signature validation API endpoint (optional)
+define('SIGNATURE_API_URL', getenv('SIGNATURE_API_URL') ?: 'http://localhost:8001');
+```
+
+## Testing
+
+```bash
+# Health check
+curl http://localhost:8001/health
+
+# Validate a signature
+curl "http://localhost:8001/api/validate-signature?signature=ABC123"
+```
+
+## Production Deployment
+
+1. **Same server**: Run on a different port (8001) alongside your PHP application
+2. **Separate server**: Run on internal network, update `SIGNATURE_API_URL` in PHP config
+3. **Systemd service** (Linux):
+
+Create `/etc/systemd/system/signature-api.service`:
+```ini
+[Unit]
+Description=Signature Validation API
+After=network.target
+
+[Service]
+Type=simple
+User=www-data
+WorkingDirectory=/var/www/signature-api
+Environment="PATH=/var/www/signature-api/.venv/bin"
+ExecStart=/var/www/signature-api/.venv/bin/uvicorn api_service:app --host 0.0.0.0 --port 8001
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
+```
+
+Then:
+```bash
+sudo systemctl enable signature-api
+sudo systemctl start signature-api
+```
+
+## Security
+
+- In production, update CORS `allow_origins` to only your PHP server domain
+- Consider adding API key authentication if exposed to public network
+- Run behind reverse proxy (nginx/Apache) with SSL
+
+## Notes
+
+- The service is stateless and lightweight
+- No data persistence required
+- Can be scaled horizontally if needed
+- Falls back gracefully if unavailable (ELSA form fields just won't have validation hints)
diff --git a/api_service.py b/api_service.py
new file mode 100644
index 0000000..543fcb7
--- /dev/null
+++ b/api_service.py
@@ -0,0 +1,67 @@
+"""
+Lightweight Python API service for signature validation
+This can run independently to support the PHP application
+"""
+from fastapi import FastAPI, Query
+from fastapi.responses import JSONResponse
+from fastapi.middleware.cors import CORSMiddleware
+from bibapi import catalogue
+import re
+import os
+
+app = FastAPI(title="Signature Validation API")
+
+# Allow PHP application to call this API
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"], # In production, restrict to your PHP server domain
+ allow_credentials=True,
+ allow_methods=["GET"],
+ allow_headers=["*"],
+)
+
+# Initialize catalogue for signature validation
+cat = catalogue.Catalogue()
+
+@app.get("/api/validate-signature")
+async def validate_signature(signature: str = Query(...)):
+ """Validate a book signature and return total pages"""
+ try:
+ book_result = cat.get_book_with_data(signature)
+ if book_result and hasattr(book_result, "pages") and book_result.pages:
+ # Try to extract numeric page count
+ pages_str = str(book_result.pages)
+ # Extract first number from pages string (e.g., "245 S." -> 245)
+ match = re.search(r"(\d+)", pages_str)
+ if match:
+ total_pages = int(match.group(1))
+ return JSONResponse(
+ {"valid": True, "total_pages": total_pages, "signature": signature}
+ )
+
+ return JSONResponse(
+ {
+ "valid": False,
+ "error": "Signatur nicht gefunden oder keine Seitenzahl verfügbar",
+ "signature": signature,
+ }
+ )
+ except Exception as e:
+ return JSONResponse(
+ {
+ "valid": False,
+ "error": f"Fehler bei der Validierung: {str(e)}",
+ "signature": signature,
+ },
+ status_code=500
+ )
+
+@app.get("/health")
+async def health_check():
+ """Health check endpoint"""
+ return {"status": "ok", "service": "signature-validation"}
+
+if __name__ == "__main__":
+ import uvicorn
+ port = int(os.getenv("API_PORT", "8001"))
+ uvicorn.run(app, host="0.0.0.0", port=port)
diff --git a/php/config.php b/php/config.php
index 56db04c..4db6933 100644
--- a/php/config.php
+++ b/php/config.php
@@ -24,5 +24,8 @@ define('MAIL_TO', getenv('MAIL_TO') ?: 'semesterapparate@ph-freiburg.de');
define('BASE_PATH', __DIR__);
define('STATIC_PATH', '/static');
+// Signature validation API (optional Python service)
+define('SIGNATURE_API_URL', getenv('SIGNATURE_API_URL') ?: 'http://localhost:8001');
+
// Email regex pattern
define('EMAIL_REGEX', '/^[^@\s]+@[^@\s]+\.[^@\s]+$/');
diff --git a/php/elsa.php b/php/elsa.php
index 9be4905..b70b41b 100644
--- a/php/elsa.php
+++ b/php/elsa.php
@@ -34,7 +34,7 @@
-