fix: raise Files group upload cap 20 MiB -> 2 GiB (api + web)

The Files tab dropzone still enforced the old 20 MiB cap client- and
server-side while every other path had moved to 2 GiB. Also corrects the
stale '100 MiB' message on the video upload rejection.
This commit is contained in:
glass beadian 2026-10-15 20:49:46 +00:00
parent ef8d28bc26
commit 613aba236b
4 changed files with 11 additions and 10 deletions

View file

@ -7,7 +7,7 @@ import { GroupFilesService, type FilePage } from "./group-files.service.js";
import type { GroupFile } from "@tactical-media-broadcast-hub/core";
import { verifyWhileStreaming } from "./ocis-webdav.js";
const MAX_FILE_UPLOAD_BYTES = 20 * 1024 * 1024;
const MAX_FILE_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
interface FileUpload {
buffer: Buffer;
@ -20,7 +20,7 @@ interface FileUpload {
*
* GET /files list/search, keyset (groupId, senderMxid,
* mimeClass, origin, name, from, to, cursor, limit)
* POST /files/groups/:groupId/upload direct web upload (≤20 MiB, multipart)
* POST /files/groups/:groupId/upload direct web upload (≤2 GiB, multipart)
* GET /files/:id one GroupFile
* GET /files/:id/download stream payload (sha256 re-verified)
* POST /files/:id/retention set retention (keep/until/legalHold)

View file

@ -184,7 +184,7 @@ export class OcisWebdavClient {
async upload(groupId: string, safeName: string, body: Readable, contentType: string): Promise<OcisUploadResult> {
await this.ensureGroupFolder(groupId);
// reva rejects chunked PUTs, so the source drains into a bounded buffer
// (the upload cap is 20 MiB) and goes out with an explicit content-length.
// (the upload cap is 2 GiB) and goes out with an explicit content-length.
const hash = createHash("sha256");
const chunks: Buffer[] = [];
let sizeBytes = 0;

View file

@ -453,7 +453,7 @@ function validateUpload(storageKey: string, mimeType: string, sizeBytes: number)
if (!Number.isSafeInteger(sizeBytes) || sizeBytes < 1) {
throw new BadRequestException("sizeBytes must be a positive safe integer");
}
if (sizeBytes > MAX_VIDEO_UPLOAD_BYTES) throw new BadRequestException("video exceeds the 100 MiB upload limit");
if (sizeBytes > MAX_VIDEO_UPLOAD_BYTES) throw new BadRequestException("video exceeds the 2 GiB upload limit");
}
function requiredRow(row: unknown, description: string): Record<string, unknown> {

View file

@ -10,11 +10,12 @@ import type { GroupFile } from "./types";
/**
* Drag-drop + picker for POST /files/groups/:groupId/upload. The API accepts a
* single `file` field capped at 20 MiB; the cap is enforced here too so an
* single `file` field capped at 2 GiB; the cap is enforced here too so an
* oversized pick fails fast with a friendly message instead of a 413.
*/
const MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
const MAX_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
const MAX_LABEL = "2 GiB";
export function UploadDropzone({ groupId, live, onUploaded }: {
groupId: string;
@ -41,8 +42,8 @@ export function UploadDropzone({ groupId, live, onUploaded }: {
if (file.size > MAX_UPLOAD_BYTES) {
setError(
t({
en: `${file.name} is ${formatBytes(file.size)} — the limit is 20 MiB.`,
es: `${file.name} pesa ${formatBytes(file.size)} — el límite es 20 MiB.`,
en: `${file.name} is ${formatBytes(file.size)} — the limit is ${MAX_LABEL}.`,
es: `${file.name} pesa ${formatBytes(file.size)} — el límite es ${MAX_LABEL}.`,
}),
);
return;
@ -73,8 +74,8 @@ export function UploadDropzone({ groupId, live, onUploaded }: {
: groupId === ""
? t({ en: "Choose a group first.", es: "Elige un grupo primero." })
: t({
en: "Drop a file, paste one, or browse. Up to 20 MiB; stored with re-verified bytes.",
es: "Arrastra un archivo, pega uno o búscalo. Hasta 20 MiB; guardado con bytes reverificados.",
en: `Drop a file, paste one, or browse. Up to ${MAX_LABEL}; stored with re-verified bytes.`,
es: `Arrastra un archivo, pega uno o búscalo. Hasta ${MAX_LABEL}; guardado con bytes reverificados.`,
});
return (