Initial commit with Email Import Wizard and Task Processor updates

This commit is contained in:
2026-05-04 08:02:11 +02:00
commit effdc5d59f
170 changed files with 67739 additions and 0 deletions
@@ -0,0 +1,70 @@
import * as fs from 'fs/promises';
import * as os from 'os';
import * as path from 'path';
import { PDFDocument, degrees } from 'pdf-lib';
import type { InboxDocument } from '../database/entities/inbox-document.entity';
/**
* Wendet die virtuellen Edits (DeletedPages, Rotations) auf das Original-PDF an
* und schreibt das Ergebnis in eine temporäre Datei. Gibt den Pfad zurück.
* Aufrufer ist verantwortlich für das Aufräumen.
*/
export async function applyEditsToTemp(
doc: InboxDocument,
pdfPath: string,
): Promise<string> {
const bytes = await fs.readFile(pdfPath);
const pdf = await PDFDocument.load(bytes, { ignoreEncryption: true });
const rotations = doc.Rotations ?? {};
for (const [pageStr, rot] of Object.entries(rotations)) {
const pageNum = Number(pageStr);
if (!Number.isInteger(pageNum)) continue;
const idx = pageNum - 1;
if (idx < 0 || idx >= pdf.getPageCount()) continue;
const normalized = ((Math.round(rot / 90) * 90) % 360 + 360) % 360;
if (normalized === 0) continue;
pdf.getPage(idx).setRotation(degrees(normalized));
}
// Seiten in absteigender Reihenfolge entfernen, damit Indizes stabil bleiben
const deleted = [...(doc.DeletedPages ?? [])].sort((a, b) => b - a);
for (const pageNum of deleted) {
const idx = pageNum - 1;
if (idx < 0 || idx >= pdf.getPageCount()) continue;
pdf.removePage(idx);
}
const out = await pdf.save();
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'inbox-pp-'));
const tmpPath = path.join(tmpDir, 'document.pdf');
await fs.writeFile(tmpPath, out);
return tmpPath;
}
export async function cleanupTemp(filePath: string | null): Promise<void> {
if (!filePath) return;
try {
await fs.unlink(filePath);
await fs.rmdir(path.dirname(filePath)).catch(() => undefined);
} catch {
// ignore
}
}
export async function extractSectionToTemp(
pdfPath: string,
pageIndices: number[],
): Promise<string> {
const bytes = await fs.readFile(pdfPath);
const srcPdf = await PDFDocument.load(bytes, { ignoreEncryption: true });
const outPdf = await PDFDocument.create();
const copied = await outPdf.copyPages(srcPdf, pageIndices);
copied.forEach(p => outPdf.addPage(p));
const out = await outPdf.save();
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'inbox-section-'));
const tmpPath = path.join(tmpDir, 'section.pdf');
await fs.writeFile(tmpPath, out);
return tmpPath;
}