Add Revit CSV preview API

This commit is contained in:
Julian Appel 2026-08-02 16:49:42 +02:00
parent 219da5ec3b
commit caa6caf99f
14 changed files with 437 additions and 3 deletions

View file

@ -0,0 +1,117 @@
import crypto from "node:crypto";
import type { Request, Response } from "express";
import { assertExternalCsvConfiguration } from "../../external-model/csv/external-csv-configuration.js";
import { ExternalCsvParseError } from "../../external-model/csv/external-csv-transport.js";
import { createExternalCsvPreview } from "../../external-model/application/external-csv-preview.js";
import { createExternalCsvConfigurationUpdateProjectCommand } from "../../domain/models/external-csv-configuration-project-command.model.js";
import {
previewExternalCsvSchema,
updateExternalCsvConfigurationSchema,
} from "../../shared/validation/external-csv.schemas.js";
import { externalCsvConfigurationRepository } from "../composition/application-repositories.js";
import { projectCommandService } from "../composition/project-command-stores.js";
import { respondWithProjectCommandError } from "./project-command.controller.js";
export function getExternalCsvConfiguration(req: Request, res: Response) {
const projectId = getProjectId(req, res);
if (!projectId) return;
const result = externalCsvConfigurationRepository.getByProject(projectId);
if (!result.projectExists) {
return res.status(404).json({ error: "Project not found" });
}
return res.json({ configuration: result.configuration });
}
export function updateExternalCsvConfiguration(req: Request, res: Response) {
const projectId = getProjectId(req, res);
if (!projectId) return;
const parsed = updateExternalCsvConfigurationSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: parsed.error.flatten() });
}
try {
assertExternalCsvConfiguration(parsed.data.configuration);
const current = externalCsvConfigurationRepository.getByProject(projectId);
if (!current.projectExists) {
return res.status(404).json({ error: "Project not found" });
}
const target = {
id: current.configuration?.id ?? crypto.randomUUID(),
projectId,
configurationVersion:
(current.configuration?.configurationVersion ?? 0) + 1,
configuration: parsed.data.configuration,
};
const result = projectCommandService.executeUser({
projectId,
expectedRevision: parsed.data.expectedRevision,
description: "Revit-CSV-Konfiguration bearbeiten",
command: createExternalCsvConfigurationUpdateProjectCommand(
current.configuration,
target
),
});
return res.json({ ...result, configuration: target });
} catch (error) {
return respondWithProjectCommandError(error, res);
}
}
export function previewExternalCsv(req: Request, res: Response) {
const projectId = getProjectId(req, res);
if (!projectId) return;
const parsed = previewExternalCsvSchema.safeParse(req.body);
if (!parsed.success) {
return res.status(400).json({ error: parsed.error.flatten() });
}
const stored = externalCsvConfigurationRepository.getByProject(projectId);
if (!stored.projectExists) {
return res.status(404).json({ error: "Project not found" });
}
if (!stored.configuration) {
return res.status(409).json({
error: "Für das Projekt ist noch keine Revit-CSV-Konfiguration gespeichert.",
code: "EXTERNAL_CSV_CONFIGURATION_REQUIRED",
});
}
try {
const bytes = decodeBase64(parsed.data.contentBase64);
return res.json(
createExternalCsvPreview({
fileName: parsed.data.fileName,
bytes,
configuration: stored.configuration.configuration,
})
);
} catch (error) {
if (error instanceof ExternalCsvParseError) {
return res.status(400).json({ error: error.message, code: error.code });
}
return res.status(400).json({
error: error instanceof Error ? error.message : "CSV-Vorschau fehlgeschlagen.",
});
}
}
function decodeBase64(value: string) {
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(value) || value.length % 4 !== 0) {
throw new Error("CSV-Inhalt ist nicht gültig Base64-kodiert.");
}
const bytes = Buffer.from(value, "base64");
if (bytes.toString("base64") !== value) {
throw new Error("CSV-Inhalt ist nicht kanonisch Base64-kodiert.");
}
if (bytes.length > 18 * 1024 * 1024) {
throw new Error("CSV-Datei überschreitet die maximale Größe von 18 MB.");
}
return bytes;
}
function getProjectId(req: Request, res: Response) {
const { projectId } = req.params;
if (typeof projectId !== "string" || !projectId.trim()) {
res.status(400).json({ error: "Invalid projectId" });
return null;
}
return projectId;
}