mirror of
https://github.com/papra-hq/papra.git
synced 2025-12-19 20:29:51 -06:00
Compare commits
5 Commits
@papra/app
...
@papra/app
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38dcc765f9 | ||
|
|
c085b9d676 | ||
|
|
a64a93544d | ||
|
|
f20559e95d | ||
|
|
7d755d0981 |
@@ -1,5 +1,9 @@
|
||||
# @papra/app-client
|
||||
|
||||
## 0.8.2
|
||||
|
||||
## 0.8.1
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@papra/app-client",
|
||||
"type": "module",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.2",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@10.12.3",
|
||||
"description": "Papra frontend client",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @papra/app-server
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#461](https://github.com/papra-hq/papra/pull/461) [`c085b9d`](https://github.com/papra-hq/papra/commit/c085b9d6766297943112601d3c634c716c4be440) Thanks [@CorentinTh](https://github.com/CorentinTh)! - Fix a regression bug that executed tagging rules before the file content was extracted
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#459](https://github.com/papra-hq/papra/pull/459) [`f20559e`](https://github.com/papra-hq/papra/commit/f20559e95d1dc7d7a099dfd9a9df42bf5ce1b0b2) Thanks [@CorentinTh](https://github.com/CorentinTh)! - Removed dev-dependency needed in production build
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@papra/app-server",
|
||||
"type": "module",
|
||||
"version": "0.8.0",
|
||||
"version": "0.8.2",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@10.12.3",
|
||||
"description": "Papra app server",
|
||||
@@ -12,13 +12,14 @@
|
||||
"dev": "tsx watch --env-file-if-exists=.env src/index.ts | crowlog-pretty",
|
||||
"build": "pnpm esbuild --bundle src/index.ts --platform=node --packages=external --format=esm --outfile=dist/index.js --minify",
|
||||
"start": "node dist/index.js",
|
||||
"start:with-migrations": "pnpm migrate:up && pnpm start",
|
||||
"start:with-migrations": "pnpm migrate:up:prod && pnpm start",
|
||||
"lint": "eslint .",
|
||||
"lint:fix": "eslint --fix .",
|
||||
"test": "vitest run",
|
||||
"test:watch": "vitest watch",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"migrate:up": "tsx --env-file-if-exists=.env src/scripts/migrate-up.script.ts | crowlog-pretty",
|
||||
"migrate:up:prod": "tsx src/scripts/migrate-up.script.ts",
|
||||
"migrate:push": "drizzle-kit push",
|
||||
"migrate:create": "sh -c 'drizzle-kit generate --name \"$1\" && tsx --env-file-if-exists=.env src/scripts/create-migration.ts \"$1\" | crowlog-pretty' --",
|
||||
"db:studio": "drizzle-kit studio",
|
||||
|
||||
@@ -4,6 +4,8 @@ import { overrideConfig } from '../config/config.test-utils';
|
||||
import { ORGANIZATION_ROLES } from '../organizations/organizations.constants';
|
||||
import { nextTick } from '../shared/async/defer.test-utils';
|
||||
import { collectReadableStreamToString } from '../shared/streams/readable-stream';
|
||||
import { createTaggingRulesRepository } from '../tagging-rules/tagging-rules.repository';
|
||||
import { createTagsRepository } from '../tags/tags.repository';
|
||||
import { documentsTagsTable } from '../tags/tags.table';
|
||||
import { createInMemoryTaskServices } from '../tasks/tasks.test-utils';
|
||||
import { documentActivityLogTable } from './document-activity/document-activity.table';
|
||||
@@ -345,6 +347,8 @@ describe('documents usecases', () => {
|
||||
|
||||
const documentsRepository = createDocumentsRepository({ db });
|
||||
const documentsStorageService = await createDocumentStorageService({ config });
|
||||
const taggingRulesRepository = createTaggingRulesRepository({ db });
|
||||
const tagsRepository = createTagsRepository({ db });
|
||||
|
||||
await db.insert(documentsTable).values({
|
||||
id: 'document-1',
|
||||
@@ -366,6 +370,8 @@ describe('documents usecases', () => {
|
||||
organizationId: 'organization-1',
|
||||
documentsRepository,
|
||||
documentsStorageService,
|
||||
taggingRulesRepository,
|
||||
tagsRepository,
|
||||
});
|
||||
|
||||
const documentRecords = await db.select().from(documentsTable);
|
||||
|
||||
@@ -95,6 +95,7 @@ export async function createDocument({
|
||||
organizationId,
|
||||
documentsRepository,
|
||||
tagsRepository,
|
||||
taggingRulesRepository,
|
||||
logger,
|
||||
})
|
||||
: await createNewDocument({
|
||||
@@ -109,6 +110,8 @@ export async function createDocument({
|
||||
documentsStorageService,
|
||||
generateDocumentId,
|
||||
trackingServices,
|
||||
taskServices,
|
||||
ocrLanguages,
|
||||
logger,
|
||||
});
|
||||
|
||||
@@ -119,8 +122,6 @@ export async function createDocument({
|
||||
documentActivityRepository,
|
||||
});
|
||||
|
||||
await applyTaggingRules({ document, taggingRulesRepository, tagsRepository });
|
||||
|
||||
deferTriggerWebhooks({
|
||||
webhookRepository,
|
||||
organizationId,
|
||||
@@ -134,11 +135,6 @@ export async function createDocument({
|
||||
},
|
||||
});
|
||||
|
||||
await taskServices.scheduleJob({
|
||||
taskName: 'extract-document-file-content',
|
||||
data: { documentId: document.id, organizationId, ocrLanguages },
|
||||
});
|
||||
|
||||
return { document };
|
||||
}
|
||||
|
||||
@@ -181,6 +177,7 @@ async function handleExistingDocument({
|
||||
organizationId,
|
||||
documentsRepository,
|
||||
tagsRepository,
|
||||
taggingRulesRepository,
|
||||
logger,
|
||||
}: {
|
||||
existingDocument: Document;
|
||||
@@ -189,6 +186,7 @@ async function handleExistingDocument({
|
||||
organizationId: string;
|
||||
documentsRepository: DocumentsRepository;
|
||||
tagsRepository: TagsRepository;
|
||||
taggingRulesRepository: TaggingRulesRepository;
|
||||
logger: Logger;
|
||||
}) {
|
||||
if (!existingDocument.isDeleted) {
|
||||
@@ -202,6 +200,8 @@ async function handleExistingDocument({
|
||||
documentsRepository.restoreDocument({ documentId: existingDocument.id, organizationId, name: fileName, userId }),
|
||||
]);
|
||||
|
||||
await applyTaggingRules({ document: restoredDocument, taggingRulesRepository, tagsRepository });
|
||||
|
||||
return { document: restoredDocument };
|
||||
}
|
||||
|
||||
@@ -217,6 +217,8 @@ async function createNewDocument({
|
||||
documentsStorageService,
|
||||
generateDocumentId,
|
||||
trackingServices,
|
||||
taskServices,
|
||||
ocrLanguages = [],
|
||||
logger,
|
||||
}: {
|
||||
file: File;
|
||||
@@ -230,6 +232,8 @@ async function createNewDocument({
|
||||
documentsStorageService: DocumentStorageService;
|
||||
generateDocumentId: () => string;
|
||||
trackingServices: TrackingServices;
|
||||
taskServices: TaskServices;
|
||||
ocrLanguages?: string[];
|
||||
logger: Logger;
|
||||
}) {
|
||||
const documentId = generateDocumentId();
|
||||
@@ -268,6 +272,11 @@ async function createNewDocument({
|
||||
throw error;
|
||||
}
|
||||
|
||||
await taskServices.scheduleJob({
|
||||
taskName: 'extract-document-file-content',
|
||||
data: { documentId, organizationId, ocrLanguages },
|
||||
});
|
||||
|
||||
if (isDefined(userId)) {
|
||||
trackingServices.captureUserEvent({ userId, event: 'Document created' });
|
||||
}
|
||||
@@ -316,8 +325,6 @@ export async function hardDeleteDocument({
|
||||
documentsRepository: DocumentsRepository;
|
||||
documentsStorageService: DocumentStorageService;
|
||||
}) {
|
||||
// TODO: use transaction
|
||||
|
||||
await Promise.all([
|
||||
documentsRepository.hardDeleteDocument({ documentId: document.id }),
|
||||
documentsStorageService.deleteFile({ storageKey: document.originalStorageKey }),
|
||||
@@ -409,12 +416,16 @@ export async function extractAndSaveDocumentFileContent({
|
||||
documentsRepository,
|
||||
documentsStorageService,
|
||||
ocrLanguages,
|
||||
taggingRulesRepository,
|
||||
tagsRepository,
|
||||
}: {
|
||||
documentId: string;
|
||||
ocrLanguages?: string[];
|
||||
organizationId: string;
|
||||
documentsRepository: DocumentsRepository;
|
||||
documentsStorageService: DocumentStorageService;
|
||||
taggingRulesRepository: TaggingRulesRepository;
|
||||
tagsRepository: TagsRepository;
|
||||
}) {
|
||||
const { document } = await documentsRepository.getDocumentById({ documentId, organizationId });
|
||||
|
||||
@@ -428,5 +439,14 @@ export async function extractAndSaveDocumentFileContent({
|
||||
|
||||
const { text } = await extractDocumentText({ file, ocrLanguages });
|
||||
|
||||
await documentsRepository.updateDocument({ documentId, organizationId, content: text });
|
||||
const { document: updatedDocument } = await documentsRepository.updateDocument({ documentId, organizationId, content: text });
|
||||
|
||||
if (!updatedDocument) {
|
||||
// This should never happen, but for type safety
|
||||
throw createDocumentNotFoundError();
|
||||
}
|
||||
|
||||
await applyTaggingRules({ document: updatedDocument, taggingRulesRepository, tagsRepository });
|
||||
|
||||
return { document: updatedDocument };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Database } from '../../app/database/database.types';
|
||||
import type { Config } from '../../config/config.types';
|
||||
import type { TaskServices } from '../../tasks/tasks.services';
|
||||
import { createTaggingRulesRepository } from '../../tagging-rules/tagging-rules.repository';
|
||||
import { createTagsRepository } from '../../tags/tags.repository';
|
||||
import { createDocumentsRepository } from '../documents.repository';
|
||||
import { extractAndSaveDocumentFileContent } from '../documents.usecases';
|
||||
import { createDocumentStorageService } from '../storage/documents.storage.services';
|
||||
@@ -13,6 +15,8 @@ export async function registerExtractDocumentFileContentTask({ taskServices, db,
|
||||
handler: async ({ data }) => {
|
||||
const documentsRepository = createDocumentsRepository({ db });
|
||||
const documentsStorageService = await createDocumentStorageService({ config });
|
||||
const taggingRulesRepository = createTaggingRulesRepository({ db });
|
||||
const tagsRepository = createTagsRepository({ db });
|
||||
|
||||
// TODO: remove type cast
|
||||
const { documentId, organizationId, ocrLanguages } = data as { documentId: string; organizationId: string; ocrLanguages: string[] };
|
||||
@@ -23,6 +27,8 @@ export async function registerExtractDocumentFileContentTask({ taskServices, db,
|
||||
ocrLanguages,
|
||||
documentsRepository,
|
||||
documentsStorageService,
|
||||
taggingRulesRepository,
|
||||
tagsRepository,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -11,6 +11,10 @@ FROM base AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# --- add build deps for sharp/node-gyp, needed to be explicitly installed for armv7 ---
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
ENV npm_config_python=/usr/bin/python3
|
||||
|
||||
COPY pnpm-lock.yaml ./
|
||||
COPY pnpm-workspace.yaml ./
|
||||
COPY apps/papra-client/package.json apps/papra-client/package.json
|
||||
|
||||
@@ -13,6 +13,10 @@ FROM base AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# --- add build deps for sharp/node-gyp, needed to be explicitly installed for armv7 ---
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && rm -rf /var/lib/apt/lists/*
|
||||
ENV npm_config_python=/usr/bin/python3
|
||||
|
||||
COPY pnpm-lock.yaml ./
|
||||
COPY pnpm-workspace.yaml ./
|
||||
COPY apps/papra-client/package.json apps/papra-client/package.json
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
"keywords": [],
|
||||
"scripts": {
|
||||
"docker:build:root": "docker build -t papra -f docker/Dockerfile .",
|
||||
"docker:build:root:armv7": "docker buildx build --platform linux/arm/v7 -t papra -f docker/Dockerfile --load .",
|
||||
"docker:build:root:amd64": "docker buildx build --platform linux/amd64 -t papra -f docker/Dockerfile --load .",
|
||||
"docker:build:root:arm64": "docker buildx build --platform linux/arm64 -t papra -f docker/Dockerfile --load .",
|
||||
"docker:build:rootless": "docker build -t papra-rootless -f docker/Dockerfile.rootless .",
|
||||
"version": "changeset version && pnpm install --no-frozen-lockfile",
|
||||
"changeset": "changeset",
|
||||
|
||||
Reference in New Issue
Block a user