From 3126b520bc452e3642c240fe4b839ab256dc6cc9 Mon Sep 17 00:00:00 2001 From: alma Date: Fri, 23 May 2025 17:10:08 +0200 Subject: [PATCH] W n8n --- My_workflow_49.json | 12 +++++++----- app/api/missions/route.ts | 30 ++++++++++++++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/My_workflow_49.json b/My_workflow_49.json index 3e848aaf..dfb148f9 100644 --- a/My_workflow_49.json +++ b/My_workflow_49.json @@ -3,7 +3,7 @@ "nodes": [ { "parameters": { - "jsCode": "const missionData = $input.item.json;\nconst binaryData = $input.item.binary;\n\n// Add detailed logging\nconsole.log('Process Mission Data - Input:', {\n hasInput: !!missionData,\n hasBinary: !!binaryData,\n hasBody: !!missionData?.body,\n hasLogo: !!missionData?.logo,\n hasAttachments: Array.isArray(missionData?.attachments),\n attachmentsCount: missionData?.attachments?.length || 0,\n logoDataType: typeof missionData?.logo,\n logoData: missionData?.logo ? 'present' : 'missing',\n contentType: missionData?.missionOriginal?.headers?.['content-type'] || 'unknown',\n binaryKeys: binaryData ? Object.keys(binaryData) : [],\n binaryDataTypes: binaryData ? Object.keys(binaryData).map(key => typeof binaryData[key]?.data) : [],\n creatorId: missionData?.creatorId || 'missing'\n});\n\n// Handle raw file input\nif (missionData?.missionOriginal?.headers?.['content-type']?.startsWith('image/')) {\n console.log('Detected raw image file input');\n \n // Get binary data from the first available key\n const binaryKey = Object.keys(binaryData || {})[0];\n const rawData = binaryKey ? binaryData[binaryKey]?.data : null;\n \n if (!rawData) {\n console.error('No binary data found in raw file input');\n throw new Error('No binary data found in raw file input');\n }\n \n // Ensure rawData is a Buffer\n const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);\n \n // Convert raw data to base64\n const base64Data = buffer.toString('base64');\n const mimeType = missionData.missionOriginal.headers['content-type'];\n \n // Create mission data structure\n return {\n missionOriginal: missionData,\n missionProcessed: {\n name: \"Unnamed Mission\",\n sanitizedName: \"unnamed-mission\",\n intention: \"\",\n description: \"Mission documentation\",\n startDate: new Date().toISOString().split('T')[0],\n endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],\n missionType: \"default\",\n guardians: {},\n volunteers: [],\n profils: [],\n services: [],\n clientId: 2,\n rocketChatUsernames: [],\n logo: {\n data: `data:${mimeType};base64,${base64Data}`,\n name: \"logo.png\",\n type: mimeType\n },\n attachments: []\n },\n config: {\n GITEA_API_URL: \"https://gite.slm-lab.net/api/v1\",\n GITEA_API_TOKEN: \"310645d564cbf752be1fe3b42582a3d5f5d0bddd\",\n GITEA_OWNER: \"alma\",\n LEANTIME_API_URL: \"https://agilite.slm-lab.net\",\n LEANTIME_API_TOKEN: \"lt_lsdShQdoYHaPUWuL07XZR1Rf3GeySsIs_UDlll3VJPk5EwAuILpMC4BwzJ9MZFRrb\",\n ROCKETCHAT_API_URL: \"https://parole.slm-lab.net/\",\n ROCKETCHAT_AUTH_TOKEN: \"w91TYgkH-Z67Oz72usYdkW5TZLLRwnre7qyAhp7aHJB\",\n ROCKETCHAT_USER_ID: \"Tpuww59PJKsrGNQJB\",\n OUTLINE_API_URL: \"https://chapitre.slm-lab.net/api\",\n OUTLINE_API_TOKEN: \"ol_api_tlLlANBfcoJ4l7zA8GOcpduAeL6QyBTcYvEnlN\",\n MISSION_API_URL: \"https://hub.slm-lab.net\",\n N8N_API_KEY: \"LwgeE1ntADD20OuWC88S3pR0EaO7FtO4\",\n KEYCLOAK_BASE_URL: \"https://connect.slm-lab.net\",\n KEYCLOAK_REALM: \"cercle\",\n KEYCLOAK_CLIENT_ID: \"lab\",\n KEYCLOAK_CLIENT_SECRET: \"LwgeE1ntADD20OuWC88S3P0EaO7FtO4\",\n MINIO_API_URL: \"https://dome-api.slm-lab.net\",\n MINIO_ACCESS_KEY: \"4aBT4CMb7JIMMyUtp4Pl\",\n MINIO_SECRET_KEY: \"HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg\"\n },\n binary: {\n data: buffer\n },\n creatorId: missionData?.creatorId || missionData?.missionOriginal?.body?.creatorId || missionData?.body?.creatorId\n };\n}\n\n// Continue with existing JSON processing\nconst sanitizeName = (name) => {\n if (!name || typeof name !== \"string\") return \"unnamed-mission\";\n return name.toLowerCase()\n .split(\"\")\n .map(c => {\n if (c >= \"a\" && c <= \"z\") return c;\n if (c >= \"0\" && c <= \"9\") return c;\n if (c === \" \" || c === \"-\") return c;\n return \"\";\n })\n .join(\"\")\n .split(\" \")\n .filter(Boolean)\n .join(\"-\");\n};\nconst formatDate = (date) => {\n if (!date) return \"\";\n const d = new Date(date);\n return d.toISOString().split(\"T\")[0];\n};\nconst missionName = missionData?.missionOriginal?.body?.name || missionData?.body?.name || missionData?.name || \"Unnamed Mission\";\n\n// Prepare file data for MinIO\nconst prepareFileData = (file) => {\n if (!file) {\n // Return default logo if no file provided\n return {\n data: \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=\",\n name: \"default-logo.png\",\n type: \"image/png\"\n };\n }\n \n // Handle different file formats\n if (typeof file === \"string\") {\n return {\n data: file,\n name: \"logo.png\",\n type: \"image/png\"\n };\n }\n \n if (typeof file === \"object\") {\n // Handle binary data\n if (file.data && typeof file.data === \"object\" && file.data.data) {\n return {\n data: file.data.data,\n name: file.name || \"logo.png\",\n type: file.type || \"image/png\"\n };\n }\n \n // Handle base64 data\n if (file.data && typeof file.data === \"string\") {\n return {\n data: file.data,\n name: file.name || \"logo.png\",\n type: file.type || \"image/png\"\n };\n }\n \n // Handle direct object\n return {\n data: file,\n name: file.name || \"logo.png\",\n type: file.type || \"image/png\"\n };\n }\n \n return null;\n};\n\nconst output = {\n missionOriginal: missionData,\n missionProcessed: {\n name: missionName,\n sanitizedName: sanitizeName(missionName),\n intention: missionData?.missionOriginal?.body?.intention || missionData?.body?.intention || missionData?.intention || \"\",\n description: missionData?.missionOriginal?.body?.intention || missionData?.body?.intention || missionData?.intention || \"Mission documentation\",\n startDate: formatDate(new Date()),\n endDate: formatDate(new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)),\n missionType: missionData?.missionOriginal?.body?.missionType || missionData?.body?.missionType || missionData?.missionType || \"default\",\n guardians: missionData?.missionOriginal?.body?.guardians || missionData?.body?.guardians || missionData?.guardians || {},\n volunteers: missionData?.missionOriginal?.body?.volunteers || missionData?.body?.volunteers || missionData?.volunteers || [],\n profils: missionData?.missionOriginal?.body?.profils || missionData?.body?.profils || missionData?.profils || [],\n services: missionData?.missionOriginal?.body?.services || missionData?.body?.services || missionData?.services || [],\n clientId: (missionData?.missionOriginal?.body?.missionType === \"interne\" || missionData?.body?.missionType === \"interne\" || missionData?.missionType === \"interne\") ? 1 : 2,\n rocketChatUsernames: [],\n logo: prepareFileData(missionData?.logo),\n attachments: Array.isArray(missionData?.attachments) ? missionData.attachments.map(prepareFileData).filter(Boolean) : []\n },\n config: {\n GITEA_API_URL: \"https://gite.slm-lab.net/api/v1\",\n GITEA_API_TOKEN: \"310645d564cbf752be1fe3b42582a3d5f5d0bddd\",\n GITEA_OWNER: \"alma\",\n LEANTIME_API_URL: \"https://agilite.slm-lab.net\",\n LEANTIME_API_TOKEN: \"lt_lsdShQdoYHaPUWuL07XZR1Rf3GeySsIs_UDlll3VJPk5EwAuILpMC4BwzJ9MZFRrb\",\n ROCKETCHAT_API_URL: \"https://parole.slm-lab.net/\",\n ROCKETCHAT_AUTH_TOKEN: \"w91TYgkH-Z67Oz72usYdkW5TZLLRwnre7qyAhp7aHJB\",\n ROCKETCHAT_USER_ID: \"Tpuww59PJKsrGNQJB\",\n OUTLINE_API_URL: \"https://chapitre.slm-lab.net/api\",\n OUTLINE_API_TOKEN: \"ol_api_tlLlANBfcoJ4l7zA8GOcpduAeL6QyBTcYvEnlN\",\n MISSION_API_URL: \"https://hub.slm-lab.net\",\n N8N_API_KEY: \"LwgeE1ntADD20OuWC88S3pR0EaO7FtO4\",\n KEYCLOAK_BASE_URL: \"https://connect.slm-lab.net\",\n KEYCLOAK_REALM: \"cercle\",\n KEYCLOAK_CLIENT_ID: \"lab\",\n KEYCLOAK_CLIENT_SECRET: \"LwgeE1ntADD20OuWC88S3P0EaO7FtO4\",\n MINIO_API_URL: \"https://dome-api.slm-lab.net\",\n MINIO_ACCESS_KEY: \"4aBT4CMb7JIMMyUtp4Pl\",\n MINIO_SECRET_KEY: \"HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg\"\n },\n creatorId: missionData?.creatorId || missionData?.missionOriginal?.body?.creatorId || missionData?.body?.creatorId || missionData?.missionOriginal?.creatorId || missionData?.missionProcessed?.creatorId\n};\n\n// Add binary data to output if available\nif (binaryData) {\n const binaryKey = Object.keys(binaryData)[0];\n if (binaryKey && binaryData[binaryKey]?.data) {\n // Ensure the data is a Buffer\n const data = binaryData[binaryKey].data;\n output.binary = {\n data: Buffer.isBuffer(data) ? data : Buffer.from(data)\n };\n }\n}\n\nconst guardians = missionData?.missionOriginal?.body?.guardians || missionData?.body?.guardians || missionData?.guardians || {};\nif (guardians) {\n for (const role in guardians) {\n const user = guardians[role];\n if (user) output.missionProcessed.rocketChatUsernames.push(user);\n }\n}\nconst volunteers = missionData?.missionOriginal?.body?.volunteers || missionData?.body?.volunteers || missionData?.volunteers || [];\nif (Array.isArray(volunteers)) {\n output.missionProcessed.rocketChatUsernames.push(...volunteers);\n}\noutput.missionProcessed.rocketChatUsernames = [...new Set(output.missionProcessed.rocketChatUsernames)];\n\n// Ensure binary data is always available\nif (!output.binary || !output.binary.data) {\n console.log('No binary data found, using default PNG');\n output.binary = {\n data: Buffer.from(\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=\", 'base64')\n };\n}\n\nreturn output;" + "jsCode": "const missionData = $input.item.json;\nconst binaryData = $input.item.binary;\n\n// Add detailed logging\nconsole.log('Process Mission Data - Input:', {\n hasInput: !!missionData,\n hasBinary: !!binaryData,\n hasBody: !!missionData?.body,\n hasLogo: !!missionData?.logo,\n hasAttachments: Array.isArray(missionData?.attachments),\n attachmentsCount: missionData?.attachments?.length || 0,\n logoDataType: typeof missionData?.logo,\n logoData: missionData?.logo ? 'present' : 'missing',\n contentType: missionData?.missionOriginal?.headers?.['content-type'] || 'unknown',\n binaryKeys: binaryData ? Object.keys(binaryData) : [],\n binaryDataTypes: binaryData ? Object.keys(binaryData).map(key => typeof binaryData[key]?.data) : [],\n creatorId: missionData?.creatorId || 'missing'\n});\n\n// Add detailed logging for services\nconsole.log('Process Mission Data - Services:', {\n originalServices: missionData?.missionOriginal?.body?.services,\n bodyServices: missionData?.body?.services,\n directServices: missionData?.services,\n finalServices: missionData?.missionOriginal?.body?.services || missionData?.body?.services || missionData?.services || []\n});\n\n// Handle raw file input\nif (missionData?.missionOriginal?.headers?.['content-type']?.startsWith('image/')) {\n console.log('Detected raw image file input');\n \n // Get binary data from the first available key\n const binaryKey = Object.keys(binaryData || {})[0];\n const rawData = binaryKey ? binaryData[binaryKey]?.data : null;\n \n if (!rawData) {\n console.error('No binary data found in raw file input');\n throw new Error('No binary data found in raw file input');\n }\n \n // Ensure rawData is a Buffer\n const buffer = Buffer.isBuffer(rawData) ? rawData : Buffer.from(rawData);\n \n // Convert raw data to base64\n const base64Data = buffer.toString('base64');\n const mimeType = missionData.missionOriginal.headers['content-type'];\n \n // Create mission data structure\n return {\n missionOriginal: missionData,\n missionProcessed: {\n name: \"Unnamed Mission\",\n sanitizedName: \"unnamed-mission\",\n intention: \"\",\n description: \"Mission documentation\",\n startDate: new Date().toISOString().split('T')[0],\n endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],\n missionType: \"default\",\n guardians: {},\n volunteers: [],\n profils: [],\n services: [],\n clientId: 2,\n rocketChatUsernames: [],\n logo: {\n data: `data:${mimeType};base64,${base64Data}`,\n name: \"logo.png\",\n type: mimeType\n },\n attachments: []\n },\n config: {\n GITEA_API_URL: \"https://gite.slm-lab.net/api/v1\",\n GITEA_API_TOKEN: \"310645d564cbf752be1fe3b42582a3d5f5d0bddd\",\n GITEA_OWNER: \"alma\",\n LEANTIME_API_URL: \"https://agilite.slm-lab.net\",\n LEANTIME_API_TOKEN: \"lt_lsdShQdoYHaPUWuL07XZR1Rf3GeySsIs_UDlll3VJPk5EwAuILpMC4BwzJ9MZFRrb\",\n ROCKETCHAT_API_URL: \"https://parole.slm-lab.net/\",\n ROCKETCHAT_AUTH_TOKEN: \"w91TYgkH-Z67Oz72usYdkW5TZLLRwnre7qyAhp7aHJB\",\n ROCKETCHAT_USER_ID: \"Tpuww59PJKsrGNQJB\",\n OUTLINE_API_URL: \"https://chapitre.slm-lab.net/api\",\n OUTLINE_API_TOKEN: \"ol_api_tlLlANBfcoJ4l7zA8GOcpduAeL6QyBTcYvEnlN\",\n MISSION_API_URL: \"https://hub.slm-lab.net\",\n N8N_API_KEY: \"LwgeE1ntADD20OuWC88S3pR0EaO7FtO4\",\n KEYCLOAK_BASE_URL: \"https://connect.slm-lab.net\",\n KEYCLOAK_REALM: \"cercle\",\n KEYCLOAK_CLIENT_ID: \"lab\",\n KEYCLOAK_CLIENT_SECRET: \"LwgeE1ntADD20OuWC88S3P0EaO7FtO4\",\n MINIO_API_URL: \"https://dome-api.slm-lab.net\",\n MINIO_ACCESS_KEY: \"4aBT4CMb7JIMMyUtp4Pl\",\n MINIO_SECRET_KEY: \"HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg\"\n },\n binary: {\n data: buffer\n },\n creatorId: missionData?.creatorId || missionData?.missionOriginal?.body?.creatorId || missionData?.body?.creatorId\n };\n}\n\n// Continue with existing JSON processing\nconst sanitizeName = (name) => {\n if (!name || typeof name !== \"string\") return \"unnamed-mission\";\n return name.toLowerCase()\n .split(\"\")\n .map(c => {\n if (c >= \"a\" && c <= \"z\") return c;\n if (c >= \"0\" && c <= \"9\") return c;\n if (c === \" \" || c === \"-\") return c;\n return \"\";\n })\n .join(\"\")\n .split(\" \")\n .filter(Boolean)\n .join(\"-\");\n};\nconst formatDate = (date) => {\n if (!date) return \"\";\n const d = new Date(date);\n return d.toISOString().split(\"T\")[0];\n};\nconst missionName = missionData?.missionOriginal?.body?.name || missionData?.body?.name || missionData?.name || \"Unnamed Mission\";\n\n// Prepare file data for MinIO\nconst prepareFileData = (file) => {\n if (!file) {\n // Return default logo if no file provided\n return {\n data: \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=\",\n name: \"default-logo.png\",\n type: \"image/png\"\n };\n }\n \n // Handle different file formats\n if (typeof file === \"string\") {\n return {\n data: file,\n name: \"logo.png\",\n type: \"image/png\"\n };\n }\n \n if (typeof file === \"object\") {\n // Handle binary data\n if (file.data && typeof file.data === \"object\" && file.data.data) {\n return {\n data: file.data.data,\n name: file.name || \"logo.png\",\n type: file.type || \"image/png\"\n };\n }\n \n // Handle base64 data\n if (file.data && typeof file.data === \"string\") {\n return {\n data: file.data,\n name: file.name || \"logo.png\",\n type: file.type || \"image/png\"\n };\n }\n \n // Handle direct object\n return {\n data: file,\n name: file.name || \"logo.png\",\n type: file.type || \"image/png\"\n };\n }\n \n return null;\n};\n\nconst output = {\n missionOriginal: missionData,\n missionProcessed: {\n name: missionName,\n sanitizedName: sanitizeName(missionName),\n intention: missionData?.missionOriginal?.body?.intention || missionData?.body?.intention || missionData?.intention || \"\",\n description: missionData?.missionOriginal?.body?.intention || missionData?.body?.intention || missionData?.intention || \"Mission documentation\",\n startDate: formatDate(new Date()),\n endDate: formatDate(new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)),\n missionType: missionData?.missionOriginal?.body?.missionType || missionData?.body?.missionType || missionData?.missionType || \"default\",\n guardians: missionData?.missionOriginal?.body?.guardians || missionData?.body?.guardians || missionData?.guardians || {},\n volunteers: missionData?.missionOriginal?.body?.volunteers || missionData?.body?.volunteers || missionData?.volunteers || [],\n profils: missionData?.missionOriginal?.body?.profils || missionData?.body?.profils || missionData?.profils || [],\n services: missionData?.missionOriginal?.body?.services || missionData?.body?.services || missionData?.services || [],\n clientId: (missionData?.missionOriginal?.body?.missionType === \"interne\" || missionData?.body?.missionType === \"interne\" || missionData?.missionType === \"interne\") ? 1 : 2,\n rocketChatUsernames: [],\n logo: prepareFileData(missionData?.logo),\n attachments: Array.isArray(missionData?.attachments) ? missionData.attachments.map(prepareFileData).filter(Boolean) : []\n },\n config: {\n GITEA_API_URL: \"https://gite.slm-lab.net/api/v1\",\n GITEA_API_TOKEN: \"310645d564cbf752be1fe3b42582a3d5f5d0bddd\",\n GITEA_OWNER: \"alma\",\n LEANTIME_API_URL: \"https://agilite.slm-lab.net\",\n LEANTIME_API_TOKEN: \"lt_lsdShQdoYHaPUWuL07XZR1Rf3GeySsIs_UDlll3VJPk5EwAuILpMC4BwzJ9MZFRrb\",\n ROCKETCHAT_API_URL: \"https://parole.slm-lab.net/\",\n ROCKETCHAT_AUTH_TOKEN: \"w91TYgkH-Z67Oz72usYdkW5TZLLRwnre7qyAhp7aHJB\",\n ROCKETCHAT_USER_ID: \"Tpuww59PJKsrGNQJB\",\n OUTLINE_API_URL: \"https://chapitre.slm-lab.net/api\",\n OUTLINE_API_TOKEN: \"ol_api_tlLlANBfcoJ4l7zA8GOcpduAeL6QyBTcYvEnlN\",\n MISSION_API_URL: \"https://hub.slm-lab.net\",\n N8N_API_KEY: \"LwgeE1ntADD20OuWC88S3pR0EaO7FtO4\",\n KEYCLOAK_BASE_URL: \"https://connect.slm-lab.net\",\n KEYCLOAK_REALM: \"cercle\",\n KEYCLOAK_CLIENT_ID: \"lab\",\n KEYCLOAK_CLIENT_SECRET: \"LwgeE1ntADD20OuWC88S3P0EaO7FtO4\",\n MINIO_API_URL: \"https://dome-api.slm-lab.net\",\n MINIO_ACCESS_KEY: \"4aBT4CMb7JIMMyUtp4Pl\",\n MINIO_SECRET_KEY: \"HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg\"\n },\n creatorId: missionData?.creatorId || missionData?.missionOriginal?.body?.creatorId || missionData?.body?.creatorId || missionData?.missionOriginal?.creatorId || missionData?.missionProcessed?.creatorId\n};\n\n// Add binary data to output if available\nif (binaryData) {\n const binaryKey = Object.keys(binaryData)[0];\n if (binaryKey && binaryData[binaryKey]?.data) {\n // Ensure the data is a Buffer\n const data = binaryData[binaryKey].data;\n output.binary = {\n data: Buffer.isBuffer(data) ? data : Buffer.from(data)\n };\n }\n}\n\nconst guardians = missionData?.missionOriginal?.body?.guardians || missionData?.body?.guardians || missionData?.guardians || {};\nif (guardians) {\n for (const role in guardians) {\n const user = guardians[role];\n if (user) output.missionProcessed.rocketChatUsernames.push(user);\n }\n}\nconst volunteers = missionData?.missionOriginal?.body?.volunteers || missionData?.body?.volunteers || missionData?.volunteers || [];\nif (Array.isArray(volunteers)) {\n output.missionProcessed.rocketChatUsernames.push(...volunteers);\n}\noutput.missionProcessed.rocketChatUsernames = [...new Set(output.missionProcessed.rocketChatUsernames)];\n\n// Ensure binary data is always available\nif (!output.binary || !output.binary.data) {\n console.log('No binary data found, using default PNG');\n output.binary = {\n data: Buffer.from(\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=\", 'base64')\n };\n}\n\n// Log the final output\nconsole.log('Process Mission Data - Final Output:', {\n services: output.missionProcessed.services,\n isArray: Array.isArray(output.missionProcessed.services),\n containsGite: Array.isArray(output.missionProcessed.services) && output.missionProcessed.services.includes('Gite')\n});\n\nreturn output;" }, "name": "Process Mission Data", "type": "n8n-nodes-base.code", @@ -219,8 +219,9 @@ "conditions": { "string": [ { - "value1": "={{ Array.isArray($node['Process Mission Data'].json.missionProcessed.services) ? $node['Process Mission Data'].json.missionProcessed.services.includes('Gite') : false }}", - "value2": "true" + "value1": "={{ $json.missionProcessed.services }}", + "operation": "contains", + "value2": "Gite" } ] } @@ -278,7 +279,8 @@ "response": { "fullResponse": true } - } + }, + "timeout": 30000 } }, "name": "Create Git Repository", @@ -589,7 +591,7 @@ }, { "parameters": { - "jsCode": "// Defensive access to all nodes\nconst missionData = $node['Process Mission Data']?.json?.missionProcessed || {};\nconst integrationResults = $node['Combine Results']?.json || {};\nconst saveMissionResult = $node['Save Mission To API']?.json || {};\nconst errors = [];\nconst warnings = [];\n\n// Check for actual errors vs expected failures\nif (saveMissionResult.error) {\n errors.push(`Failed to save mission: ${saveMissionResult.error.message || 'Unknown error'}`);\n}\n\n// Track which resources were actually created vs already existed\nconst resourceStatus = {\n gitRepo: false,\n leantimeProject: false,\n docCollection: false,\n rocketChatChannel: false\n};\n\n// Check Git repository\nif (integrationResults.gitRepo?.html_url) {\n resourceStatus.gitRepo = true;\n console.log('Git repository created successfully');\n} else if (integrationResults.gitRepo?.error?.includes('already exists')) {\n console.log('Git repository already exists, this is expected');\n warnings.push('Git repository already exists');\n} else if (integrationResults.gitRepo?.error) {\n errors.push(`Git repository creation failed: ${integrationResults.gitRepo.error}`);\n} else {\n errors.push('Git repository creation failed: Unknown error');\n}\n\n// Check Leantime project\nif (integrationResults.leantimeProject?.result?.id) {\n resourceStatus.leantimeProject = true;\n console.log('Leantime project created successfully');\n} else if (integrationResults.leantimeProject?.error?.includes('already exists')) {\n console.log('Leantime project already exists, this is expected');\n warnings.push('Leantime project already exists');\n} else if (integrationResults.leantimeProject?.error) {\n errors.push(`Leantime project creation failed: ${integrationResults.leantimeProject.error}`);\n} else {\n errors.push('Leantime project creation failed: Unknown error');\n}\n\n// Check RocketChat channel\nif (integrationResults.rocketChatChannel?.channel?._id) {\n resourceStatus.rocketChatChannel = true;\n console.log('RocketChat channel created successfully');\n} else if (integrationResults.rocketChatChannel?.error?.includes('error-duplicate-channel-name')) {\n console.log('RocketChat channel already exists, this is expected');\n warnings.push('RocketChat channel already exists');\n} else if (integrationResults.rocketChatChannel?.error) {\n errors.push(`RocketChat channel creation failed: ${integrationResults.rocketChatChannel.error}`);\n} else {\n errors.push('RocketChat channel creation failed: Unknown error');\n}\n\n// Check Documentation collection\nif (integrationResults.docCollection?.id) {\n resourceStatus.docCollection = true;\n console.log('Documentation collection created successfully');\n} else if (integrationResults.docCollection?.error?.includes('already exists')) {\n console.log('Documentation collection already exists, this is expected');\n warnings.push('Documentation collection already exists');\n} else if (integrationResults.docCollection?.error) {\n errors.push(`Documentation collection creation failed: ${integrationResults.docCollection.error}`);\n} else {\n errors.push('Documentation collection creation failed: Unknown error');\n}\n\n// Check if any critical resources failed to create\nconst criticalFailures = errors.filter(error => \n !error.includes('already exists') && \n !error.includes('expected')\n);\n\n// If the mission was successfully saved, consider it a success even if some resources already exist\nconst success = saveMissionResult.body?.message === 'Mission updated successfully' || \n saveMissionResult.body?.message === 'Mission created successfully';\n\n// Determine the final status\nconst status = criticalFailures.length > 0 ? 'error' : \n warnings.length > 0 ? 'warning' : \n 'success';\n\nconst output = {\n success: success && criticalFailures.length === 0,\n status,\n error: errors.length > 0 ? errors.join('; ') : null,\n errors,\n warnings,\n missionData,\n integrationResults,\n saveMissionResult,\n resourceStatus,\n message: status === 'success' ? \n 'Mission integration complete: All systems updated successfully' : \n status === 'warning' ? \n `Mission integration complete with warnings: ${warnings.join('; ')}` : \n `Mission integration failed: ${errors.join('; ')}`\n};\n\n// Log the final status\nconsole.log('Process Results - Final Status:', {\n success: output.success,\n status: output.status,\n errors: output.errors.length,\n warnings: output.warnings.length,\n resourceStatus\n});\n\nreturn output;" + "jsCode": "// Defensive access to all nodes\nconst missionData = $node['Process Mission Data']?.json?.missionProcessed || {};\nconst integrationResults = $node['Combine Results']?.json || {};\nconst saveMissionResult = $node['Save Mission To API']?.json || {};\nconst errors = [];\nconst warnings = [];\n\n// Check for actual errors vs expected failures\nif (saveMissionResult.error) {\n errors.push(`Failed to save mission: ${saveMissionResult.error.message || 'Unknown error'}`);\n}\n\n// Track which resources were actually created vs already existed\nconst resourceStatus = {\n gitRepo: false,\n leantimeProject: false,\n docCollection: false,\n rocketChatChannel: false\n};\n\n// Check Git repository\nif (integrationResults.gitRepo?.html_url) {\n resourceStatus.gitRepo = true;\n console.log('Git repository created successfully');\n} else if (integrationResults.gitRepo?.error?.includes('already exists')) {\n console.log('Git repository already exists, this is expected');\n warnings.push('Git repository already exists');\n} else if (integrationResults.gitRepo?.error) {\n errors.push(`Git repository creation failed: ${integrationResults.gitRepo.error}`);\n} else {\n errors.push('Git repository creation failed: Unknown error');\n}\n\n// Check Leantime project\nif (integrationResults.leantimeProject?.result?.[0]) {\n resourceStatus.leantimeProject = true;\n console.log('Leantime project created successfully');\n} else if (integrationResults.leantimeProject?.error?.includes('already exists')) {\n console.log('Leantime project already exists, this is expected');\n warnings.push('Leantime project already exists');\n} else if (integrationResults.leantimeProject?.error) {\n errors.push(`Leantime project creation failed: ${integrationResults.leantimeProject.error}`);\n} else {\n errors.push('Leantime project creation failed: Unknown error');\n}\n\n// Check RocketChat channel\nif (integrationResults.rocketChatChannel?.channel?._id) {\n resourceStatus.rocketChatChannel = true;\n console.log('RocketChat channel created successfully');\n} else if (integrationResults.rocketChatChannel?.error?.includes('error-duplicate-channel-name')) {\n console.log('RocketChat channel already exists, this is expected');\n warnings.push('RocketChat channel already exists');\n} else if (integrationResults.rocketChatChannel?.error) {\n errors.push(`RocketChat channel creation failed: ${integrationResults.rocketChatChannel.error}`);\n} else {\n errors.push('RocketChat channel creation failed: Unknown error');\n}\n\n// Check Documentation collection\nif (integrationResults.docCollection?.data?.id) {\n resourceStatus.docCollection = true;\n console.log('Documentation collection created successfully');\n} else if (integrationResults.docCollection?.error?.includes('already exists')) {\n console.log('Documentation collection already exists, this is expected');\n warnings.push('Documentation collection already exists');\n} else if (integrationResults.docCollection?.error) {\n errors.push(`Documentation collection creation failed: ${integrationResults.docCollection.error}`);\n} else {\n errors.push('Documentation collection creation failed: Unknown error');\n}\n\n// Check if any critical resources failed to create\nconst criticalFailures = errors.filter(error => \n !error.includes('already exists') && \n !error.includes('expected')\n);\n\n// If the mission was successfully saved, consider it a success even if some resources already exist\nconst success = saveMissionResult.body?.message === 'Mission updated successfully' || \n saveMissionResult.body?.message === 'Mission created successfully';\n\n// Determine the final status\nconst status = criticalFailures.length > 0 ? 'error' : \n warnings.length > 0 ? 'warning' : \n 'success';\n\nconst output = {\n success: success && criticalFailures.length === 0,\n status,\n error: errors.length > 0 ? errors.join('; ') : null,\n errors,\n warnings,\n missionData,\n integrationResults,\n saveMissionResult,\n resourceStatus,\n message: status === 'success' ? \n 'Mission integration complete: All systems updated successfully' : \n status === 'warning' ? \n `Mission integration complete with warnings: ${warnings.join('; ')}` : \n `Mission integration failed: ${errors.join('; ')}`\n};\n\n// Log the final status\nconsole.log('Process Results - Final Status:', {\n success: output.success,\n status: output.status,\n errors: output.errors.length,\n warnings: output.warnings.length,\n resourceStatus\n});\n\nreturn output;" }, "name": "Process Results", "type": "n8n-nodes-base.code", diff --git a/app/api/missions/route.ts b/app/api/missions/route.ts index f3fe7ab3..9eccfed5 100644 --- a/app/api/missions/route.ts +++ b/app/api/missions/route.ts @@ -8,24 +8,29 @@ import { Prisma } from '@prisma/client'; // Types interface MissionCreateInput { name: string; - oddScope?: string[]; - niveau: string; - intention: string; - missionType: string; - donneurDOrdre: string; - projection: string; + oddScope: string[]; + niveau?: string; + intention?: string; + missionType?: string; + donneurDOrdre?: string; + projection?: string; services?: string[]; participation?: string; profils?: string[]; guardians?: Record; volunteers?: string[]; - logo?: string | null; + logo?: { + data: string; + name?: string; + type?: string; + } | null; leantimeProjectId?: string | null; outlineCollectionId?: string | null; rocketChatChannelId?: string | null; - giteaRepositoryUrl?: string | null; - penpotProjectId?: string | null; - creatorId?: string; + gitRepositoryId?: string | null; + status?: string; + createdAt?: Date; + updatedAt?: Date; } interface MissionUserInput { @@ -242,6 +247,11 @@ export async function POST(request: Request) { guardians: body.guardians || {}, volunteers: Array.isArray(body.volunteers) ? body.volunteers : [], creatorId: userId, + logo: body.logo ? { + data: body.logo.data, + name: body.logo.name || 'logo.png', + type: body.logo.type || 'image/png' + } : null, config: { N8N_API_KEY: process.env.N8N_API_KEY, MISSION_API_URL: process.env.NEXT_PUBLIC_API_URL || 'https://api.slm-lab.net/api'