UNPKG

n8n-nodes-nextcloud-tables

Version:

Production-Ready n8n Node für Nextcloud Tables - Vollständige API-Abdeckung mit erweiterten Filtern, Multi-Column-Sorting, CSV-Import und professioneller Datenvalidierung

313 lines 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataFormatter = void 0; /** * Datenformatierer für Nextcloud Tables Row-Daten */ class DataFormatter { /** * Formatiert Row-Daten basierend auf Spaltentypen */ static formatRowData(data, columns, options = {}) { const formattedData = {}; for (const [columnKey, value] of Object.entries(data)) { // Leere Werte überspringen if (value === undefined || value === null || value === '') { continue; } const columnId = parseInt(columnKey, 10); const column = columns?.find(col => col.id === columnId); if (column) { // Spezifische Formatierung basierend auf Spaltentyp formattedData[columnKey] = this.formatColumnValue(value, column, options); } else { // Fallback: Basis-Formatierung ohne Spalten-Info formattedData[columnKey] = this.formatGenericValue(value); } } return formattedData; } /** * Formatiert einen Wert basierend auf dem Spaltentyp */ static formatColumnValue(value, column, options) { switch (column.type) { case 'text': return this.formatTextValue(value, column); case 'number': return this.formatNumberValue(value, column); case 'datetime': return this.formatDateTimeValue(value, column, options); case 'selection': return this.formatSelectionValue(value, column, options); case 'usergroup': return this.formatUserGroupValue(value, column, options); case 'file': return this.formatFileValue(value, column); default: return this.formatGenericValue(value); } } /** * Formatiert Text-Spalten */ static formatTextValue(value, column) { const stringValue = String(value); // Max-Länge prüfen if (column.textMaxLength && stringValue.length > column.textMaxLength) { throw new Error(`Text zu lang: ${stringValue.length} Zeichen, Maximum: ${column.textMaxLength}`); } // Pattern-Validierung if (column.textAllowedPattern) { const regex = new RegExp(column.textAllowedPattern); if (!regex.test(stringValue)) { throw new Error(`Text entspricht nicht dem erlaubten Muster: ${column.textAllowedPattern}`); } } return stringValue; } /** * Formatiert Zahlen-Spalten */ static formatNumberValue(value, column) { const numValue = parseFloat(value); if (isNaN(numValue)) { throw new Error(`Ungültiger Zahlenwert: ${value}`); } // Min/Max-Prüfung - nur wenn Werte gesetzt sind (nicht null oder undefined) if (column.numberMin !== undefined && column.numberMin !== null && numValue < column.numberMin) { throw new Error(`Zahl zu klein: ${numValue}, Minimum: ${column.numberMin}`); } if (column.numberMax !== undefined && column.numberMax !== null && numValue > column.numberMax) { throw new Error(`Zahl zu groß: ${numValue}, Maximum: ${column.numberMax}`); } // Dezimalstellen if (column.numberDecimals !== undefined) { return parseFloat(numValue.toFixed(column.numberDecimals)); } return numValue; } /** * Formatiert DateTime-Spalten */ static formatDateTimeValue(value, column, options) { let dateValue; // Verschiedene Eingabeformate verarbeiten if (value instanceof Date) { dateValue = value; } else if (typeof value === 'string') { // ISO-Format, Unix-Timestamp oder andere Formate if (/^\d+$/.test(value)) { // Unix-Timestamp dateValue = new Date(parseInt(value, 10) * 1000); } else { dateValue = new Date(value); } } else if (typeof value === 'number') { // Unix-Timestamp in Sekunden oder Millisekunden dateValue = new Date(value > 1e10 ? value : value * 1000); } else { throw new Error(`Ungültiger DateTime-Wert: ${value}`); } if (isNaN(dateValue.getTime())) { throw new Error(`Ungültiges Datum: ${value}`); } // Standard-Format für Nextcloud Tables: ISO 8601 const format = options.dateTimeFormat || 'iso'; switch (format) { case 'iso': return dateValue.toISOString(); case 'unix': return Math.floor(dateValue.getTime() / 1000).toString(); case 'date': return dateValue.toISOString().split('T')[0]; default: return dateValue.toISOString(); } } /** * Formatiert Selection-Spalten */ static formatSelectionValue(value, column, options) { if (!value) { return column.selectionDefault || ''; } // Optionen validieren falls verfügbar if (options.validateSelections && column.selectionOptions) { const availableOptions = this.parseSelectionOptions(column.selectionOptions); const valueArray = Array.isArray(value) ? value : [value]; for (const val of valueArray) { if (!availableOptions.includes(String(val))) { throw new Error(`Ungültige Auswahl: ${val}. Erlaubt: ${availableOptions.join(', ')}`); } } } // Mehrfachauswahl oder Einfachauswahl if (Array.isArray(value)) { return value.map(v => String(v)); } return String(value); } /** * Formatiert UserGroup-Spalten */ static formatUserGroupValue(value, column, options) { if (!value) { return column.usergroupDefault || ''; } // TODO: User/Group-ID-Auflösung implementieren wenn resolveUserGroups aktiviert if (options.resolveUserGroups) { // Hier würde die Auflösung von User-IDs zu Benutzernamen stattfinden // Das erfordert zusätzliche API-Calls } // Mehrfachauswahl unterstützen if (column.usergroupMultipleItems) { if (Array.isArray(value)) { return value.map(v => String(v)); } return [String(value)]; } return String(value); } /** * Formatiert File-Spalten (für zukünftige Implementierung) */ static formatFileValue(value, column) { // TODO: File-Attachment-Formatierung implementieren // Dies erfordert spezielle Behandlung von File-Uploads if (typeof value === 'string' && value.length > 0) { // Annahme: File-ID oder File-Path return value; } if (typeof value === 'object' && value.fileId) { // File-Objekt mit ID return value.fileId; } return value; } /** * Generische Wert-Formatierung ohne Spalten-Info */ static formatGenericValue(value) { // Basis-Sanitization if (typeof value === 'string') { return value.trim(); } if (typeof value === 'number') { return value; } if (typeof value === 'boolean') { return value; } if (Array.isArray(value)) { return value.map(v => this.formatGenericValue(v)); } if (value instanceof Date) { return value.toISOString(); } return value; } /** * Parst Selection-Optionen aus dem String-Format */ static parseSelectionOptions(optionsString) { try { // Nextcloud Tables speichert Optionen oft als JSON-Array-String if (optionsString.startsWith('[') && optionsString.endsWith(']')) { return JSON.parse(optionsString); } // Oder als komma-getrennte Liste return optionsString.split(',').map(opt => opt.trim()); } catch (error) { // Fallback: Als einzelne Option behandeln return [optionsString]; } } /** * Validiert Bulk-Row-Daten */ static validateBulkData(rows, columns) { const errors = []; rows.forEach((row, index) => { try { this.formatRowData(row, columns, { validateSelections: true }); } catch (error) { errors.push(`Zeile ${index + 1}: ${error.message}`); } }); return errors; } /** * Konvertiert Row-Daten für Export */ static convertForExport(rows, columns, format = 'json') { const convertedRows = rows.map(row => { const converted = {}; if (row.data && Array.isArray(row.data)) { for (const item of row.data) { const column = columns?.find(col => col.id === item.columnId); const columnName = column?.title || `column_${item.columnId}`; converted[columnName] = this.convertValueForExport(item.value, column); } } return converted; }); if (format === 'csv') { return this.convertToCsv(convertedRows); } return convertedRows; } /** * Konvertiert einen Wert für Export */ static convertValueForExport(value, column) { if (!column) { return value; } switch (column.type) { case 'datetime': if (value && !isNaN(new Date(value).getTime())) { return new Date(value).toLocaleString(); } return value; case 'selection': case 'usergroup': if (Array.isArray(value)) { return value.join(', '); } return value; default: return value; } } /** * Konvertiert Daten zu CSV-Format */ static convertToCsv(data) { if (data.length === 0) { return ''; } const headers = Object.keys(data[0]); const csvRows = [headers.join(',')]; for (const row of data) { const values = headers.map(header => { const value = row[header]; if (typeof value === 'string' && (value.includes(',') || value.includes('"'))) { return `"${value.replace(/"/g, '""')}"`; } return value || ''; }); csvRows.push(values.join(',')); } return csvRows.join('\n'); } } exports.DataFormatter = DataFormatter; //# sourceMappingURL=data.formatter.js.map