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

@@ -9,6 +9,7 @@ from .cv import (
PublicAssetLookupResponse,
PublicAssetResponse,
PublishRequest,
ShareLinkRequest,
SubmissionCreateRequest,
SubmissionResponse,
SubmissionStatusUpdateRequest,
@@ -31,6 +32,7 @@ __all__ = [
"SuggestionResponse",
"SuggestionUpdateRequest",
"PublishRequest",
"ShareLinkRequest",
"PublicAssetResponse",
"PublicAssetLookupResponse",
"PublicAssetAnalyticsResponse",

View File

@@ -121,6 +121,11 @@ class PublishRequest(BaseModel):
version_id: str | None = None
submission_id: str | None = None
slug: str | None = None
expires_at: datetime | None = None
class ShareLinkRequest(BaseModel):
expiration_date: datetime | None = None
class PublicAssetResponse(BaseModel):
@@ -134,6 +139,7 @@ class PublicAssetResponse(BaseModel):
version_id: str | None = None
submission_id: str | None = None
url: str | None = None
paperless_share_url: str | None = None
class PublicAssetLookupResponse(BaseModel):