73 lines
2.3 KiB
JavaScript
73 lines
2.3 KiB
JavaScript
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,
|
|
};
|