fix(nextcloud-files): WR-08/IN-06 Auswahl-ZIP per POST, Downloads mit Vorabpruefung
- WR-08: POST download/zip mit den Namen im Koerper (JSON oder unsichtbares Formular mit names als JSON-Text) statt im Query-String; hoechstens 1000 Namen; die Weboberflaeche laedt per Formular in einen unsichtbaren Rahmen (Strom direkt auf die Platte, Cookie und Content-Disposition bleiben); alles ausgewaehlt -> ganzer Ordner als ZIP - Nextcloud nimmt die Auswahl nur in ihrer Adresse an (gemessen: Apache lehnt ueber 8190 Zeichen mit 414 ab); Tessera prueft die Laenge und antwortet vorher mit 413 selectionTooLarge, die Weboberflaeche meldet es schon vor dem Absenden - IN-06: Vorabpruefung (check=1 bzw. check: true, ein PROPFIND Depth 0) vor jedem Download; Fehler stehen in der Statuszeile, connectionExpired fuehrt zum Anmeldebildschirm; auch der Klick auf einen Dateinamen geht ueber die Pruefung - e2e-transfer auf POST umgestellt (JSON, Formular ueber /api-proxy, 300 Namen, Pruefung), Anwenderhandbuch Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -112,21 +112,51 @@ export class DownloadQueryDto {
|
||||
@IsOptional()
|
||||
@IsIn(['1'])
|
||||
zip?: string;
|
||||
|
||||
/**
|
||||
* `1`: nur pruefen (Verbindung, Eintrag vorhanden), keinen Datenstrom liefern (IN-06). Die
|
||||
* Weboberflaeche fragt so vor dem eigentlichen Herunterladen, weil sie Fehler eines
|
||||
* Downloads im Browser sonst nicht sieht.
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsIn(['1'])
|
||||
check?: string;
|
||||
}
|
||||
|
||||
export class ZipQueryDto {
|
||||
/** Hoechstzahl gewaehlter Eintraege fuer ein Auswahl-ZIP (WR-08). */
|
||||
export const ZIP_MAX_NAMES = 1000;
|
||||
|
||||
/**
|
||||
* Auswahl-ZIP (WR-08): die Namen kommen im KOERPER eines POST, nicht in der Adresse — mehrere
|
||||
* hundert Namen sprengten sonst die Kopfzeilen-Grenze von Node (431) oder den Proxy (414).
|
||||
* Als JSON (`names` ist eine Liste) oder aus einem unsichtbaren Formular der Weboberflaeche
|
||||
* (`names` ist dieselbe Liste als JSON-Text; so laedt der Browser das ZIP als Strom direkt
|
||||
* auf die Platte, statt es im Arbeitsspeicher zu sammeln).
|
||||
*/
|
||||
export class ZipBodyDto {
|
||||
/** Ordner, aus dem die gewaehlten Eintraege kommen (`/` = Wurzel). */
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@MaxLength(4096)
|
||||
dir?: string;
|
||||
|
||||
/** Namen der gewaehlten Eintraege; ein einzelnes `name=...` wird zur Liste. */
|
||||
@Transform(({ value }) => (Array.isArray(value) ? value : value === undefined ? [] : [value]))
|
||||
@Transform(({ value }) => {
|
||||
if (typeof value !== 'string') return value;
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
} catch {
|
||||
return value;
|
||||
}
|
||||
})
|
||||
@IsArray()
|
||||
@ArrayMinSize(1)
|
||||
@ArrayMaxSize(500)
|
||||
@ArrayMaxSize(ZIP_MAX_NAMES)
|
||||
@IsString({ each: true })
|
||||
@MaxLength(255, { each: true })
|
||||
name!: string[];
|
||||
names!: string[];
|
||||
|
||||
/** `true` (JSON) oder `1` (Formular): nur pruefen, kein ZIP (IN-06). */
|
||||
@IsOptional()
|
||||
@IsIn([true, '1'])
|
||||
check?: boolean | string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user