Compare commits

..

1 Commits

Author SHA1 Message Date
Aiirondev_dev f0b5edff79 fix of the json upload format 2026-08-04 21:11:13 +02:00
+70 -56
View File
@@ -48,30 +48,64 @@
</div>
<script>
// Robuster CSV-Parser, der Kommas innerhalb von Anführungszeichen ignoriert
function parseCSVLine(text) {
const result = [];
let cur = '';
let inQuotes = false;
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (c === '"' || c === "'") {
inQuotes = !inQuotes;
} else if (c === ',' && !inQuotes) {
result.push(cur.trim());
cur = '';
// 1. Ein echter CSV-Parser, der Zeilenumbrüche und Kommas in Texten korrekt ignoriert
function parseCSV(csvString) {
const rows = [];
let currentRow = [];
let currentCell = '';
let insideQuotes = false;
for (let i = 0; i < csvString.length; i++) {
const char = csvString[i];
const nextChar = csvString[i + 1];
if (char === '"' && insideQuotes && nextChar === '"') {
currentCell += '"';
i++; // Escaped Quotes ("") überspringen
} else if (char === '"') {
insideQuotes = !insideQuotes;
} else if (char === ',' && !insideQuotes) {
currentRow.push(currentCell);
currentCell = '';
} else if ((char === '\n' || char === '\r') && !insideQuotes) {
if (char === '\r' && nextChar === '\n') i++; // Windows Umbrüche überspringen
currentRow.push(currentCell);
// Leere Zeilen ignorieren
if (currentRow.length > 1 || currentRow[0] !== '') {
rows.push(currentRow);
}
currentRow = [];
currentCell = '';
} else {
cur += c;
currentCell += char;
}
}
result.push(cur.trim());
return result;
if (currentCell !== '' || currentRow.length > 0) {
currentRow.push(currentCell);
if (currentRow.length > 1 || currentRow[0] !== '') {
rows.push(currentRow);
}
}
return rows;
}
// Extrahiert Bildnamen aus Einträgen wie "['bild1.jpg', 'bild2.jpg']" oder "bild1.jpg"
// 2. Baut das Array wieder sicher zu einer sauberen CSV-Zeile für das Backend zusammen
function rowToCSV(rowArray) {
return rowArray.map(cell => {
if (cell === null || cell === undefined) return '';
let cellStr = String(cell);
// Wenn kritische Zeichen drin sind, sauber in Anführungszeichen verpacken
if (cellStr.includes(',') || cellStr.includes('"') || cellStr.includes('\n') || cellStr.includes('\r')) {
return '"' + cellStr.replace(/"/g, '""') + '"';
}
return cellStr;
}).join(',');
}
// 3. Bildnamen extrahieren (bleibt wie es war)
function extractImageNames(cellValue) {
if (!cellValue) return [];
let raw = cellValue.replace(/^["']|["']$/g, '').trim();
let raw = String(cellValue).replace(/^["']|["']$/g, '').trim();
if (raw.startsWith('[') && raw.endsWith(']')) {
try {
const jsonValid = raw.replace(/'/g, '"');
@@ -116,7 +150,6 @@ document.getElementById('batchUploadForm').addEventListener('submit', async func
const csvFile = csvInput.files[0];
const allImages = Array.from(imageInput.files);
// Map für schnellen Dateinamen-Vergleich (ohne Pfadangabe)
const imageMap = new Map();
allImages.forEach(file => {
imageMap.set(file.name.toLowerCase(), file);
@@ -126,57 +159,40 @@ document.getElementById('batchUploadForm').addEventListener('submit', async func
try {
const csvText = await csvFile.text();
let rows = csvText.split(/\r?\n/).filter(r => r.trim().length > 0);
// Hier rufen wir jetzt unseren sicheren Parser auf!
const allRows = parseCSV(csvText);
if (rows.length <= 1) {
if (allRows.length <= 1) {
throw new Error("CSV-Datei ist leer oder enthält nur Kopfzeilen.");
}
const headerRow = rows[0];
const dataRows = rows.slice(1);
const headerRow = allRows[0];
const dataRows = allRows.slice(1);
// 1. Client-Deduplizierung
const uniqueRowsSet = new Set();
const uniqueDataRows = [];
let duplicateCount = 0;
log(`${dataRows.length} Einträge gefunden. Bereite Batches vor...`);
for (const row of dataRows) {
if (uniqueRowsSet.has(row)) {
duplicateCount++;
} else {
uniqueRowsSet.add(row);
uniqueDataRows.push(row);
}
}
// Spalten-Index von "Images" sicher ermitteln
const imagesColIndex = headerRow.findIndex(h => h.toLowerCase().trim() === 'images');
log(`${uniqueDataRows.length} eindeutige Einträge. ${duplicateCount} Duplikate entfernt.`);
// Spalten-Index von "Images" ermitteln
const headers = parseCSVLine(headerRow).map(h => h.replace(/['"]/g, '').trim());
const imagesColIndex = headers.findIndex(h => h.toLowerCase() === 'images');
// 2. In Batches aufteilen
// In Batches aufteilen
const batches = [];
for (let i = 0; i < uniqueDataRows.length; i += BATCH_SIZE) {
batches.push(uniqueDataRows.slice(i, i + BATCH_SIZE));
for (let i = 0; i < dataRows.length; i += BATCH_SIZE) {
batches.push(dataRows.slice(i, i + BATCH_SIZE));
}
progressBar.max = batches.length;
progressBar.value = 0;
// 3. Sequenzieller Upload
for (let b = 0; b < batches.length; b++) {
const batchRows = batches[b];
progressText.textContent = `Lade Batch ${b + 1} von ${batches.length} hoch...`;
// Zuordnung der benötigten Bilder für diesen Batch
const requiredImagesForBatch = new Set();
if (imagesColIndex !== -1) {
batchRows.forEach(rowStr => {
const cols = parseCSVLine(rowStr);
if (cols[imagesColIndex]) {
const imgNames = extractImageNames(cols[imagesColIndex]);
batchRows.forEach(rowCols => {
if (rowCols[imagesColIndex]) {
const imgNames = extractImageNames(rowCols[imagesColIndex]);
imgNames.forEach(name => {
const fileMatch = imageMap.get(name.toLowerCase());
if (fileMatch) {
@@ -187,26 +203,24 @@ document.getElementById('batchUploadForm').addEventListener('submit', async func
});
}
// CSV für diesen Batch erstellen
const batchCsvText = [headerRow, ...batchRows].join('\n');
// Sicherer Zusammenbau des CSV-Batches
const batchCsvArray = [headerRow, ...batchRows];
const batchCsvText = batchCsvArray.map(rowToCSV).join('\n');
const batchCsvBlob = new Blob([batchCsvText], { type: 'text/csv' });
const formData = new FormData();
formData.append('csv_file', batchCsvBlob, `batch_${b + 1}.csv`);
// CSRF-Token im Form-Field übergeben
if (csrfToken) {
formData.append('csrf_token', csrfToken);
}
// Zugehörige Bilder anfügen
requiredImagesForBatch.forEach(imgFile => {
formData.append('images', imgFile);
});
log(`Batch ${b + 1}: ${batchRows.length} Items & ${requiredImagesForBatch.size} zugehörige Bilder.`);
// Request mit CSRF-Header ausführen
const response = await fetch('/upload_csv_batch', {
method: 'POST',
body: formData,
@@ -221,11 +235,11 @@ document.getElementById('batchUploadForm').addEventListener('submit', async func
throw new Error(result.message || `Server-Fehler ${response.status}`);
}
log(`Batch ${b + 1} abgeschlossen: ${result.message}`);
log(`Batch ${b + 1} abgeschlossen.`);
progressBar.value = b + 1;
}
progressText.textContent = "Upload erfolgreich beendet!";
progressText.textContent = "Upload erfolgreich beendet! Keine verschobenen Spalten mehr.";
uploadBtn.disabled = false;
} catch (err) {