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

@@ -80,6 +80,7 @@ export type PublicAsset = {
version_id?: string | null;
submission_id?: string | null;
created_at: string;
paperless_share_url?: string | null;
};
export type PublicAssetAnalytics = {
@@ -229,11 +230,23 @@ export async function publishVersion(
versionId?: string | null,
submissionId?: string | null,
slug?: string | null,
expiresAt?: string | null,
): Promise<PublicAsset> {
return req<PublicAsset>('/api/v1/public/publish', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ version_id: versionId ?? null, submission_id: submissionId ?? null, slug: slug ?? null }),
body: JSON.stringify({ version_id: versionId ?? null, submission_id: submissionId ?? null, slug: slug ?? null, expires_at: expiresAt ?? null }),
});
}
export async function createShareLink(
slug: string,
expirationDate?: string | null,
): Promise<PublicAsset> {
return req<PublicAsset>(`/api/v1/public/${encodeURIComponent(slug)}/share-links`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ expiration_date: expirationDate ?? null }),
});
}

View File

@@ -64,6 +64,8 @@ export interface PublicAsset {
isPublic: boolean;
expiresAt?: string;
viewCount: number;
url?: string | null;
paperlessShareUrl?: string | null;
}
export interface AISuggestion {