diff --git a/src/api.js b/src/api.js index 8bdcd4c..b4e869e 100644 --- a/src/api.js +++ b/src/api.js @@ -6,7 +6,12 @@ import * as pdfFonts from './vfs_fonts.js'; export default { id: 'operation-pdf-builder', - handler: async ({filename, folder, storage, template, fonts}, {services, database, accountability, getSchema}) => { + handler: async ({filename, folder, storage, template, fonts, images}, { + services, + database, + accountability, + getSchema + }) => { const {FilesService, AssetsService} = services; const schema = await getSchema({database}); const filesService = new FilesService({ @@ -23,8 +28,7 @@ export default { pdfMake.vfs = await getBase64Fonts(fonts, assetsService); pdfMake.fonts = getPdfMakeFonts(fonts); - console.log('VFS:', pdfMake.vfs); - console.log('Fonts:', pdfMake.fonts); + template['images'] = await addImages(images, assetsService, filesService); const pdfDocGenerator = pdfMake.createPdf(template); @@ -92,12 +96,40 @@ async function streamToBuffer(stream) { } async function fetchExternalFont(url) { - return await fetch(url, {headers: {responseType: 'arraybuffer'}}).then((response) => { - return Buffer.from(response.data, 'binary').toString('base64'); - }).catch((error) => { + try { + const response = await fetch(url); + + if (!response.ok) { + console.error(`HTTP error! status: ${response.status}`); + return false; + } + + const arrayBuffer = await response.arrayBuffer(); + return Buffer.from(arrayBuffer).toString('base64'); + } catch (error) { console.error('Error fetching external font:', error); return false; - }); + } +} + +async function fetchExternalImage(url) { + try { + const response = await fetch(url); + + if (!response.ok) { + console.error(`HTTP error! status: ${response.status}`); + return false; + } + + const contentType = response.headers.get('content-type'); + const arrayBuffer = await response.arrayBuffer(); + const base64Image = Buffer.from(arrayBuffer).toString('base64'); + + return `data:${contentType};base64,${base64Image}`; + } catch (error) { + console.error('Error fetching external image:', error); + return false; + } } async function fetchInternalFont(uuid, assetsService) { @@ -113,6 +145,22 @@ async function fetchInternalFont(uuid, assetsService) { }); } +async function fetchInternalImage(uuid, assetsService, filesService) { + return assetsService.getAsset(uuid) + .then(async (fileStream) => { + const {stream} = fileStream; + const {type} = await filesService.readOne(uuid); + const buffer = await streamToBuffer(stream); + const base64Image = Buffer.from(buffer).toString('base64'); + + return `data:${type};base64,${base64Image}`; + }) + .catch((error) => { + console.error('Error fetching internal image:', error); + return false; + }); +} + async function getBase64Fonts(fonts, assetsService) { const base64Fonts = []; // Load the default pdfMake fonts @@ -163,8 +211,25 @@ function getPdfMakeFonts(fonts) { }; } return fontList; - }catch (e) { + } catch (e) { console.error(e); return false; } } + +async function addImages(images, assetsService, filesService) { + let imageList = {}; + + if (Array.isArray(images)) { + for (const image of images) { + const {image_name, url} = image; + if (uuidValidate(url)) { + imageList[image_name] = await fetchInternalImage(url, assetsService, filesService); + } else if (url) { + imageList[image_name] = await fetchExternalImage(url, assetsService); + } + } + } + + return imageList; +} diff --git a/src/app.js b/src/app.js index c897da6..2df07d7 100644 --- a/src/app.js +++ b/src/app.js @@ -3,10 +3,14 @@ export default { name: 'PDF Builder Operation', icon: 'picture_as_pdf', description: 'Generate a pdf with flow data and the template.', - overview: ({filename}) => [ + overview: ({filename, fonts}) => [ { label: 'Filename', text: filename, + }, + { + label: 'Fonts', + text: getFontList(fonts), } ], options: [ @@ -41,7 +45,7 @@ export default { }, { field: 'filename', - name: 'Filename', + name: '$t:fields.directus_files.filename_download', type: 'string', meta: { width: 'full', @@ -50,7 +54,7 @@ export default { }, { field: 'folder', - name: 'Folder', + name: '$t:folder', type: 'uuid', meta: { width: 'half', @@ -59,7 +63,7 @@ export default { }, { field: 'storage', - name: 'Storage', + name: '$t:fields.directus_files.storage', type: 'string', meta: { width: 'half', @@ -72,7 +76,7 @@ export default { }, { field: 'template', - name: 'Template', + name: '$t:template', type: 'json', meta: { width: 'full', @@ -145,6 +149,66 @@ export default { ] } } + }, + { + field: 'images', + name: 'Images', + type: 'json', + meta: { + width: 'full', + interface: 'list', + special: 'cast-json', + options: { + template: '{{ image_name }}', + fields: [ + { + field: 'image_name', + name: 'Name', + type: 'string', + meta: { + width: 'full', + interface: 'input', + required: true, + options: { + placeholder: 'image', + iconRight: 'image', + } + } + }, + { + field: 'url', + name: 'Url', + type: 'string', + meta: { + width: 'full', + interface: 'input', + required: true, + options: { + placeholder: 'https://example.com/image.jpg', + iconRight: 'link', + } + } + }, + ] + } + } } ], }; + +function getFontList(fonts) { + if (!Array.isArray(fonts)) { + return '$t:no_items'; + } else { + const uniqueFonts = fonts.reduce((acc, current) => { + const font = acc.find(item => item.font_family === current.font_family); + if (!font) { + return acc.concat([current]); + } else { + return acc; + } + }, []); + + return uniqueFonts.map(font => `${font.font_family} - ${font.font_type}`).join(uniqueFonts.length > 1 ? ', ' : ''); + } +}