const Minio = require('minio'); const crypto = require('crypto'); const getTrimmedEnv = (name, fallback = '') => String(process.env[name] ?? fallback).trim(); const MINIO_ENDPOINT = getTrimmedEnv('MINIO_ENDPOINT'); const MINIO_PORT = Number(process.env.MINIO_PORT || 9000); const MINIO_USE_SSL = process.env.MINIO_USE_SSL === 'true'; const MINIO_ACCESS_KEY = getTrimmedEnv('MINIO_ACCESS_KEY'); const MINIO_SECRET_KEY = getTrimmedEnv('MINIO_SECRET_KEY'); const MINIO_BUCKET = getTrimmedEnv('MINIO_BUCKET', 'plant-images') || 'plant-images'; const isStorageConfigured = () => Boolean(MINIO_ENDPOINT && MINIO_ACCESS_KEY && MINIO_SECRET_KEY); const getMinioPublicUrl = () => getTrimmedEnv('MINIO_PUBLIC_URL', `http://${MINIO_ENDPOINT}:${MINIO_PORT}`).replace(/\/$/, ''); const getClient = () => { if (!isStorageConfigured()) { throw new Error('Image storage is not configured.'); } return new Minio.Client({ endPoint: MINIO_ENDPOINT, port: MINIO_PORT, useSSL: MINIO_USE_SSL, accessKey: MINIO_ACCESS_KEY, secretKey: MINIO_SECRET_KEY, }); }; const ensureStorageBucket = async () => { const client = getClient(); const exists = await client.bucketExists(MINIO_BUCKET); if (!exists) { await client.makeBucket(MINIO_BUCKET); const policy = JSON.stringify({ Version: '2012-10-17', Statement: [ { Effect: 'Allow', Principal: { AWS: ['*'] }, Action: ['s3:GetObject'], Resource: [`arn:aws:s3:::${MINIO_BUCKET}/*`], }, ], }); await client.setBucketPolicy(MINIO_BUCKET, policy); console.log(`MinIO bucket '${MINIO_BUCKET}' created with public read policy.`); } }; const uploadImage = async (base64Data, contentType = 'image/jpeg') => { const client = getClient(); const rawExtension = contentType.split('/')[1] || 'jpg'; const extension = rawExtension === 'jpeg' ? 'jpg' : rawExtension; const filename = `${Date.now()}-${crypto.randomBytes(8).toString('hex')}.${extension}`; const buffer = Buffer.from(base64Data, 'base64'); await client.putObject(MINIO_BUCKET, filename, buffer, buffer.length, { 'Content-Type': contentType, }); const url = `${getMinioPublicUrl()}/${MINIO_BUCKET}/${filename}`; return { url, filename }; }; module.exports = { ensureStorageBucket, uploadImage, isStorageConfigured, };