Add paperless-ngx integration for document storage and share links

- dlib/integrations/paperless.py: sync HTTP client wrapping the paperless-ngx
  REST API (upload doc, poll task, create/delete share links, delete document)
- config: PAPERLESS_ENABLED, PAPERLESS_BASE_URL, PAPERLESS_TOKEN, PAPERLESS_TAG_IDS
- PublicAsset model: paperless_document_id + paperless_share_slug columns
- publication service: after creating the asset, if paperless is enabled upload
  the patched PDF and create a share link; stores doc id + share slug on the asset
- public routes: pass expires_at through to publish_version; new
  POST /{slug}/share-links endpoint to (re)create expiring share links on demand
- schemas: PublishRequest.expires_at, PublicAssetResponse.paperless_share_url,
  new ShareLinkRequest model
- frontend: paperless_share_url field on PublicAsset type, createShareLink()
  and expiresAt param on publishVersion() in api.ts
- .env.example: documented paperless env vars

https://claude.ai/code/session_01YPVs6uBwCvcwVMvrfLBBdu
This commit is contained in:
Claude
2026-04-09 09:27:26 +00:00
parent 61430317f4
commit f5621f120f
11 changed files with 214 additions and 18 deletions

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
import enum
from datetime import datetime, timezone
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, String, Text
from sqlalchemy import Boolean, DateTime, Enum, ForeignKey, Integer, String, Text
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
@@ -148,6 +148,8 @@ class PublicAsset(Base, IdentifierMixin, TimestampMixin):
expires_at: Mapped[str | None] = mapped_column(
DateTime(timezone=True), nullable=True
)
paperless_document_id: Mapped[int | None] = mapped_column(Integer, nullable=True)
paperless_share_slug: Mapped[str | None] = mapped_column(String(160), nullable=True)
submission: Mapped[Submission | None] = relationship(
"Submission", back_populates="public_asset"