feat: improve upload admin workflow

Add users.is_admin SQLite migration for promoted admins.

Support curl PUT request uploads, save uploads into admin file-manager paths, default 25 GiB uploads, tabbed UI, and local dev preview.
This commit is contained in:
Ludwig Lehnert
2026-06-18 17:09:07 +00:00
parent 61f10fd994
commit a2b6054440
19 changed files with 1148 additions and 396 deletions

View File

@@ -1,5 +1,6 @@
import fs from 'node:fs';
import { Readable } from 'node:stream';
import { Readable, Transform } from 'node:stream';
import { pipeline } from 'node:stream/promises';
import Busboy from 'busboy';
@@ -108,3 +109,43 @@ export async function streamMultipartToPath(request, options) {
Readable.fromWeb(request.body).pipe(parser);
});
}
export async function streamBodyToPath(request, options) {
const { targetPath, maxBytes = 0 } = options;
if (!request.body) {
throw new Error('missing-body');
}
let sizeBytes = 0;
const counter = new Transform({
transform(chunk, encoding, callback) {
sizeBytes += chunk.length;
if (maxBytes > 0 && sizeBytes > maxBytes) {
callback(new Error('file-too-large'));
return;
}
callback(null, chunk);
},
});
try {
await pipeline(
Readable.fromWeb(request.body),
counter,
fs.createWriteStream(targetPath, { flags: 'wx' })
);
} catch (error) {
await fs.promises.rm(targetPath, { force: true }).catch(() => undefined);
throw error;
}
if (sizeBytes <= 0) {
await fs.promises.rm(targetPath, { force: true }).catch(() => undefined);
throw new Error('missing-file');
}
return { sizeBytes };
}