From 6ac2261cf143f0cc76cd3edb77b3f9e83ac930ba Mon Sep 17 00:00:00 2001 From: Matthieu Morin Date: Fri, 5 Apr 2024 14:28:25 +0200 Subject: [PATCH] new Cloudinary image logic - schema, validation, --- package.json | 4 ++- src/content/images.json | 14 +++++++++ src/content/vakuslim/vakuslim.json | 49 ------------------------------ src/lib/utils/imageService.ts | 21 +++++++++++++ src/lib/utils/uploadImages.ts | 49 ++++++++++++++++++++++++++++++ tests/validateImages.js | 32 +++++++++++++++++++ 6 files changed, 119 insertions(+), 50 deletions(-) create mode 100644 src/content/images.json delete mode 100644 src/content/vakuslim/vakuslim.json create mode 100644 src/lib/utils/imageService.ts create mode 100644 src/lib/utils/uploadImages.ts create mode 100644 tests/validateImages.js diff --git a/package.json b/package.json index 3ebce00..0f674dd 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,9 @@ "private": true, "type": "module", "scripts": { - "validate": "node ./tests/ValidateServices.js", + "validate:images": "node ./tests/validateImages.js", + "validate:services": "node ./tests/ValidateServices.js", + "validate": "pnpm run validate:services && validate:images", "dev": "pnpm run validate && vite dev --mode development", "build": "pnpm run validate && vite build", "build-dev": "pnpm run validate && vite build --mode development", diff --git a/src/content/images.json b/src/content/images.json new file mode 100644 index 0000000..c519cf5 --- /dev/null +++ b/src/content/images.json @@ -0,0 +1,14 @@ +{ + "example_image": { + "publicId": "example_image", + "transformations": [ + { "width": 1200, "height": 627, "crop": "fill", "quality": "auto", "format": "auto" } + ] + }, + "another_image": { + "publicId": "another_image", + "transformations": [ + { "width": 800, "height": 600, "crop": "fill", "quality": "auto", "format": "auto" } + ] + } +} diff --git a/src/content/vakuslim/vakuslim.json b/src/content/vakuslim/vakuslim.json deleted file mode 100644 index 0c4d193..0000000 --- a/src/content/vakuslim/vakuslim.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "$schema": "../schema-categories.json", - "title": "Vakuslim 48 - zeštíhlující procedura", - "description": "A description of a description", - "id": "depilace", - "image": "", - "services": [ - { - "title": "Ošetření horních končetin", - "description": "Diagnostika pleti, odlíčení tonizace", - "id": "vakuslim-48-zestihlujici-procedura-horni-koncetiny", - "image": "", - "price": 600, - "duration": 120 - }, - { - "title": "1 ošetření spodní části těla (břicho, boky, dolní končetiny)", - "description": "Diagnostika pleti, odlíčení tonizace", - "id": "vakuslim-48-zestihlujici-procedura-spodni-cast-tela", - "image": "", - "price": 800, - "duration": 120 - }, - { - "title": "1 ošetření komplet horní-dolní části", - "description": "Diagnostika pleti, odlíčení tonizace", - "id": "vakuslim-48-zestihlujici-procedura-komplet-horni-dolni-cast", - "image": "", - "price": 1200, - "duration": 120 - }, - { - "title": "6 ošetření předplatné kompet", - "description": "Diagnostika pleti, odlíčení tonizace", - "id": "vakuslim-48-zestihlujici-procedura-6-o-setreni-predplatne-kompet", - "image": "", - "price": 6600, - "duration": 120 - }, - { - "title": "12 ošetření předplatné komplet", - "description": "Diagnostika pleti, odlíčení tonizace", - "id": "vakuslim-48-zestihlujici-procedura-12-o-setreni-predplatne-komplet", - "image": "", - "price": 11000, - "duration": 120 - } - ] -} diff --git a/src/lib/utils/imageService.ts b/src/lib/utils/imageService.ts new file mode 100644 index 0000000..64d8a39 --- /dev/null +++ b/src/lib/utils/imageService.ts @@ -0,0 +1,21 @@ +// imageService.ts +import cloudinary from 'cloudinary'; +import imagesData from '$content/images.json'; + +cloudinary.v2.config({ + cloud_name: import.meta.env.VITE_CLOUDINARY_CLOUD_NAME, +}); + +export const getCloudinaryImageUrl = (publicId: string, options: cloudinary.UploadApiOptions = {}) => { + const imageData = imagesData[publicId]; + if (!imageData) { + throw new Error(`Image with public ID ${publicId} not found in images.json`); + } + + const transformationOptions = { + ...options, + ...imageData.transformations, + }; + + return cloudinary.v2.url(publicId, transformationOptions); +}; diff --git a/src/lib/utils/uploadImages.ts b/src/lib/utils/uploadImages.ts new file mode 100644 index 0000000..53dd7fe --- /dev/null +++ b/src/lib/utils/uploadImages.ts @@ -0,0 +1,49 @@ +// uploadImages.ts +import fs from 'fs'; +import path from 'path'; +import cloudinary from 'cloudinary'; +import matter from 'gray-matter'; + +cloudinary.v2.config({ + cloud_name: import.meta.env.VITE_CLOUDINARY_CLOUD_NAME, + api_key: import.meta.env.VITE_CLOUDINARY_API_KEY, + api_secret: import.meta.env.VITE_CLOUDINARY_API_SECRET, +}); + +const contentDir = 'src/content'; +const imagesJsonPath = 'src/content/images.json'; + +async function uploadImages() { + const imagesData = {}; + + // Read all Markdown files in the content directory + const mdFiles = fs.readdirSync(contentDir).filter((file) => file.endsWith('.md')); + + for (const mdFile of mdFiles) { + const mdFilePath = path.join(contentDir, mdFile); + const mdContent = fs.readFileSync(mdFilePath, 'utf-8'); + const { data, content } = matter(mdContent); + + // Extract relative image paths from the Markdown content + const imagePaths = content.match(/\!\[.*?\]\((.*?)\)/g) || []; + + for (const imagePath of imagePaths) { + const relativeImagePath = imagePath.match(/\((.*?)\)/)[1]; + const imageFilePath = path.join(contentDir, relativeImagePath); + + // Upload the image to Cloudinary + const uploadResult = await cloudinary.v2.uploader.upload(imageFilePath); + + // Add the image metadata to the imagesData object + imagesData[uploadResult.public_id] = { + publicId: uploadResult.public_id, + // Add any desired transformation options here + }; + } + } + + // Write the imagesData to the images.json file + fs.writeFileSync(imagesJsonPath, JSON.stringify(imagesData, null, 2)); +} + +uploadImages(); diff --git a/tests/validateImages.js b/tests/validateImages.js new file mode 100644 index 0000000..43d699b --- /dev/null +++ b/tests/validateImages.js @@ -0,0 +1,32 @@ +import cloudinary from 'cloudinary'; +import imagesData from '$content/images.json'; +import { env } from '$env/dynamic/private'; + + +cloudinary.v2.config({ + cloud_name: env.CLOUDINARY_CLOUD_NAME, + api_key: env.CLOUDINARY_API_KEY, + api_secret: env.CLOUDINARY_API_SECRET, +}); + +async function validateImages() { + const invalidImages = []; + + for (const publicId in imagesData) { + try { + // Check if the image exists on Cloudinary + await cloudinary.v2.api.resource(publicId); + } catch (error) { + invalidImages.push(publicId); + } + } + + if (invalidImages.length > 0) { + console.error(`The following images are missing or invalid on Cloudinary: ${invalidImages.join(', ')}`); + process.exit(1); + } else { + console.log('All images are valid on Cloudinary.'); + } +} + +validateImages();