versioning.go ergaenzt Restore (stellt eine fruehere Revision ueber denselben CheckOut/CheckIn-Mechanismus als NEUE Revision wieder her, kein separater Codepfad) und GetRevisionContent (beliebige, nicht nur die aktuelle Revision). Revision.CreatedBy ergaenzt fuer Autor-Anzeige. internal/versioningapi: Liste/Content/Restore als HTTP-Endpunkte. OwnerChecker ist eine minimale, echte PermissionChecker-Implementierung (Dokument- oder Revisions-Ersteller) - keine zentrale RBAC-Anbindung fuer dieses Modul vorhanden (VER-01/VER-05-Praezedenzfall), der Aufrufvertrag ist aber so geschnitten, dass eine spaetere echte Rollenpruefung diesen Handler nicht aendern muss. web/dms-browser: Versionsliste (Autor/Zeitpunkt/Kommentar, Download- und Wiederherstellen-Aktion je Zeile), nutzt dieselbe bei DOC-10 gegen 10.000 Zeilen bewiesene Virtualisierungs-Logik. Pruefungen: 1. Wiederherstellung veraendert Historie nicht - alle felder der alten revisionen unveraendert, wiederhergestellter inhalt real entschluesselt und verglichen 2. 100 revisionen bleiben uebersichtlich - dieselbe bei doc-10 bewiesene virtualisierung, weit unterhalb des bewiesenen 10.000er-bereichs 3. berechtigung wird JE revision geprueft - nicht-ersteller sieht accessible:false und bekommt 403, ersteller kann zugreifen (200) Regressionsfrei: go test ./... -p 1 alle pakete PASS, 22/22 vitest-tests. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
40 lines
1.8 KiB
TypeScript
40 lines
1.8 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { fetchRevisions, restoreRevision, revisionContentUrl } from "./versionsApi";
|
|
|
|
const ORIGINAL_ENV = process.env;
|
|
|
|
beforeEach(() => {
|
|
process.env = { ...ORIGINAL_ENV, NEXT_PUBLIC_VERSIONING_API_URL: "http://backend.test", NEXT_PUBLIC_USER_ID: "user-a" };
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env = ORIGINAL_ENV;
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
describe("versionsApi", () => {
|
|
it("fetchRevisions ruft den erwarteten Endpunkt mit caller-Parameter auf", async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue(new Response("[]", { status: 200 }));
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
await fetchRevisions("doc-1");
|
|
expect(fetchMock.mock.calls[0][0]).toBe("http://backend.test/documents/doc-1/revisions?caller=user-a");
|
|
});
|
|
|
|
it("revisionContentUrl baut die Download-URL fuer eine bestimmte Revision", () => {
|
|
expect(revisionContentUrl("doc-1", "rev-2")).toBe(
|
|
"http://backend.test/documents/doc-1/revisions/rev-2/content?caller=user-a"
|
|
);
|
|
});
|
|
|
|
it("restoreRevision wirft bei 403 eine verstaendliche Fehlermeldung", async () => {
|
|
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response(null, { status: 403 })));
|
|
await expect(restoreRevision("doc-1", "rev-1")).rejects.toThrow(/Berechtigung/);
|
|
});
|
|
|
|
it("restoreRevision liefert die neue Revision bei Erfolg", async () => {
|
|
const newRev = { id: "rev-2", revision_number: 2, size_bytes: 10, mime_type: "application/pdf", comment: "x", created_by: "user-a", created_at: "2026-09-17T00:00:00Z", accessible: true };
|
|
vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response(JSON.stringify(newRev), { status: 200, headers: { "Content-Type": "application/json" } })));
|
|
await expect(restoreRevision("doc-1", "rev-1")).resolves.toEqual(newRev);
|
|
});
|
|
});
|